1
0
Fork 0
forked from lthn/blockchain

Merge branch 'develop' into release

This commit is contained in:
sowle 2024-07-04 20:14:27 +02:00
commit e726ae9da6
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
51 changed files with 1742 additions and 871 deletions

9
LICENSE Normal file
View file

@ -0,0 +1,9 @@
Copyright (C) 2024 Zano project
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Zano project shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Zano project.

View file

@ -6,15 +6,18 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
endif()
message("DB ENGINE: lmdb")
add_subdirectory(liblmdb)
if(MSVC)
target_compile_options(lmdb PRIVATE /wd4996 /wd4503 /wd4345 /wd4267 /wd4244 /wd4146 /wd4333 /wd4172)
else()
# Warnings as used by LMDB itself (LMDB_0.9.23)
target_compile_options(lmdb PRIVATE -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized)
endif()
if(NOT DISABLE_MDBX)
message("DB ENGINE: mdbx")
add_subdirectory(libmdbx)
endif()
message("DB ENGINE: lmdb")
add_subdirectory(liblmdb)
if(MSVC)
target_compile_options(lmdb PRIVATE /wd4996 /wd4503 /wd4345 /wd4267 /wd4244 /wd4146 /wd4333 /wd4172)
else()
# Warnings as used by LMDB itself (LMDB_0.9.23)
target_compile_options(lmdb PRIVATE -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized)
endif()
if(NOT DISABLE_MDBX)
message("DB ENGINE: mdbx")
add_subdirectory(libmdbx)
# remove mdbx tools from the default MSVC build
set_target_properties(mdbx_chk mdbx_copy mdbx_dump mdbx_load mdbx_stat PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
endif()

View file

@ -244,11 +244,6 @@ DISABLE_VS_WARNINGS(4100)
#define CHECK_AND_ASSERT_MES_CUSTOM(expr, fail_ret_val, custom_code, message) do{if(!(expr)) {LOG_ERROR(message); custom_code; return fail_ret_val;};}while(0)
#endif
/*#ifndef CHECK_AND_ASSERT_MES_AND_THROW
#define CHECK_AND_ASSERT_MES_AND_THROW(expr, message) do{if(!(expr)) {LOG_ERROR(message); throw std::runtime_error(message);};}while(0)
#endif
*/
#ifndef CHECK_AND_NO_ASSERT_MES
#define CHECK_AND_NO_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_PRINT_MAGENTA(message, LOG_LEVEL_0); /*LOCAL_ASSERT(expr);*/ return fail_ret_val;};}while(0)
#endif
@ -265,6 +260,22 @@ DISABLE_VS_WARNINGS(4100)
#define CHECK_AND_ASSERT_MES2(expr, message) do{if(!(expr)) {LOG_ERROR(message); };}while(0)
#endif
#ifndef CHECK_AND_ASSERT_EQ
#define CHECK_AND_ASSERT_EQ(A, B) CHECK_AND_ASSERT_MES((A) == (B), false, STR(A) " != " STR(B) " because " << A << " != " << B)
#endif
#ifndef CHECK_AND_ASSERT_NEQ
#define CHECK_AND_ASSERT_NEQ(A, B) CHECK_AND_ASSERT_MES((A) != (B), false, STR(A) " == " STR(B) " because " << A << " == " << B)
#endif
#ifndef CHECK_AND_ASSERT_LESS
#define CHECK_AND_ASSERT_LESS(A, B) CHECK_AND_ASSERT_MES((A) < (B), false, STR(A) " >= " STR(B) " because " << A << " >= " << B)
#endif
#ifndef CHECK_AND_ASSERT_GREATER
#define CHECK_AND_ASSERT_GREATER(A, B) CHECK_AND_ASSERT_MES((A) > (B), false, STR(A) " <= " STR(B) " because " << A << " <= " << B)
#endif
namespace epee
{
namespace debug

View file

@ -1,3 +1,4 @@
// Copyright (c) 2024, Zano Project
// Copyright (c) 2006-2017, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
@ -39,7 +40,8 @@ namespace epee
{
s.insert(0, decimal_point + 1 - s.size(), '0');
}
s.insert(s.size() - decimal_point, ".");
if (decimal_point > 0)
s.insert(s.size() - decimal_point, ".");
return s;
}
}

View file

@ -121,8 +121,13 @@ namespace epee
boost::split(pod_items, a, boost::is_any_of(", ][\""));
t_pod_container_type res;
if (!a.size())
return res;
for (const auto& item : pod_items)
{
if(!item.size())
continue;
res.resize(res.size() + 1);
typename t_pod_container_type::value_type& pod_val = res.back();

View file

@ -107,6 +107,7 @@ public: \
//#define DOC_EXMP_AUTO_2(arg_1, arg_2) , KV_MAKE_ALIAS_NAME() (arg_1, arg_2)
#define DOC_END ); }
#define DOC_EXMP_AUTO(...) , epee::create_t_object<KV_MAKE_ALIAS_NAME() >(__VA_ARGS__)
#define DOC_EXMP_AGGR(...) , epee::create_t_object<KV_MAKE_ALIAS_NAME() >(KV_MAKE_ALIAS_NAME(){__VA_ARGS__})
// Function template to create an object with forwarded constructor arguments

View file

@ -116,7 +116,7 @@ namespace epee
template<class t_stream>
static void handle_obj_end(t_stream& strm, size_t indent)
{
strm << "}";
strm << make_indent(indent) << "}";
}
template<class t_stream>

View file

@ -9,7 +9,7 @@
#define VARIANT_CASE(v_type, typed_name) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { v_type& typed_name ATTRIBUTE_UNUSED = boost::get<v_type>(local_reference_eokcmeokmeokcm);
#define VARIANT_CASE_TV(v_type) VARIANT_CASE(v_type, tv)
#define VARIANT_CASE_OTHER() } else {
#define VARIANT_CASE_THROW_ON_OTHER() } else { ASSERT_MES_AND_THROW("Unknown type in switch statemet: " << local_reference_eokcmeokmeokcm.type().name());
#define VARIANT_CASE_THROW_ON_OTHER() } else { ASSERT_MES_AND_THROW("Unknown type in switch statement: " << local_reference_eokcmeokmeokcm.type().name());
#define VARIANT_CASE_THROW_ON_OTHER_MSG(err_msg) } else { ASSERT_MES_AND_THROW(err_msg << local_reference_eokcmeokmeokcm.type().name());
#define VARIANT_SWITCH_END() } }

View file

@ -50,8 +50,9 @@ namespace crypto
//
// Disclaimer: extensions to the CLSAG implemented below are non-standard and are in proof-of-concept state.
// They shouldn't be used in production code until formal security proofs are done and (ideally) the code is peer-reviewed.
// d/v-CLSAG implementation
// See the whitepaper: https://hyle-team.github.io/docs/zano/dv-CLSAG-extension/dv-CLSAG-extension.pdf
// Review by Cypher Stack: https://github.com/cypherstack/zano-clsag-review
// -- sowle
//

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Copyright (c) 2012-2013 The Boolberry developers
@ -1882,7 +1882,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
// miner tx prevalidation (light checks)
if (!prevalidate_miner_transaction(b, abei.height, pos_block))
{
LOG_PRINT_RED_L0("Alternative block " << id << " @ " << coinbase_height << "has invalid miner transaction.");
LOG_PRINT_RED_L0("Alternative block " << id << " @ " << coinbase_height << " has invalid miner transaction.");
bvc.m_verification_failed = true;
return false;
}
@ -1917,6 +1917,10 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
//
}
abei.difficulty = current_diff;
wide_difficulty_type cumulative_diff_delta = 0;
abei.cumulative_diff_adjusted = alt_chain.size() ? it_prev->second.cumulative_diff_adjusted : m_db_blocks[*ptr_main_prev]->cumulative_diff_adjusted;
std::unordered_set<crypto::key_image> alt_block_keyimages;
uint64_t ki_lookup_total = 0;
if (!validate_alt_block_txs(b, id, alt_block_keyimages, abei, alt_chain, connection_height, ki_lookup_total))
@ -1925,10 +1929,6 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
bvc.m_verification_failed = true;
return false;
}
abei.difficulty = current_diff;
wide_difficulty_type cumulative_diff_delta = 0;
abei.cumulative_diff_adjusted = alt_chain.size() ? it_prev->second.cumulative_diff_adjusted : m_db_blocks[*ptr_main_prev]->cumulative_diff_adjusted;
if (pos_block)
cumulative_diff_delta = get_adjusted_cumulative_difficulty_for_next_alt_pos(alt_chain, abei.height, current_diff, connection_height);
@ -3888,7 +3888,7 @@ uint64_t blockchain_storage::get_assets(uint64_t offset, uint64_t count, std::li
assets.push_back(asset_descriptor_with_id());
static_cast<asset_descriptor_base&>(assets.back()) = asset_descriptor_history.back().descriptor;
assets.back().asset_id = asset_id;
if (i + count > offset)
if (assets.size() >= count)
{
return false;
}
@ -4990,7 +4990,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
scan_for_keys_context scan_context = AUTO_VAL_INIT(scan_context);
if(!get_output_keys_for_input_with_checks(tx, txin, output_keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase))
{
LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << ")");
LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money_brief(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << "), tx: " << tx_prefix_hash);
return false;
}
//TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_ch_in_get_keys_loop);
@ -7379,9 +7379,11 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
const crypto::hash& bl_id,
const crypto::hash& input_tx_hash,
size_t input_index,
uint64_t split_height,
const alt_chain_type& alt_chain,
const std::unordered_set<crypto::hash>& alt_chain_block_ids,
uint64_t split_height,
const alt_chain_type& alt_chain,
const std::unordered_set<crypto::hash>& alt_chain_block_ids,
const uint64_t pos_block_timestamp,
const wide_difficulty_type& pos_difficulty,
uint64_t& ki_lookuptime,
uint64_t* p_max_related_block_height /* = nullptr */) const
{
@ -7458,41 +7460,55 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
std::vector<txout_ref_v> abs_key_offsets = relative_output_offsets_to_absolute(input_key_offsets);
CHECK_AND_ASSERT_MES(abs_key_offsets.size() > 0 && abs_key_offsets.size() == input_key_offsets.size(), false, "internal error: abs_key_offsets.size()==" << abs_key_offsets.size() << ", input_key_offsets.size()==" << input_key_offsets.size());
// eventually we should found all public keys for all outputs this input refers to, for checking ring signature
std::vector<crypto::public_key> pub_keys(abs_key_offsets.size(), null_pkey);
//
// let's try to resolve references and populate pub keys container for check_tokey_input()
// let's try to resolve references and populate the ring for ring signature check
//
uint64_t global_outs_for_amount = 0;
//figure out if this amount touched alt_chain amount's index and if it is, get
bool amount_touched_altchain = false;
//auto abg_it = abei.gindex_lookup_table.find(input_to_key.amount);
//if (abg_it == abei.gindex_lookup_table.end())
if (!alt_chain.empty())
{
auto abg_it = alt_chain.back()->second.gindex_lookup_table.find(input_amount);
if (input_amount != 0 /* <-- TODO @#@# remove this condition after ZC outs support is implemented*/ && abg_it != alt_chain.back()->second.gindex_lookup_table.end())
{
amount_touched_altchain = true;
// local gindex lookup table contains last used gindex, so we can't get total number of outs
// just skip setting global_outs_for_amount
}
else
{
//quite easy,
global_outs_for_amount = m_db_outputs.get_item_size(input_amount);
}
}
if (!alt_chain.empty() && alt_chain.back()->second.gindex_lookup_table.count(input_amount) != 0)
amount_touched_altchain = true; // local gindex lookup table contains last used gindex, so we can't get total number of outs, just skip setting global_outs_for_amount
else
{
//quite easy,
global_outs_for_amount = m_db_outputs.get_item_size(input_amount);
}
CHECK_AND_ASSERT_MES(pub_keys.size() == abs_key_offsets.size(), false, "pub_keys.size()==" << pub_keys.size() << " != abs_key_offsets.size()==" << abs_key_offsets.size()); // just a little bit of paranoia
std::vector<const crypto::public_key*> pub_key_pointers;
bool pos_miner_tx = is_pos_miner_tx(input_tx);
// eventually we should found all required public keys for all outputs this input refers to, because it's required for ring signature check
std::vector<crypto::public_key> pub_keys(abs_key_offsets.size(), null_pkey); // old bare outputs
std::vector<const crypto::public_key*> pub_key_pointers; // old bare outputs (pointers)
vector<crypto::CLSAG_GGX_input_ref_t> zc_input_ring; // ZC outputs
vector<crypto::CLSAG_GGXXG_input_ref_t> zarcanum_input_ring; // Zarcanum outputs
auto add_output_to_the_ring = [&](const tx_out_v& out_v, size_t index, uint64_t top_minus_source_height) -> bool {
VARIANT_SWITCH_BEGIN(out_v)
VARIANT_CASE_CONST(tx_out_bare, bo)
{
VARIANT_SWITCH_BEGIN(bo.target)
VARIANT_CASE_CONST(txout_to_key, ttk)
pub_keys[index] = ttk.key;
pub_key_pointers.push_back(&pub_keys[index]);
VARIANT_CASE_CONST(txout_htlc, out_htlc)
bool htlc_expired = out_htlc.expiration > top_minus_source_height ? false : true;
pub_keys[index] = htlc_expired ? out_htlc.pkey_refund : out_htlc.pkey_redeem;
pub_key_pointers.push_back(&pub_keys[index]);
VARIANT_CASE_OTHER()
return false;
VARIANT_SWITCH_END()
}
VARIANT_CASE_CONST(tx_out_zarcanum, zo)
{
if (pos_miner_tx)
zarcanum_input_ring.emplace_back(zo.stealth_address, zo.amount_commitment, zo.blinded_asset_id, zo.concealing_point);
else
zc_input_ring.emplace_back(zo.stealth_address, zo.amount_commitment, zo.blinded_asset_id);
}
VARIANT_CASE_OTHER()
return false;
VARIANT_SWITCH_END()
return true;
};
uint64_t height_of_current_alt_block = alt_chain.size() ? alt_chain.back()->second.height + 1 : split_height + 1;
@ -7506,13 +7522,13 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
{
uint64_t offset_gindex = boost::get<uint64_t>(off);
CHECK_AND_ASSERT_MES(amount_touched_altchain || (offset_gindex < global_outs_for_amount), false,
"invalid global output index " << offset_gindex << " for amount=" << input_amount <<
"invalid global output index " << offset_gindex << " for amount " << print_money_brief(input_amount) <<
", max is " << global_outs_for_amount <<
", referred to by offset #" << pk_n <<
", amount_touched_altchain = " << amount_touched_altchain);
if (amount_touched_altchain)
{
bool found_the_key = false;
bool found = false;
for (auto alt_it = alt_chain.rbegin(); alt_it != alt_chain.rend(); alt_it++)
{
auto it_aag = (*alt_it)->second.gindex_lookup_table.find(input_amount);
@ -7528,42 +7544,25 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
//GOT IT!!
//TODO: At the moment we ignore check of mix_attr against mixing to simplify alt chain check, but in future consider it for stronger validation
uint64_t local_offset = offset_gindex - it_aag->second;
auto& alt_keys = (*alt_it)->second.outputs_pub_keys;
CHECK_AND_ASSERT_MES(local_offset < alt_keys[input_amount].size(), false, "Internal error: local_offset=" << local_offset << " while alt_keys[" << input_amount << " ].size()=" << alt_keys.size());
const output_key_or_htlc_v& out_in_alt = alt_keys[input_amount][local_offset];
auto& alt_outputs = (*alt_it)->second.outputs;
CHECK_AND_ASSERT_MES(local_offset < alt_outputs[input_amount].size(), false, "Internal error: local_offset=" << local_offset << " while alt_outputs[" << input_amount << " ].size()=" << alt_outputs.size());
const tx_out_v& out_in_alt = alt_outputs[input_amount][local_offset];
/*
here we do validation against compatibility of input and output type
TxOutput | TxInput | Allowed
----------------------------
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
TO_KEY | HTLC | NOT
TO_KEY | TO_KEY | YES
*/
uint64_t height_of_source_block = (*alt_it)->second.height;
CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed");
bool r = is_output_allowed_for_input(out_in_alt, input_v, height_of_current_alt_block - height_of_source_block);
uint64_t top_minus_source_height = height_of_current_alt_block - height_of_source_block;
bool r = is_output_allowed_for_input(out_in_alt, input_v, top_minus_source_height);
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
r = add_output_to_the_ring(out_in_alt, pk_n, top_minus_source_height);
CHECK_AND_ASSERT_MES(r, false, "offset #" << pk_n << ": add_output_to_the_ring failed");
if (out_in_alt.type() == typeid(crypto::public_key))
{
pk = boost::get<crypto::public_key>(out_in_alt);
}
else
{
const txout_htlc& out_htlc = boost::get<txout_htlc>(out_in_alt);
bool htlc_expired = out_htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false:true;
pk = htlc_expired ? out_htlc.pkey_refund : out_htlc.pkey_redeem;
//input_v
}
pub_key_pointers.push_back(&pk);
found_the_key = true;
found = true;
break;
}
}
if (found_the_key)
if (found)
continue;
//otherwise lookup in main chain index
}
@ -7583,114 +7582,62 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
{
uint64_t height_of_source_block = it->second.second;
CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed");
uint64_t top_minus_source_height = height_of_current_alt_block - height_of_source_block;
//source tx found in altchain
CHECK_AND_ASSERT_MES(it->second.first.vout.size() > out_n, false, "Internal error: out_n(" << out_n << ") >= it->second.vout.size()(" << it->second.first.vout.size() << ")");
const tx_out_v& out_in_alt = it->second.first.vout[out_n];
VARIANT_SWITCH_BEGIN(it->second.first.vout[out_n]);
VARIANT_CASE_CONST(tx_out_bare, o)
{
/*
here we do validation against compatibility of input and output type
r = is_output_allowed_for_input(out_in_alt, input_v, top_minus_source_height);
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
TxOutput | TxInput | Allowed
----------------------------
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
TO_KEY | HTLC | NOT
TO_KEY | TO_KEY | YES
*/
txout_target_v out_target_v = o.target;
bool r = is_output_allowed_for_input(out_target_v, input_v, height_of_current_alt_block - height_of_source_block);
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
if (out_target_v.type() == typeid(txout_htlc))
{
//source is hltc out
const txout_htlc& htlc = boost::get<txout_htlc>(out_target_v);
bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true;
pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem;
pub_key_pointers.push_back(&pk);
continue;
}
else if (out_target_v.type() == typeid(txout_to_key))
{
//source is to_key out
pk = boost::get<txout_to_key>(out_target_v).key;
pub_key_pointers.push_back(&pk);
continue;
}
else
{
ASSERT_MES_AND_THROW("Unexpected out type for tx_in in altblock: " << out_target_v.type().name());
}
}
VARIANT_CASE_CONST(tx_out_zarcanum, toz)
//@#@
VARIANT_SWITCH_END();
r = add_output_to_the_ring(out_in_alt, pk_n, top_minus_source_height);
CHECK_AND_ASSERT_MES(r, false, "offset #" << pk_n << ": add_output_to_the_ring failed");
continue; // found in altchain, continue with the new output
}
}
// lookup the output in the main chain
auto p = m_db_transactions.get(tx_id);
CHECK_AND_ASSERT_MES(p != nullptr && out_n < p->tx.vout.size(), false, "can't find output #" << out_n << " for tx " << tx_id << " referred by offset #" << pk_n);
const tx_out_v& out_in_main = p->tx.vout[out_n];
VARIANT_SWITCH_BEGIN(p->tx.vout[out_n]);
VARIANT_CASE_CONST(tx_out_bare, o)
uint64_t height_of_source_block = p->m_keeper_block_height;
CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed");
uint64_t top_minus_source_height = height_of_current_alt_block - height_of_source_block;
uint8_t mix_attr = 0;
if (get_mix_attr_from_tx_out_v(out_in_main, mix_attr))
{
auto &t = o.target;
/*
here we do validation against compatibility of input and output type
TxOutput | TxInput | Allowed
----------------------------
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
TO_KEY | HTLC | NOT
TO_KEY | TO_KEY | YES
*/
uint64_t height_of_source_block = p->m_keeper_block_height;
CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed");
bool r = is_output_allowed_for_input(t, input_v, height_of_current_alt_block - height_of_source_block);
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
if (t.type() == typeid(txout_to_key))
{
const txout_to_key& out_tk = boost::get<txout_to_key>(t);
pk = out_tk.key;
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(p->tx.version, out_tk.mix_attr, abs_key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(mixattr_ok, false, "input offset #" << pk_n << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(out_tk.mix_attr) << ", input's key_offsets.size = " << abs_key_offsets.size());
}
else if (t.type() == typeid(txout_htlc))
{
const txout_htlc& htlc = boost::get<txout_htlc>(t);
bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true;
pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem;
}
// case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid)
CHECK_AND_ASSERT_MES(p->m_keeper_block_height < split_height, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height);
if (max_related_block_height < p->m_keeper_block_height)
max_related_block_height = p->m_keeper_block_height;
// TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks()
// make sure it was actually found
// let's disable this check due to missing equal check in main chain validation code
//TODO: implement more strict validation with next hard fork
//CHECK_AND_ASSERT_MES(pk != null_pkey, false, "Can't determine output public key for offset " << pk_n << " in related tx: " << tx_id << ", out_n = " << out_n);
pub_key_pointers.push_back(&pk);
// having either txout_to_key or txout_zarcanum, for htlc or multisig outputs this check is not applicable
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(p->tx.version, mix_attr, abs_key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(mixattr_ok, false, "input offset #" << pk_n << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(mix_attr) << ", input's key_offsets.size = " << abs_key_offsets.size());
}
VARIANT_CASE_CONST(tx_out_zarcanum, toz)
//@#@
VARIANT_SWITCH_END();
// case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid)
r = p->m_keeper_block_height < split_height;
CHECK_AND_ASSERT_MES(r, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height);
r = is_output_allowed_for_input(out_in_main, input_v, top_minus_source_height);
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
r = add_output_to_the_ring(out_in_main, pk_n, top_minus_source_height);
CHECK_AND_ASSERT_MES(r, false, "offset #" << pk_n << ": add_output_to_the_ring failed");
if (max_related_block_height < p->m_keeper_block_height)
max_related_block_height = p->m_keeper_block_height;
// TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks()
// make sure it was actually found
// let's disable this check due to missing equal check in main chain validation code
//TODO: implement more strict validation with next hard fork
//CHECK_AND_ASSERT_MES(pk != null_pkey, false, "Can't determine output public key for offset " << pk_n << " in related tx: " << tx_id << ", out_n = " << out_n);
}
// @#@# TODO review the following checks!
// do input checks (attachment_info, ring signature and extra signature, etc.)
VARIANT_SWITCH_BEGIN(input_v);
@ -7703,17 +7650,33 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
VARIANT_CASE_CONST(txin_zc_input, input_zc);
if (is_pos_miner_tx(input_tx))
{
// TODO @#@# Special case: handling Zarcanum PoS block input
// Zarcanum signature (PoS block miner tx)
stake_kernel sk{};
stake_modifier_type sm{};
uint64_t last_pow_block_height = 0;
r = build_stake_modifier(sm, alt_chain, split_height, nullptr, &last_pow_block_height);
CHECK_AND_ASSERT_MES(r, false, "failed to build_stake_modifier");
r = build_kernel(input_key_image, sk, sm, pos_block_timestamp);
CHECK_AND_ASSERT_MES(r, false, "failed to build kernel_stake");
crypto::hash kernel_hash = crypto::cn_fast_hash(&sk, sizeof(sk));
crypto::scalar_t last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, sm.last_pow_id);
CHECK_AND_ASSERT_MES(input_tx.signatures.size() != 2, false, "input_tx.signatures has wrong size: " << input_tx.signatures.size());
CHECK_AND_ASSERT_MES(input_tx.signatures[0].type() == typeid(zarcanum_sig), false, "input_tx.signatures[" << input_index << "] has wrong type: " << input_tx.signatures[input_index].type().name());
const zarcanum_sig& sig = boost::get<zarcanum_sig>(input_tx.signatures[0]);
uint8_t err = 0;
r = crypto::zarcanum_verify_proof(bl_id, kernel_hash, zarcanum_input_ring, last_pow_block_id_hashed, input_key_image, pos_difficulty, sig, &err);
CHECK_AND_ASSERT_MES(r, false, "zarcanum_verify_proof failed: err=" << (int)err);
}
else
{
// TODO @#@# properly handle ZC inputs! check_tx_input below isn't working because of incorrectly assembled ring
/*
uint64_t max_related_block_height = 0;
bool all_tx_ins_have_explicit_asset_ids = true; // stub for now, TODO @#@#
r = check_tx_input(input_tx, input_index, input_zc, input_tx_hash, max_related_block_height, all_tx_ins_have_explicit_asset_ids);
CHECK_AND_ASSERT_MES(r, false, "check_tx_input failed");
*/
// ZC signature (3/2-CLSAG GGX)
crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(input_tx, input_index, input_tx_hash);
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed");
CHECK_AND_ASSERT_MES(input_index < input_tx.signatures.size(), false, "input_tx.signatures has wrong size: " << input_tx.signatures.size());
CHECK_AND_ASSERT_MES(input_tx.signatures[input_index].type() == typeid(ZC_sig), false, "input_tx.signatures[" << input_index << "] has wrong type: " << input_tx.signatures[input_index].type().name());
const ZC_sig& sig = boost::get<ZC_sig>(input_tx.signatures[input_index]);
bool r = crypto::verify_CLSAG_GGX(tx_hash_for_signature, zc_input_ring, sig.pseudo_out_amount_commitment, sig.pseudo_out_blinded_asset_id, input_key_image, sig.clsags_ggx);
CHECK_AND_ASSERT_MES(r, false, "verify_CLSAG_GGX failed");
}
VARIANT_CASE_OTHER()
LOG_ERROR("unexpected input type: " << input_v.type().name());
@ -7739,19 +7702,26 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::is_output_allowed_for_input(const tx_out_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height) const
{
if (out_v.type() == typeid(tx_out_bare))
{
return is_output_allowed_for_input(boost::get<tx_out_bare>(out_v).target, in_v, top_minus_source_height);
}
else if (out_v.type() == typeid(tx_out_zarcanum))
{
return is_output_allowed_for_input(boost::get<tx_out_zarcanum>(out_v), in_v);
}
else
{
LOG_ERROR("[is_output_allowed_for_input]: Wrong output type in : " << out_v.type().name());
return false;
}
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::is_output_allowed_for_input(const txout_target_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const
{
/*
TxOutput | TxInput | Allowed
----------------------------
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
TO_KEY | HTLC | NOT
TO_KEY | TO_KEY | YES
*/
if (out_v.type() == typeid(txout_to_key))
{
return is_output_allowed_for_input(boost::get<txout_to_key>(out_v), in_v);
@ -7770,6 +7740,14 @@ bool blockchain_storage::is_output_allowed_for_input(const txout_target_v& out_v
//------------------------------------------------------------------
bool blockchain_storage::is_output_allowed_for_input(const txout_htlc& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const
{
/*
TxOutput | TxInput | Allowed
----------------------------
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
TO_KEY | HTLC | NOT
TO_KEY | TO_KEY | YES
*/
bool htlc_expired = out_v.expiration > (top_minus_source_height) ? false : true;
if (!htlc_expired)
{
@ -7791,21 +7769,6 @@ bool blockchain_storage::is_output_allowed_for_input(const txout_to_key& out_v,
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::is_output_allowed_for_input(const output_key_or_htlc_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const
{
if (out_v.type() == typeid(crypto::public_key))
{
return is_output_allowed_for_input(txout_to_key(), in_v);
}
else if (out_v.type() == typeid(txout_htlc))
{
return is_output_allowed_for_input(boost::get<txout_htlc>(out_v), in_v, top_minus_source_height);
}
else {
ASSERT_MES_AND_THROW("Unexpected type in output_key_or_htlc_v: " << out_v.type().name());
}
}
//------------------------------------------------------------------
bool blockchain_storage::is_output_allowed_for_input(const tx_out_zarcanum& out, const txin_v& in_v) const
{
CHECK_AND_ASSERT_MES(in_v.type() == typeid(txin_zc_input), false, "tx_out_zarcanum can only be referenced by txin_zc_input, not by " << in_v.type().name());
@ -7970,19 +7933,17 @@ bool blockchain_storage::update_alt_out_indexes_for_tx_in_block(const transactio
abei.gindex_lookup_table[o.amount] = m_db_outputs.get_item_size(o.amount);
//LOG_PRINT_MAGENTA("FIRST TOUCH: size=" << abei.gindex_lookup_table[o.amount], LOG_LEVEL_0);
}
if (o.target.type() == typeid(txout_to_key))
{
abei.outputs_pub_keys[o.amount].push_back(boost::get<txout_to_key>(o.target).key);
}
else
{
abei.outputs_pub_keys[o.amount].push_back(boost::get<txout_htlc>(o.target));
}
abei.outputs[o.amount].emplace_back(o);
//TODO: At the moment we ignore check of mix_attr again mixing to simplify alt chain check, but in future consider it for stronger validation
}
VARIANT_CASE_CONST(tx_out_zarcanum, toz)
//@#@
if (abei.gindex_lookup_table.find(0) == abei.gindex_lookup_table.end())
{
// amount was not found in altchain gindexes container, start indexing from current main chain gindex
abei.gindex_lookup_table[0] = m_db_outputs.get_item_size(0);
}
abei.outputs[0].emplace_back(toz);
VARIANT_SWITCH_END();
}
return true;
@ -8004,8 +7965,8 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
abei.gindex_lookup_table = alt_chain.back()->second.gindex_lookup_table;
//adjust indices for next alt block entry according to emount of pubkeys in txs of prev block
auto& prev_alt_keys = alt_chain.back()->second.outputs_pub_keys;
for (auto it = prev_alt_keys.begin(); it != prev_alt_keys.end(); it++)
auto& prev_alt_outputs = alt_chain.back()->second.outputs;
for (auto it = prev_alt_outputs.cbegin(); it != prev_alt_outputs.cend(); it++)
{
auto it_amont_in_abs_ind = abei.gindex_lookup_table.find(it->first);
CHECK_AND_ASSERT_MES(it_amont_in_abs_ind != abei.gindex_lookup_table.end(), false, "internal error: not found amount " << it->first << "in gindex_lookup_table");
@ -8038,7 +7999,7 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
// check PoS block miner tx in a special way
CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1 && b.miner_tx.vin.size() == 2, false, "invalid PoS block's miner_tx, signatures size = " << b.miner_tx.signatures.size() << ", miner_tx.vin.size() = " << b.miner_tx.vin.size());
r = validate_alt_block_input(b.miner_tx, collected_keyimages, alt_chain_tx_ids, id, get_block_hash(b), 1, split_height, alt_chain, alt_chain_block_ids, ki_lookup, &max_related_block_height);
r = validate_alt_block_input(b.miner_tx, collected_keyimages, alt_chain_tx_ids, id, get_block_hash(b), 1, split_height, alt_chain, alt_chain_block_ids, b.timestamp, abei.difficulty, ki_lookup, &max_related_block_height);
CHECK_AND_ASSERT_MES(r, false, "miner tx " << get_transaction_hash(b.miner_tx) << ": validation failed");
ki_lookup_time_total += ki_lookup;
@ -8071,7 +8032,7 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
if (tx.vin[n].type() == typeid(txin_to_key) || tx.vin[n].type() == typeid(txin_htlc) || tx.vin[n].type() == typeid(txin_zc_input))
{
uint64_t ki_lookup = 0;
r = validate_alt_block_input(tx, collected_keyimages, alt_chain_tx_ids, id, tx_id, n, split_height, alt_chain, alt_chain_block_ids, ki_lookup);
r = validate_alt_block_input(tx, collected_keyimages, alt_chain_tx_ids, id, tx_id, n, split_height, alt_chain, alt_chain_block_ids, 0, 0 /* <= both are not required for normal txs*/, ki_lookup);
CHECK_AND_ASSERT_MES(r, false, "tx " << tx_id << ", input #" << n << ": validation failed");
ki_lookup_time_total += ki_lookup;
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Copyright (c) 2012-2013 The Boolberry developers
@ -165,15 +165,13 @@ namespace currency
// retrieve gindex from main chain gindex table # not outputs having given amount are present after the given height
//
typedef boost::variant<crypto::public_key, txout_htlc> output_key_or_htlc_v;
struct alt_block_extended_info: public block_extended_info
{
// {amount -> gindex } output global index lookup table for this altblock (if an amount isn't present -- it's retreived from main outputs_container)
std::map<uint64_t, uint64_t> gindex_lookup_table;
// {amount -> pub_keys} map of outputs' pub_keys appeared in this alt block ( index_in_vector == output_gindex - gindex_lookup_table[output_amount] )
std::map<uint64_t, std::vector<output_key_or_htlc_v> > outputs_pub_keys;
// {amount -> outs} map of outputs' appeared in this alt block ( index_in_vector == output_gindex - gindex_lookup_table[output_amount] )
std::map<uint64_t, std::vector<tx_out_v> > outputs;
//date added to alt chain storage
uint64_t timestamp;
@ -638,6 +636,8 @@ namespace currency
uint64_t split_height,
const alt_chain_type& alt_chain,
const std::unordered_set<crypto::hash>& alt_chain_block_ids,
const uint64_t pos_block_timestamp,
const wide_difficulty_type& pos_difficulty,
uint64_t& ki_lookuptime,
uint64_t* p_max_related_block_height = nullptr) const;
bool validate_alt_block_ms_input(const transaction& input_tx,
@ -703,10 +703,10 @@ namespace currency
void calculate_local_gindex_lookup_table_for_height(uint64_t split_height, std::map<uint64_t, uint64_t>& increments) const;
void do_erase_altblock(alt_chain_container::iterator it);
uint64_t get_blockchain_launch_timestamp()const;
bool is_output_allowed_for_input(const txout_target_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const;
bool is_output_allowed_for_input(const output_key_or_htlc_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const;
bool is_output_allowed_for_input(const txout_to_key& out_v, const txin_v& in_v)const;
bool is_output_allowed_for_input(const txout_htlc& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const;
bool is_output_allowed_for_input(const tx_out_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height) const;
bool is_output_allowed_for_input(const txout_target_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height) const;
bool is_output_allowed_for_input(const txout_to_key& out_v, const txin_v& in_v) const;
bool is_output_allowed_for_input(const txout_htlc& out_v, const txin_v& in_v, uint64_t top_minus_source_height) const;
bool is_output_allowed_for_input(const tx_out_zarcanum& out, const txin_v& in_v) const;
@ -876,24 +876,26 @@ namespace currency
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
}
VARIANT_CASE_CONST(tx_out_zarcanum, out_zc)
bool r = is_output_allowed_for_input(out_zc, verified_input);
CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible");
r = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, out_zc.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast<uint32_t>(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size());
bool legit_output_key = validate_output_key_legit(out_zc.stealth_address);
CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << out_zc.stealth_address);
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n))
{
size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin();
LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx));
return false;
bool r = is_output_allowed_for_input(out_zc, verified_input);
CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible");
r = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, out_zc.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast<uint32_t>(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size());
bool legit_output_key = validate_output_key_legit(out_zc.stealth_address);
CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << out_zc.stealth_address);
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n))
{
size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin();
LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx));
return false;
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
VARIANT_CASE_THROW_ON_OTHER();
VARIANT_SWITCH_END();

View file

@ -180,7 +180,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(total_pos_blocks) DOC_DSCR("Number of blocks in a given range.") DOC_EXMP(87482) DOC_END
KV_SERIALIZE(votes) DOC_DSCR("Result of votes in a given range.") DOC_END
KV_SERIALIZE(votes) DOC_DSCR("Result of votes in a given range.") DOC_EXMP_AUTO(2) DOC_END
END_KV_SERIALIZE_MAP()
};

View file

@ -700,7 +700,7 @@ namespace currency
{
uint64_t total_max_supply = 0;
uint64_t current_supply = 0;
uint8_t decimal_point = 12;
uint8_t decimal_point = 0;
std::string ticker;
std::string full_name;
std::string meta_info;
@ -733,12 +733,12 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(total_max_supply) DOC_DSCR("Maximum possible supply for given asset, can't be changed after deployment") DOC_EXMP(1000000000000000000) DOC_END
KV_SERIALIZE(current_supply) DOC_DSCR("Currently emitted supply for given asset") DOC_EXMP(500000000000000000) DOC_END
KV_SERIALIZE(current_supply) DOC_DSCR("Currently emitted supply for given asset (ignored for REGISTER operation)") DOC_EXMP(500000000000000000) DOC_END
KV_SERIALIZE(decimal_point) DOC_DSCR("Decimal point") DOC_EXMP(12) DOC_END
KV_SERIALIZE(ticker) DOC_DSCR("Ticker associated with asset") DOC_EXMP("ZUSD") DOC_END
KV_SERIALIZE(full_name) DOC_DSCR("Full name of the asset") DOC_EXMP("Zano wrapped USD") DOC_END
KV_SERIALIZE(meta_info) DOC_DSCR("Any other information assetiaded with asset in a free form") DOC_EXMP("Stable and private") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(owner) DOC_DSCR("Owner's key, used to validate any operations on the asset altering, could be changed in case of transfer ownership") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(owner) DOC_DSCR("Owner's key, used only for EMIT and UPDATE validation, could be changed by transferring asset ownership") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
KV_SERIALIZE(hidden_supply) DOC_DSCR("This one reserved for future use, will be documented later") DOC_END
END_KV_SERIALIZE_MAP()
};

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2023 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Copyright (c) 2012-2013 The Boolberry developers
@ -355,7 +355,7 @@ namespace currency
CHECK_AND_ASSERT_MES(commitment_to_zero_is_sane, false, "internal error: commitment_to_zero is malformed (X)");
#endif
r = crypto::generate_double_schnorr_sig<crypto::gt_X, crypto::gt_G>(tx_id, commitment_to_zero, secret_x, ogc.tx_pub_key_p, ogc.tx_key.sec, proof.dss);
CHECK_AND_ASSERT_MES(r, false, "genergenerate_double_schnorr_sigate_schnorr_sig (X, G) failed");
CHECK_AND_ASSERT_MES(r, false, "generate_double_schnorr_sig (X, G) failed");
}
return true;
@ -700,6 +700,14 @@ namespace currency
// (sum(bare inputs' amounts) - fee) * H + sum(pseudo outs commitments for ZC inputs) - sum(outputs' commitments) = lin(X) OR = lin(G)
crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * currency::native_coin_asset_id_pt + sum_of_pseudo_out_amount_commitments - outs_commitments_sum;
DBG_VAL_PRINT(tx_id);
DBG_VAL_PRINT(tx_pub_key);
DBG_VAL_PRINT(bare_inputs_sum);
DBG_VAL_PRINT(fee);
DBG_VAL_PRINT(sum_of_pseudo_out_amount_commitments);
DBG_VAL_PRINT(outs_commitments_sum);
DBG_VAL_PRINT(commitment_to_zero);
CHECK_AND_ASSERT_MES(zc_inputs_count == zc_sigs_count, false, "zc inputs count (" << zc_inputs_count << ") and zc sigs count (" << zc_sigs_count << ") missmatch");
if (zc_inputs_count > 0)
{
@ -785,8 +793,7 @@ namespace currency
}
}
//---------------------------------------------------------------
// TODO: reverse order of arguments
bool parse_amount(uint64_t& amount, const std::string& str_amount_)
bool parse_amount(const std::string& str_amount_, uint64_t& amount, const size_t decimal_point /* = CURRENCY_DISPLAY_DECIMAL_POINT */)
{
std::string str_amount = str_amount_;
boost::algorithm::trim(str_amount);
@ -796,12 +803,12 @@ namespace currency
if (std::string::npos != point_index)
{
fraction_size = str_amount.size() - point_index - 1;
while (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size && '0' == str_amount.back())
while (decimal_point < fraction_size && '0' == str_amount.back())
{
str_amount.erase(str_amount.size() - 1, 1);
--fraction_size;
}
if (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size)
if (decimal_point < fraction_size)
return false;
str_amount.erase(point_index, 1);
}
@ -813,9 +820,9 @@ namespace currency
if (str_amount.empty())
return false;
if (fraction_size < CURRENCY_DISPLAY_DECIMAL_POINT)
if (fraction_size < decimal_point)
{
str_amount.append(CURRENCY_DISPLAY_DECIMAL_POINT - fraction_size, '0');
str_amount.append(decimal_point - fraction_size, '0');
}
return string_tools::get_xtype_from_string(amount, str_amount);
@ -3460,7 +3467,7 @@ namespace currency
uint64_t remainder = amount % coin;
amount /= coin;
if (remainder == 0)
return std::to_string(amount) + ".0";
return std::to_string(amount) + (decimal_point > 0 ? ".0" : "");
std::string r = std::to_string(remainder);
if (r.size() < decimal_point)
r.insert(0, decimal_point - r.size(), '0');
@ -4455,6 +4462,11 @@ namespace currency
return o << "<" << r.n << ":" << r.tx_id << ">";
}
//--------------------------------------------------------------------------------
std::ostream& operator <<(std::ostream& o, const std::type_info& ti)
{
return o << ti.name();
}
//--------------------------------------------------------------------------------
#ifndef MOBILE_WALLET_BUILD
const std::locale& utf8_get_conversion_locale()
{

View file

@ -402,7 +402,7 @@ namespace currency
uint64_t get_outs_money_amount(const transaction& tx, const currency::account_keys& acc_keys_for_hidden_amounts = currency::null_acc_keys);
bool check_inputs_types_supported(const transaction& tx);
bool check_outs_valid(const transaction& tx);
bool parse_amount(uint64_t& amount, const std::string& str_amount);
bool parse_amount(const std::string& str_amount, uint64_t& amount, const size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT);
bool parse_tracking_seed(const std::string& tracking_seed, account_public_address& address, crypto::secret_key& view_sec_key, uint64_t& creation_timestamp);
@ -610,20 +610,25 @@ namespace currency
return true;
}
//---------------------------------------------------------------
// outputs "1391306.970000000000"
// outputs "1391306.970000000000" (decimal_point = 12)
// outputs "1391306970000000000" (decimal_point = 0)
template<typename t_number>
std::string print_fixed_decimal_point(t_number amount, size_t decimal_point)
{
return epee::string_tools::print_fixed_decimal_point(amount, decimal_point);
}
//---------------------------------------------------------------
// outputs "1391306.97 "
// outputs "1391306.97 " (decimal_point = 12)
// outputs "139130697 " (decimal_point = 0)
template<typename t_number>
std::string print_fixed_decimal_point_with_trailing_spaces(t_number amount, size_t decimal_point)
{
std::string s = epee::string_tools::print_fixed_decimal_point(amount, decimal_point);
for(size_t n = s.size() - 1; n != 0 && s[n] == '0' && s[n-1] != '.'; --n)
s[n] = ' ';
if (s.find('.') != std::string::npos)
{
for(size_t n = s.size() - 1; n != 0 && s[n] == '0' && s[n-1] != '.'; --n)
s[n] = ' ';
}
return s;
}
//---------------------------------------------------------------
@ -945,6 +950,7 @@ namespace currency
//---------------------------------------------------------------
//---------------------------------------------------------------
std::ostream& operator <<(std::ostream& o, const ref_by_id& r);
std::ostream& operator <<(std::ostream& o, const std::type_info& ti);
//---------------------------------------------------------------
#ifndef MOBILE_WALLET_BUILD
std::string utf8_to_upper(const std::string& s);

View file

@ -398,14 +398,112 @@ namespace currency
CATCH_ENTRY2(std::vector<tx_source_entry::output_entry>{});
}
//---------------------------------------------------------------
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context)
bool validate_tx_details_against_tx_generation_context(const transaction& tx, const tx_generation_context& tgc)
{
//TODO: Implement this function before mainnet
#ifdef TESTNET
CHECK_AND_ASSERT_MES(tx.version >= TRANSACTION_VERSION_POST_HF4, false, "validate_tx_details_against_tx_generation_context should never be called for pre-HF4 txs");
//
// outputs
// (all outputs are ZC outputs, because we require tx.version to be post-HF4)
size_t tx_outs_count = tx.vout.size();
CHECK_AND_ASSERT_EQ(tgc.asset_ids.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.blinded_asset_ids.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.amount_commitments.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.asset_id_blinding_masks.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.amounts.size(), tx_outs_count);
CHECK_AND_ASSERT_EQ(tgc.amount_blinding_masks.size(), tx_outs_count);
crypto::point_t amount_commitments_sum = crypto::c_point_0;
crypto::scalar_t amount_blinding_masks_sum{};
crypto::scalar_t asset_id_blinding_mask_x_amount_sum{};
for(size_t i = 0; i < tx_outs_count; ++i)
{
crypto::point_t calculated_T = tgc.asset_ids[i] + tgc.asset_id_blinding_masks[i] * crypto::c_point_X;
CHECK_AND_ASSERT_MES(calculated_T.is_in_main_subgroup(), false, "calculated_T isn't in the main subgroup");
CHECK_AND_ASSERT_EQ(tgc.blinded_asset_ids[i], calculated_T);
crypto::point_t calculated_A = tgc.amounts[i] * calculated_T + tgc.amount_blinding_masks[i] * crypto::c_point_G;
CHECK_AND_ASSERT_MES(calculated_A.is_in_main_subgroup(), false, "calculated_A isn't in the main subgroup");
CHECK_AND_ASSERT_EQ(tgc.amount_commitments[i], calculated_A);
const tx_out_zarcanum& tx_out_zc = boost::get<tx_out_zarcanum>(tx.vout[i]);
crypto::point_t tx_T = crypto::point_t(tx_out_zc.blinded_asset_id).modify_mul8();
CHECK_AND_ASSERT_EQ(tgc.blinded_asset_ids[i], tx_T);
crypto::point_t tx_A = crypto::point_t(tx_out_zc.amount_commitment).modify_mul8();
CHECK_AND_ASSERT_EQ(tgc.amount_commitments[i], tx_A);
amount_commitments_sum += calculated_A;
amount_blinding_masks_sum += tgc.amount_blinding_masks[i];
asset_id_blinding_mask_x_amount_sum += tgc.asset_id_blinding_masks[i] * tgc.amounts[i];
}
CHECK_AND_ASSERT_EQ(tgc.amount_commitments_sum, amount_commitments_sum);
CHECK_AND_ASSERT_EQ(tgc.amount_blinding_masks_sum, amount_blinding_masks_sum);
CHECK_AND_ASSERT_EQ(tgc.asset_id_blinding_mask_x_amount_sum, asset_id_blinding_mask_x_amount_sum);
//
// inputs
//
size_t tx_inputs_count = tx.vin.size();
size_t tx_zc_inputs_count = count_type_in_variant_container<txin_zc_input>(tx.vin);
size_t tx_bare_inputs_count = count_type_in_variant_container<txin_to_key>(tx.vin);
CHECK_AND_ASSERT_EQ(tx_inputs_count, tx_zc_inputs_count + tx_bare_inputs_count);
CHECK_AND_ASSERT_EQ(tx.signatures.size(), tx.vin.size()); // can do this because we shouldn't face additional signature so far
CHECK_AND_ASSERT_EQ(tgc.pseudo_outs_blinded_asset_ids.size(), tx_zc_inputs_count);
CHECK_AND_ASSERT_EQ(tgc.pseudo_outs_plus_real_out_blinding_masks.size(), tx_zc_inputs_count);
CHECK_AND_ASSERT_EQ(tgc.real_zc_ins_asset_ids.size(), tx_zc_inputs_count);
CHECK_AND_ASSERT_EQ(tgc.zc_input_amounts.size(), tx_zc_inputs_count);
crypto::point_t pseudo_out_amount_commitments_sum = crypto::c_point_0;
for(size_t input_index = 0, zc_input_index = 0; input_index < tx.vin.size(); ++input_index)
{
const txin_v& in_v = tx.vin[input_index];
if (in_v.type() == typeid(txin_zc_input))
{
CHECK_AND_ASSERT_EQ(tx.signatures[input_index].type(), typeid(ZC_sig));
const ZC_sig& sig = boost::get<ZC_sig>(tx.signatures[input_index]);
crypto::point_t sig_pseudo_out_amount_commitment = crypto::point_t(sig.pseudo_out_amount_commitment).modify_mul8();
crypto::point_t sig_pseudo_out_blinded_asset_id = crypto::point_t(sig.pseudo_out_blinded_asset_id).modify_mul8();
crypto::point_t pseudo_out_blinded_asset_id_calculated = tgc.real_zc_ins_asset_ids[zc_input_index] + tgc.pseudo_outs_plus_real_out_blinding_masks[zc_input_index] * crypto::c_point_X; // T^P = H_i + r_pi*X + r'_i*X
CHECK_AND_ASSERT_EQ(sig_pseudo_out_blinded_asset_id, pseudo_out_blinded_asset_id_calculated);
CHECK_AND_ASSERT_EQ(tgc.pseudo_outs_blinded_asset_ids[zc_input_index], pseudo_out_blinded_asset_id_calculated);
CHECK_AND_ASSERT_MES(pseudo_out_blinded_asset_id_calculated.is_in_main_subgroup(), false, "pseudo_out_blinded_asset_id_calculated isn't in the main subgroup");
// cannot be verified:
// tgc.zc_input_amounts[zc_input_index]; // ZC only input amounts
pseudo_out_amount_commitments_sum += sig_pseudo_out_amount_commitment;
++zc_input_index;
}
else if (in_v.type() == typeid(txin_to_key))
{
// do nothing
}
else
{
// should never get here
CHECK_AND_ASSERT_MES(false, false, "internal error, unexpected type: " << in_v.type().name());
}
}
// tx secret and public keys
CHECK_AND_ASSERT_MES(tgc.tx_pub_key_p.is_in_main_subgroup(), false, "tgc.tx_pub_key_p isn't in the main subgroup");
CHECK_AND_ASSERT_EQ(tgc.tx_pub_key_p.to_public_key(), tgc.tx_key.pub);
CHECK_AND_ASSERT_EQ(crypto::scalar_t(tgc.tx_key.sec) * crypto::c_point_G, tgc.tx_pub_key_p);
// no ongoing asset operation
CHECK_AND_ASSERT_EQ(tgc.ao_asset_id, currency::null_pkey);
CHECK_AND_ASSERT_EQ(tgc.ao_asset_id_pt, crypto::c_point_0);
CHECK_AND_ASSERT_EQ(tgc.ao_amount_commitment, crypto::c_point_0);
CHECK_AND_ASSERT_EQ(tgc.ao_amount_blinding_mask, crypto::c_scalar_0);
// cannot be verified:
// tgc.pseudo_out_amount_blinding_masks_sum
// tgc.real_in_asset_id_blinding_mask_x_amount_sum
return true;
#else
return true;
#endif
}
//----------------------------------------------------------------------------------------------------
@ -421,4 +519,4 @@ namespace currency
}
}
}

View file

@ -286,15 +286,15 @@ namespace currency
// consider redesign, some data may possibly be excluded from kv serialization -- sowle
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blinded_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_commitments)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_id_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amounts)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_blinded_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_plus_real_out_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(real_zc_ins_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(blinded_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(amount_commitments)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(asset_id_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(amounts)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(amount_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(pseudo_outs_blinded_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(pseudo_outs_plus_real_out_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_HEX(real_zc_ins_asset_ids)
KV_SERIALIZE(zc_input_amounts)
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_commitments_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_blinding_masks_sum)
@ -344,7 +344,8 @@ namespace currency
END_SERIALIZE()
}; // struct tx_generation_context
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context);
bool validate_tx_details_against_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context);
std::string transform_tx_to_str(const transaction& tx);
transaction transform_str_to_tx(const std::string& tx_str);

View file

@ -978,18 +978,36 @@ QString MainWindow::start_backend(const QString& params)
QString MainWindow::sync_call(const QString& func_name, const QString& params)
{
if (func_name == "transfer")
{
return this->transfer(params);
}
else if (func_name == "test_call")
if (func_name == "test_call")
{
return params;
}
std::string fuc_name_std = func_name.toStdString();
QString response_str;
bool r = QMetaObject::invokeMethod(this, fuc_name_std.c_str(), Qt::DirectConnection, Q_RETURN_ARG(QString, response_str), Q_ARG(QString, params));
//bool r = this->invokeMethod(fuc_name_std.c_str(), Q_RETURN_ARG(QString, response_str), Q_ARG(QString, params));
if (r)
return response_str;
else
{
return QString(QString() + "{ \"status\": \"Method '" + func_name + "' not found\"}");
return QString(QString() + "{ \"status\": \"Method '" + func_name + "' not found\"}");
}
}
QString MainWindow::sync_call_2a(const QString& func_name, const QString& params1, const QString& params2)
{
std::string fuc_name_std = func_name.toStdString();
QString response_str;
bool r = QMetaObject::invokeMethod(this, fuc_name_std.c_str(), Qt::DirectConnection, Q_RETURN_ARG(QString, response_str), Q_ARG(QString, params1), Q_ARG(QString, params2));
//bool r = this->invokeMethod(fuc_name_std.c_str(), Q_RETURN_ARG(QString, response_str), Q_ARG(QString, params));
if (r)
return response_str;
else
{
return QString(QString() + "{ \"status\": \"Method '" + func_name + "' not found\"}");
}
}
QString MainWindow::async_call(const QString& func_name, const QString& params)
@ -1010,6 +1028,25 @@ QString MainWindow::async_call(const QString& func_name, const QString& params)
return QString::fromStdString(std::string("{ \"job_id\": ") + std::to_string(job_id) + "}");
}
QString MainWindow::async_call_2a(const QString& func_name, const QString& params1, const QString& params2)
{
uint64_t job_id = m_ui_dispatch_id_counter++;
QString method_name = func_name;
QString argements1 = params1;
QString argements2 = params2;
auto async_callback = [this, method_name, argements1, argements2, job_id]()
{
QString res_str = this->sync_call_2a(method_name, argements1, argements2);
this->dispatch_async_call_result(std::to_string(job_id).c_str(), res_str); //general function
};
m_threads_pool.add_job(async_callback);
LOG_PRINT_L2("[UI_ASYNC_CALL]: started " << method_name.toStdString() << ", job id: " << job_id);
return QString::fromStdString(std::string("{ \"job_id\": ") + std::to_string(job_id) + "}");
}
bool MainWindow::update_wallet_status(const view::wallet_status_info& wsi)
{
@ -1294,7 +1331,7 @@ QString MainWindow::request_alias_update(const QString& param)
// view::transfer_response tr = AUTO_VAL_INIT(tr);
currency::transaction res_tx = AUTO_VAL_INIT(res_tx);
ar.error_code = m_backend.request_alias_update(tp.alias, tp.wallet_id, tp.fee, res_tx, tp.reward);
ar.error_code = m_backend.request_alias_update(tp.alias, tp.wallet_id, tp.fee, res_tx);
if (ar.error_code != API_RETURN_CODE_OK)
return MAKE_RESPONSE(ar);

View file

@ -110,7 +110,7 @@ public:
QString get_version(const QString& param);
QString get_os_version(const QString& param);
QString get_network_type(const QString& param);
QString transfer(const QString& json_transfer_object);
QString transfer(const QString& param);
QString have_secure_app_data(const QString& param);
QString drop_secure_app_data(const QString& param);
QString get_secure_app_data(const QString& param);
@ -193,6 +193,9 @@ public:
QString async_call(const QString& func_name, const QString& params);
QString sync_call(const QString& func_name, const QString& params);
QString async_call_2a(const QString& func_name, const QString& params1, const QString& params2);
QString sync_call_2a(const QString& func_name, const QString& params1, const QString& params2);
//for test purposes only
QString request_dummy(const QString& param);

@ -1 +1 @@
Subproject commit 9be6a53f757a17403ea5798d08b577d450eb620a
Subproject commit 0710887ae3231d329092691f326d91d90662149e

View file

@ -39,7 +39,7 @@ namespace currency
void set_rpc_chain_handler(epee::net_utils::http::i_chain_handler* prpc_chain_handler) { m_prpc_chain_handler = prpc_chain_handler; }
bool on_get_blocks_direct(const COMMAND_RPC_GET_BLOCKS_DIRECT::request& req, COMMAND_RPC_GET_BLOCKS_DIRECT::response& res, connection_context& cntx);
void set_ignore_connectivity_status(bool ignore) { m_ignore_status = ignore;}
bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, connection_context& cntx);
bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, connection_context& cntx);

View file

@ -89,7 +89,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status code, OK if succeeded.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(error_code) DOC_DSCR("Error code, if there's any error (optional).") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(aliases_que) DOC_DSCR("List of aliases from txs that are currently in the tx pool.") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(aliases_que) DOC_DSCR("List of aliases from txs that are currently in the tx pool.") DOC_EXMP_AUTO(1) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -161,8 +161,8 @@ namespace currency
uint64_t count = 100;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(offset) DOC_DSCR("Offset for the item to start copying") DOC_EXMP(0) DOC_END
KV_SERIALIZE(count) DOC_DSCR("Number of items to recieve") DOC_EXMP(100) DOC_END
KV_SERIALIZE(offset) DOC_DSCR("Offset for the item to start copying") DOC_EXMP(0) DOC_END
KV_SERIALIZE(count) DOC_DSCR("Number of items to recieve") DOC_EXMP(100) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -172,8 +172,8 @@ namespace currency
std::list<currency::asset_descriptor_with_id> assets;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status code of operation, OK if success") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(assets) DOC_DSCR("List of assets registered in Zano blockchain") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status code of operation, OK if success") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(assets) DOC_DSCR("List of assets registered in Zano blockchain") DOC_EXMP_AUTO(1) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -224,9 +224,9 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blocks) DOC_DSCR("Bunch of blocks") DOC_END
KV_SERIALIZE(start_height) DOC_DSCR("Starting height of the resulting bunch of blocks.") DOC_END
KV_SERIALIZE(current_height) DOC_DSCR("Current height of the blockchain.") DOC_END
KV_SERIALIZE(blocks) DOC_DSCR("Bunch of blocks") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(start_height) DOC_DSCR("Starting height of the resulting bunch of blocks.") DOC_EXMP(2000000) DOC_END
KV_SERIALIZE(current_height) DOC_DSCR("Current height of the blockchain.") DOC_EXMP(2555000) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -245,7 +245,7 @@ namespace currency
std::list<std::string> txs_hashes;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txs_hashes) DOC_DSCR("List of transactions' IDs.") DOC_EXMP_AUTO() DOC_END // "146791c4f5ca94bcf423557e5eb859a3a69991bd33960d52f709d88bf5d1ac6d","ec4d913a40a9ac1fbd9d33b71ef507b5c85d1f503b89096618a18b08991b5171") DOC_END
KV_SERIALIZE(txs_hashes) DOC_DSCR("List of transactions' IDs.") DOC_EXMP_AGGR("146791c4f5ca94bcf423557e5eb859a3a69991bd33960d52f709d88bf5d1ac6d","ec4d913a40a9ac1fbd9d33b71ef507b5c85d1f503b89096618a18b08991b5171") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -257,7 +257,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txs_as_hex) DOC_DSCR("Transactions stored as blobs") DOC_EXMP_AUTO(1, "7d914497d91442f8f3c2268397d914497d91442f8f3c22683585eaa60b53757d49bf046a96269cef45c1bc9ff7300cc2f8f3c22683585eaa60b53757d49bf046a96269cef45c1bc9ff7300cc") DOC_END
KV_SERIALIZE(missed_tx) DOC_DSCR("Missed transactions hashes") DOC_EXMP_AUTO(1, "97d91442f8f3c22683585eaa60b53757d49bf046a96269cef45c1bc9ff7300cc") DOC_END
KV_SERIALIZE(missed_tx) DOC_DSCR("Missed transactions hashes") DOC_EXMP_AUTO(1, "ec4d913a40a9ac1fbd9d33b71ef507b5c85d1f503b89096618a18b08991b5171") DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -307,7 +307,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txs) DOC_DSCR("Transactions as blobs.") DOC_EXMP_AUTO(1, "7d914497d91442f8f3c2268397d914497d91442f8f3c22683585eaa60b53757d49bf046a96269cef45c1bc9ff7300cc2f8f3c22683585eaa60b53757d49bf046a96269cef45c1bc9ff7300cc") DOC_END
KV_SERIALIZE(tx_expiration_ts_median) DOC_DSCR("Timestamp median value of last TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW blocks.") DOC_END
KV_SERIALIZE(tx_expiration_ts_median) DOC_DSCR("Timestamp median value of last TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW blocks.") DOC_EXMP(1711021795) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -321,7 +321,7 @@ namespace currency
{
std::list<crypto::key_image> images;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(images) //DOC_DSCR("List of key images.") DOC_END
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(images) //DOC_DSCR("List of key images.") DOC_EXMP_AGGR({{'\xd6', '\x32', '\x9b', '\x5b', '\x1f', '\x7c', '\x08', '\x05', '\xb5', '\xc3', '\x45', '\xf4', '\x95', '\x75', '\x54', '\x00', '\x2a', '\x2f', '\x55', '\x78', '\x45', '\xf6', '\x4d', '\x76', '\x45', '\xda', '\xe0', '\xe0', '\x51', '\xa6', '\x49', '\x8a'}}) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -374,8 +374,8 @@ namespace currency
uint64_t i;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount) DOC_DSCR("The specific amount of output to query.") DOC_END
KV_SERIALIZE(i) DOC_DSCR("The global index of the output amount to be queried.") DOC_END
KV_SERIALIZE(amount) DOC_DSCR("The specific amount of output to query.") DOC_EXMP(3000000000000) DOC_END
KV_SERIALIZE(i) DOC_DSCR("The global index of the output amount to be queried.") DOC_EXMP(0) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -386,8 +386,8 @@ namespace currency
uint64_t out_no;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Transaction ID where the queried output is present, if found.") DOC_END
KV_SERIALIZE(out_no) DOC_DSCR("Local output index within the transaction.") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Transaction ID where the queried output is present, if found.") DOC_EXMP("a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8") DOC_END
KV_SERIALIZE(out_no) DOC_DSCR("Local output index within the transaction.") DOC_EXMP(7) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -403,7 +403,7 @@ namespace currency
crypto::hash ms_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(ms_id) DOC_DSCR("The multisig output's unique identifier (hash).") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(ms_id) DOC_DSCR("The multisig output's unique identifier (hash).") DOC_EXMP("a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -414,8 +414,8 @@ namespace currency
uint64_t out_no;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Transaction ID where the multisig output is present, if found.")DOC_END
KV_SERIALIZE(out_no) DOC_DSCR("Local output index within the transaction.") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Transaction ID where the multisig output is present, if found.") DOC_EXMP("a88541e38d64f87c41b9153412d1d7667f6e4337fe429ed1374722355fa7b423") DOC_END
KV_SERIALIZE(out_no) DOC_DSCR("Local output index within the transaction.") DOC_EXMP(11) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -432,10 +432,10 @@ namespace currency
uint64_t height_upper_limit; // if nonzero, all the decoy outputs must be either older than, or the same age as this height
bool use_forced_mix_outs;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amounts) DOC_DSCR("List of amounts for which decoy outputs are requested.") DOC_END
KV_SERIALIZE(decoys_count) DOC_DSCR("Number of decoy outputs required for each amount specified.") DOC_END
KV_SERIALIZE(height_upper_limit) DOC_DSCR("Maximum blockchain height from which decoys can be taken. If nonzero, decoys must be at this height or older.") DOC_END
KV_SERIALIZE(use_forced_mix_outs) DOC_DSCR("If true, only outputs with a 'mix_attr' greater than 0 are used as decoys.") DOC_END
KV_SERIALIZE(amounts) DOC_DSCR("List of amounts for which decoy outputs are requested.") DOC_EXMP_AGGR(0, 10000000000, 5000000000000) DOC_END
KV_SERIALIZE(decoys_count) DOC_DSCR("Number of decoy outputs required for each amount specified.") DOC_EXMP_AUTO(10) DOC_END
KV_SERIALIZE(height_upper_limit) DOC_DSCR("Maximum blockchain height from which decoys can be taken. If nonzero, decoys must be at this height or older.") DOC_EXMP_AUTO(2555000) DOC_END
KV_SERIALIZE(use_forced_mix_outs) DOC_DSCR("If true, only outputs with a 'mix_attr' greater than 0 are used as decoys.") DOC_EXMP_AUTO(false) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -469,7 +469,7 @@ namespace currency
std::list<out_entry> outs;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount) DOC_DSCR("The amount for which decoys are returned.") DOC_END
KV_SERIALIZE(amount) DOC_DSCR("The amount for which decoys are returned.") DOC_EXMP_AUTO(10000000000) DOC_END
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs) //DOC_DSCR("List of 'out_entry' structures, serialized as a blob.") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -479,7 +479,7 @@ namespace currency
std::vector<outs_for_amount> outs;
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs) DOC_DSCR("List of 'outs_for_amount' structures, each containing decoys for a specific amount.") DOC_END
KV_SERIALIZE(outs) DOC_DSCR("List of 'outs_for_amount' structures, each containing decoys for a specific amount.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -495,8 +495,8 @@ namespace currency
std::vector<uint64_t> global_offsets; //[i] = global_index to pick up
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount) DOC_DSCR("If set to 0, only ZC outputs are considered. If nonzero, only old bare outputs are considered.") DOC_END
KV_SERIALIZE(global_offsets) DOC_DSCR("List of global indices for picking decoys. Each index corresponds to a potential decoy output.") DOC_END
KV_SERIALIZE(amount) DOC_DSCR("If set to 0, only ZC outputs are considered. If nonzero, only old bare outputs are considered.") DOC_EXMP_AUTO(0) DOC_END
KV_SERIALIZE(global_offsets) DOC_DSCR("List of global indices for picking decoys. Each index corresponds to a potential decoy output.") DOC_EXMP_AGGR(1, 3, 5928, 2811) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -508,10 +508,10 @@ namespace currency
bool use_forced_mix_outs;
uint64_t coinbase_percents; //from 0 to 100, estimate percents of coinbase outputs included in decoy sets
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amounts) DOC_DSCR("List of amount distributions specifying where to look for decoys, based on old bare outputs or ZC outputs.") DOC_END
KV_SERIALIZE(height_upper_limit) DOC_DSCR("Maximum blockchain height from which decoys can be taken. If nonzero, decoys must be at this height or older.") DOC_END
KV_SERIALIZE(use_forced_mix_outs) DOC_DSCR("If true, only outputs with a 'mix_attr' greater than 0 are used as decoys.") DOC_END
KV_SERIALIZE(coinbase_percents) DOC_DSCR("Specifies the estimated percentage of coinbase outputs to be included in the decoy sets, ranging from 0 to 100.") DOC_END
KV_SERIALIZE(amounts) DOC_DSCR("List of amount distributions specifying where to look for decoys, based on old bare outputs or ZC outputs.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(height_upper_limit) DOC_DSCR("Maximum blockchain height from which decoys can be taken. If nonzero, decoys must be at this height or older.") DOC_EXMP(2555000) DOC_END
KV_SERIALIZE(use_forced_mix_outs) DOC_DSCR("If true, only outputs with a 'mix_attr' greater than 0 are used as decoys.") DOC_EXMP(false) DOC_END
KV_SERIALIZE(coinbase_percents) DOC_DSCR("Specifies the estimated percentage of coinbase outputs to be included in the decoy sets, ranging from 0 to 100.") DOC_EXMP(15) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -529,9 +529,9 @@ namespace currency
bool use_forced_mix_outs;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amounts) DOC_DSCR("List of amounts for which decoy outputs are requested.") DOC_END
KV_SERIALIZE(outs_count) DOC_DSCR("Number of decoy outputs requested for each amount.") DOC_END
KV_SERIALIZE(use_forced_mix_outs) DOC_DSCR("If true, only outputs with a 'mix_attr' greater than 0 are used as decoys.") DOC_END
KV_SERIALIZE(amounts) DOC_DSCR("List of amounts for which decoy outputs are requested.") DOC_EXMP_AGGR(0, 10000000000) DOC_END
KV_SERIALIZE(outs_count) DOC_DSCR("Number of decoy outputs requested for each amount.") DOC_EXMP(2) DOC_END
KV_SERIALIZE(use_forced_mix_outs) DOC_DSCR("If true, only outputs with a 'mix_attr' greater than 0 are used as decoys.") DOC_EXMP(false) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -549,7 +549,7 @@ namespace currency
std::list<out_entry> outs;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount) DOC_DSCR("The amount for which decoys are returned.") DOC_END
KV_SERIALIZE(amount) DOC_DSCR("The amount for which decoys are returned.") DOC_EXMP(10000000000) DOC_END
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs) //DOC_DSCR("List of 'out_entry' structures serialized as a blob, representing the decoy outputs for the specified amount.") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -560,7 +560,7 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs) DOC_DSCR("List of 'outs_for_amount' structures, each containing decoys for a specific amount.") DOC_END
KV_SERIALIZE(outs) DOC_DSCR("List of 'outs_for_amount' structures, each containing decoys for a specific amount.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -595,7 +595,7 @@ namespace currency
explicit request(const transaction &);
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_as_hex) DOC_DSCR("The transaction data as a hexadecimal string, ready for network broadcast.") DOC_END
KV_SERIALIZE(tx_as_hex) DOC_DSCR("The transaction data as a hexadecimal string, ready for network broadcast.") DOC_EXMP("00018ed1535b8b4862e.....368cdc5a86") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -619,7 +619,7 @@ namespace currency
std::vector<std::string> txs_as_hex;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txs_as_hex) DOC_DSCR("List of transactions as a hexadecimal strings.") DOC_END
KV_SERIALIZE(txs_as_hex) DOC_DSCR("List of transactions as a hexadecimal strings.") DOC_EXMP_AGGR("000535b8b2e.....3685a86", "00087368b2e.....349b77f") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -644,8 +644,8 @@ namespace currency
uint64_t threads_count;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(miner_address) DOC_DSCR("The address where the mining rewards will be deposited.") DOC_END
KV_SERIALIZE(threads_count) DOC_DSCR("The number of CPU threads to use for mining.") DOC_END
KV_SERIALIZE(miner_address) DOC_DSCR("The address where the mining rewards will be deposited.") DOC_EXMP("ZxCSpsGGeJsS8fwvQ4HktDU3qBeauoJTR6j73jAWWZxFXdF7XTbGm4YfS2kXJmAP4Rf5BVsSQ9iZ45XANXEYsrLN2L2W77dH7") DOC_END
KV_SERIALIZE(threads_count) DOC_DSCR("The number of CPU threads to use for mining.") DOC_EXMP(2) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -850,7 +850,7 @@ namespace currency
uint64_t flags;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(flags) DOC_DSCR("Combination of flags to request specific data elements that are computationally expensive to calculate.") DOC_END
KV_SERIALIZE(flags) DOC_DSCR("Combination of flags to request specific data elements that are computationally expensive to calculate.") DOC_EXMP(1048575) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -920,55 +920,55 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
// Always calculated and provided fields
KV_SERIALIZE(height) DOC_DSCR("The current size of the blockchain, equal to the height of the top block plus one.") DOC_END
KV_SERIALIZE(pos_allowed) DOC_DSCR("Boolean value indicating whether PoS mining is currently allowed based on network rules and state.") DOC_END
KV_SERIALIZE(pos_difficulty) DOC_DSCR("Current difficulty for Proof of Stake mining.") DOC_END
KV_SERIALIZE(pow_difficulty) DOC_DSCR("Current difficulty for Proof of Work mining.") DOC_END
KV_SERIALIZE(tx_count) DOC_DSCR("Total number of transactions in the blockchain.") DOC_END
KV_SERIALIZE(tx_pool_size) DOC_DSCR("Number of transactions currently in the pool.") DOC_END
KV_SERIALIZE(alt_blocks_count) DOC_DSCR("Number of alternative blocks on the blockchain.") DOC_END
KV_SERIALIZE(outgoing_connections_count) DOC_DSCR("Number of outgoing P2P connections to other nodes.") DOC_END
KV_SERIALIZE(incoming_connections_count) DOC_DSCR("Number of incoming P2P connections established by other nodes.") DOC_END
KV_SERIALIZE(synchronized_connections_count) DOC_DSCR("Number of P2P connections to nodes that have a fully synchronized blockchain.") DOC_END
KV_SERIALIZE(white_peerlist_size) DOC_DSCR("Size of the white peer list, which includes addresses of reliable nodes.") DOC_END
KV_SERIALIZE(grey_peerlist_size) DOC_DSCR("Size of the grey peer list, which includes addresses of nodes with less consistent availability.") DOC_END
KV_SERIALIZE(height) DOC_DSCR("The current size of the blockchain, equal to the height of the top block plus one.") DOC_EXMP(2555000) DOC_END
KV_SERIALIZE(pos_allowed) DOC_DSCR("Boolean value indicating whether PoS mining is currently allowed based on network rules and state.") DOC_EXMP(true) DOC_END
KV_SERIALIZE(pos_difficulty) DOC_DSCR("Current difficulty for Proof of Stake mining.") DOC_EXMP("1848455949616658404658") DOC_END
KV_SERIALIZE(pow_difficulty) DOC_DSCR("Current difficulty for Proof of Work mining.") DOC_EXMP(12777323347117) DOC_END
KV_SERIALIZE(tx_count) DOC_DSCR("Total number of transactions in the blockchain.") DOC_EXMP(767742) DOC_END
KV_SERIALIZE(tx_pool_size) DOC_DSCR("Number of transactions currently in the pool.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(alt_blocks_count) DOC_DSCR("Number of alternative blocks on the blockchain.") DOC_EXMP(99) DOC_END
KV_SERIALIZE(outgoing_connections_count) DOC_DSCR("Number of outgoing P2P connections to other nodes.") DOC_EXMP(8) DOC_END
KV_SERIALIZE(incoming_connections_count) DOC_DSCR("Number of incoming P2P connections established by other nodes.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(synchronized_connections_count) DOC_DSCR("Number of P2P connections to nodes that have a fully synchronized blockchain.") DOC_EXMP(8) DOC_END
KV_SERIALIZE(white_peerlist_size) DOC_DSCR("Size of the white peer list, which includes addresses of reliable nodes.") DOC_EXMP(12) DOC_END
KV_SERIALIZE(grey_peerlist_size) DOC_DSCR("Size of the grey peer list, which includes addresses of nodes with less consistent availability.") DOC_EXMP(321) DOC_END
KV_SERIALIZE(current_blocks_median) // TODO
KV_SERIALIZE(alias_count) DOC_DSCR("The total number of unique aliases registered on the blockchain. Aliases are alternate, human-readable names associated with addresses.") DOC_END
KV_SERIALIZE(current_max_allowed_block_size) DOC_DSCR("Current maximum allowed cummulative block size in bytes.") DOC_END
KV_SERIALIZE(is_hardfok_active) DOC_DSCR("A list of boolean values indicating whether each corresponding hardfork is active. For example, a list 'true, true, false' indicates that the first hardfork is activated, while the second is not. Hardfork #0 is always active as it is a stub.") DOC_END
KV_SERIALIZE(daemon_network_state) DOC_DSCR("Current network state of the daemon, which could be connecting, synchronizing, online, loading core, internal error, unloading core, or downloading database.") DOC_END
KV_SERIALIZE(synchronization_start_height) DOC_DSCR("Blockchain height at which the current synchronization process started. Indicates the starting point for catching up to the network's latest state.") DOC_END
KV_SERIALIZE(max_net_seen_height) DOC_DSCR("Maximum blockchain height observed in the network by this node.") DOC_END
KV_SERIALIZE(default_fee) DOC_DSCR("Default fee for transactions.") DOC_END
KV_SERIALIZE(minimum_fee) DOC_DSCR("Minimum fee for transactions.") DOC_END
KV_SERIALIZE(mi) DOC_DSCR("The most recent mainterner's info.") DOC_END
KV_SERIALIZE(alias_count) DOC_DSCR("The total number of unique aliases registered on the blockchain. Aliases are alternate, human-readable names associated with addresses.") DOC_EXMP(1653) DOC_END
KV_SERIALIZE(current_max_allowed_block_size) DOC_DSCR("Current maximum allowed cummulative block size in bytes.") DOC_EXMP(250000) DOC_END
KV_SERIALIZE(is_hardfok_active) DOC_DSCR("A list of boolean values indicating whether each corresponding hardfork is active. For example, a list 'true, true, false' indicates that the first hardfork is activated, while the second is not. Hardfork #0 is always active as it is a stub.") DOC_EXMP_AGGR(true,true,true,true,true,false) DOC_END
KV_SERIALIZE(daemon_network_state) DOC_DSCR("Current network state of the daemon, which could be connecting, synchronizing, online, loading core, internal error, unloading core, or downloading database.") DOC_EXMP(2) DOC_END
KV_SERIALIZE(synchronization_start_height) DOC_DSCR("Blockchain height at which the current synchronization process started. Indicates the starting point for catching up to the network's latest state.") DOC_EXMP(2555000) DOC_END
KV_SERIALIZE(max_net_seen_height) DOC_DSCR("Maximum blockchain height observed in the network by this node.") DOC_EXMP(2555743) DOC_END
KV_SERIALIZE(default_fee) DOC_DSCR("Default fee for transactions.") DOC_EXMP(10000000000) DOC_END
KV_SERIALIZE(minimum_fee) DOC_DSCR("Minimum fee for transactions.") DOC_EXMP(10000000000) DOC_END
KV_SERIALIZE(mi) DOC_DSCR("The most recent mainterner's info.") DOC_EXMP_AUTO() DOC_END
// Fields dependent on flags for their inclusion
KV_SERIALIZE(net_time_delta_median) DOC_DSCR("A value of 0 indicates no time synchronization issues, while a value of 1 indicates the presence of time sync issues. Only available if the COMMAND_RPC_GET_INFO_FLAG_NET_TIME_DELTA_MEDIAN flag is set.") DOC_END
KV_SERIALIZE(current_network_hashrate_50)DOC_DSCR("The PoW hash rate calculated over the last 50 blocks of any type. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_CURRENT_NETWORK_HASHRATE_50 flag is set.") DOC_END
KV_SERIALIZE(current_network_hashrate_350) DOC_DSCR("The PoW hash rate calculated over the last 350 blocks of any type. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_CURRENT_NETWORK_HASHRATE_350 flag is set.") DOC_END
KV_SERIALIZE(seconds_for_10_blocks) DOC_DSCR("The time period in seconds between the most recent block and the 10th block older. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_SECONDS_FOR_10_BLOCKS flag is set.") DOC_END
KV_SERIALIZE(seconds_for_30_blocks) DOC_DSCR("The time period in seconds between the most recent block and the 30th block older. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_SECONDS_FOR_30_BLOCKS flag is set.") DOC_END
KV_SERIALIZE(transactions_cnt_per_day) DOC_DSCR("The number of non-mining transactions recorded over the last 24 hours. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_TRANSACTIONS_DAILY_STAT flag is set.") DOC_END
KV_SERIALIZE(transactions_volume_per_day)DOC_DSCR("The total sum of input amounts from all non-mining transactions over the last 24 hours. Only old bare inputs with explicit amounts are considered. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_TRANSACTIONS_DAILY_STAT flag is set.") DOC_END
KV_SERIALIZE(last_pos_timestamp) DOC_DSCR("The timestamp of the most recent PoS block. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_LAST_POS_TIMESTAMP flag is set.") DOC_END
KV_SERIALIZE(last_pow_timestamp) DOC_DSCR("The timestamp of the most recent PoW block. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_LAST_POW_TIMESTAMP flag is set.") DOC_END
KV_SERIALIZE(total_coins) DOC_DSCR("The total amount of all emitted coins in the system. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_END
KV_SERIALIZE(last_block_size) DOC_DSCR("The size of the last block in bytes. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_LAST_BLOCK_SIZE flag is set.") DOC_END
KV_SERIALIZE(tx_count_in_last_block) DOC_DSCR("The number of non-mining transactions in the last block. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_TX_COUNT_IN_LAST_BLOCK flag is set.") DOC_END
KV_SERIALIZE(pos_sequence_factor) DOC_DSCR("The current PoS sequence factor, representing the number of consecutive PoS blocks. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_POS_SEQUENCE_FACTOR flag is set.") DOC_END
KV_SERIALIZE(pow_sequence_factor) DOC_DSCR("The current PoW sequence factor, representing the number of consecutive PoW blocks. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_POW_SEQUENCE_FACTOR flag is set.") DOC_END
KV_SERIALIZE(block_reward) DOC_DSCR("The base block reward that is effective for the next block. Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_END
KV_SERIALIZE(last_block_total_reward) DOC_DSCR("Reward for the last block, including base reward and transaction fees. Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_END
KV_SERIALIZE(pos_diff_total_coins_rate) DOC_DSCR("PoS difficulty divided by the total amount of all coins in the system minus a premined amount (17,517,203). Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_END
KV_SERIALIZE(last_block_timestamp) DOC_DSCR("Timestamp of the last block. Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_END
KV_SERIALIZE(last_block_hash) DOC_DSCR("Hash of the last block. Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_END
KV_SERIALIZE(pos_block_ts_shift_vs_actual) DOC_DSCR("The difference between the timestamp used in the last PoS block for mining purposes and its actual timestamp as stored in the miner's transaction extra data. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_POS_BLOCK_TS_SHIFT_VS_ACTUAL flag is set.") DOC_END
KV_SERIALIZE(outs_stat) DOC_DSCR("Statistics for the number of outputs that have a specific amount. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_OUTS_STAT flag is set.") DOC_END
KV_SERIALIZE(performance_data) DOC_DSCR("Detailed technical performance data intended for developers. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE flag is set.") DOC_END
KV_SERIALIZE(tx_pool_performance_data) DOC_DSCR("Detailed technical performance data intended for developers. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE flag is set.") DOC_END
KV_SERIALIZE(offers_count) DOC_DSCR("Current number of offers in the offers service. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE flag is set.") DOC_END
KV_SERIALIZE(expiration_median_timestamp)DOC_DSCR("Median of timestamps of the last N blocks, used to determine the expiration status of transactions. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_EXPIRATIONS_MEDIAN flag is set.") DOC_END
KV_SERIALIZE(net_time_delta_median) DOC_DSCR("A value of 0 indicates no time synchronization issues, while a value of 1 indicates the presence of time sync issues. Only available if the COMMAND_RPC_GET_INFO_FLAG_NET_TIME_DELTA_MEDIAN flag is set.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(current_network_hashrate_50)DOC_DSCR("The PoW hash rate calculated over the last 50 blocks of any type. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_CURRENT_NETWORK_HASHRATE_50 flag is set.") DOC_EXMP(109575236643) DOC_END
KV_SERIALIZE(current_network_hashrate_350) DOC_DSCR("The PoW hash rate calculated over the last 350 blocks of any type. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_CURRENT_NETWORK_HASHRATE_350 flag is set.") DOC_EXMP(107939216153) DOC_END
KV_SERIALIZE(seconds_for_10_blocks) DOC_DSCR("The time period in seconds between the most recent block and the 10th block older. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_SECONDS_FOR_10_BLOCKS flag is set.") DOC_EXMP(476) DOC_END
KV_SERIALIZE(seconds_for_30_blocks) DOC_DSCR("The time period in seconds between the most recent block and the 30th block older. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_SECONDS_FOR_30_BLOCKS flag is set.") DOC_EXMP(1264) DOC_END
KV_SERIALIZE(transactions_cnt_per_day) DOC_DSCR("The number of non-mining transactions recorded over the last 24 hours. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_TRANSACTIONS_DAILY_STAT flag is set.") DOC_EXMP(1325) DOC_END
KV_SERIALIZE(transactions_volume_per_day)DOC_DSCR("The total sum of input amounts from all non-mining transactions over the last 24 hours. Only old bare inputs with explicit amounts are considered. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_TRANSACTIONS_DAILY_STAT flag is set.") DOC_EXMP(6615220203700000) DOC_END
KV_SERIALIZE(last_pos_timestamp) DOC_DSCR("The timestamp of the most recent PoS block. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_LAST_POS_TIMESTAMP flag is set.") DOC_EXMP(1719585105) DOC_END
KV_SERIALIZE(last_pow_timestamp) DOC_DSCR("The timestamp of the most recent PoW block. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_LAST_POW_TIMESTAMP flag is set.") DOC_EXMP(1719586493) DOC_END
KV_SERIALIZE(total_coins) DOC_DSCR("The total amount of all emitted coins in the system. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_EXMP("14308874719144585856") DOC_END
KV_SERIALIZE(last_block_size) DOC_DSCR("The size of the last block in bytes. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_LAST_BLOCK_SIZE flag is set.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(tx_count_in_last_block) DOC_DSCR("The number of non-mining transactions in the last block. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_TX_COUNT_IN_LAST_BLOCK flag is set.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(pos_sequence_factor) DOC_DSCR("The current PoS sequence factor, representing the number of consecutive PoS blocks. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_POS_SEQUENCE_FACTOR flag is set.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(pow_sequence_factor) DOC_DSCR("The current PoW sequence factor, representing the number of consecutive PoW blocks. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_POW_SEQUENCE_FACTOR flag is set.") DOC_EXMP(1) DOC_END
KV_SERIALIZE(block_reward) DOC_DSCR("The base block reward that is effective for the next block. Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_EXMP(1000000000000) DOC_END
KV_SERIALIZE(last_block_total_reward) DOC_DSCR("Reward for the last block, including base reward and transaction fees. Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(pos_diff_total_coins_rate) DOC_DSCR("PoS difficulty divided by the total amount of all coins in the system minus a premined amount (17,517,203). Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(last_block_timestamp) DOC_DSCR("Timestamp of the last block. Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_EXMP(1719586493) DOC_END
KV_SERIALIZE(last_block_hash) DOC_DSCR("Hash of the last block. Calculated only if either COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY or COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS flag is set.") DOC_EXMP("153af86fd0d7d0a427526258e30505a4d21b8f77261f5276c7669e0a6c83efa0") DOC_END
KV_SERIALIZE(pos_block_ts_shift_vs_actual) DOC_DSCR("The difference between the timestamp used in the last PoS block for mining purposes and its actual timestamp as stored in the miner's transaction extra data. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_POS_BLOCK_TS_SHIFT_VS_ACTUAL flag is set.") DOC_EXMP(-1387) DOC_END
KV_SERIALIZE(outs_stat) DOC_DSCR("Statistics for the number of outputs that have a specific amount. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_OUTS_STAT flag is set.") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(performance_data) DOC_DSCR("Detailed technical performance data intended for developers. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE flag is set.") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(tx_pool_performance_data) DOC_DSCR("Detailed technical performance data intended for developers. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE flag is set.") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(offers_count) DOC_DSCR("Current number of offers in the offers service. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_PERFORMANCE flag is set.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(expiration_median_timestamp)DOC_DSCR("Median of timestamps of the last N blocks, used to determine the expiration status of transactions. This information is only provided if the COMMAND_RPC_GET_INFO_FLAG_EXPIRATIONS_MEDIAN flag is set.") DOC_EXMP(1719585827) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1011,7 +1011,7 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(count) DOC_DSCR("The total number of blocks in the blockchain, equivalent to the top block's height plus one.") DOC_END
KV_SERIALIZE(count) DOC_DSCR("The total number of blocks in the blockchain, equivalent to the top block's height plus one.") DOC_EXMP(2697388) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1044,12 +1044,12 @@ namespace currency
bool pos_block; // is pos block
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_BLOB_AS_HEX_STRING(explicit_transaction) DOC_DSCR("A transaction blob that must be explicitly included in the block.") DOC_END
KV_SERIALIZE(extra_text) DOC_DSCR("Arbitrary data added to the extra field of the miner transaction.") DOC_END
KV_SERIALIZE(wallet_address) DOC_DSCR("Address where mining rewards will be deposited.") DOC_END
KV_SERIALIZE_BLOB_AS_HEX_STRING(explicit_transaction) DOC_DSCR("A transaction blob that must be explicitly included in the block.") DOC_EXMP("5fa8eaaf231a305053260ff91d69c6ef1ecbd0f5") DOC_END
KV_SERIALIZE(extra_text) DOC_DSCR("Arbitrary data added to the extra field of the miner transaction.") DOC_EXMP("OMG, you can't just ask people why they're PoW-maxi") DOC_END
KV_SERIALIZE(wallet_address) DOC_DSCR("Address where mining rewards will be deposited.") DOC_EXMP("ZxCSpsGGeJsS8fwvQ4HktDU3qBeauoJTR6j73jAWWZxFXdF7XTbGm4YfS2kXJmAP4Rf5BVsSQ9iZ45XANXEYsrLN2L2W77dH7") DOC_END
KV_SERIALIZE(stakeholder_address) DOC_DSCR("Address where the stake is returned for PoS blocks (usually the same as 'wallet_address').") DOC_END
KV_SERIALIZE(pe) DOC_DSCR("PoS entry details, relevant only for PoS block generation.") DOC_END
KV_SERIALIZE(pos_block) DOC_DSCR("Flag indicating whether the block is a PoS block.") DOC_END
KV_SERIALIZE(pos_block) DOC_DSCR("Flag indicating whether the block is a PoS block.") DOC_EXMP(false) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1067,15 +1067,15 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(difficulty) DOC_DSCR("The mining difficulty targeted by the block template.") DOC_END
KV_SERIALIZE(height) DOC_DSCR("The height of the block template in the blockchain.") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(seed) DOC_DSCR("Seed value for the ProgPoWZ mining algorithm's epoch.") DOC_END
KV_SERIALIZE(blocktemplate_blob) DOC_DSCR("Serialized block template blob.") DOC_END
KV_SERIALIZE(prev_hash) DOC_DSCR("Hash of the previous block in the chain.") DOC_END
KV_SERIALIZE(miner_tx_tgc) DOC_DSCR("Miner transaction generation context. Intended for PoS blocks and Zarcanum.") DOC_END
KV_SERIALIZE(block_reward_without_fee) DOC_DSCR("Base block reward excluding any transaction fees.") DOC_END
KV_SERIALIZE(block_reward) DOC_DSCR("Total block reward, including transaction fees if they are given to the miner (legacy), or the base reward if fees are burnt (current state).") DOC_END
KV_SERIALIZE(txs_fee) DOC_DSCR("Total fees from transactions included in the block.") DOC_END
KV_SERIALIZE(difficulty) DOC_DSCR("The mining difficulty targeted by the block template.") DOC_EXMP("12936195379842") DOC_END
KV_SERIALIZE(height) DOC_DSCR("The height of the block template in the blockchain.") DOC_EXMP(2555002) DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(seed) DOC_DSCR("Seed value for the ProgPoWZ mining algorithm's epoch.") DOC_EXMP("0518e1373ff88ccabb28493cac10cb0731313135d880dae0d846be6016ab9acf") DOC_END
KV_SERIALIZE(blocktemplate_blob) DOC_DSCR("Serialized block template blob.") DOC_EXMP("030000000000000000ae73338b792......6258a2b5ee340700") DOC_END
KV_SERIALIZE(prev_hash) DOC_DSCR("Hash of the previous block in the chain.") DOC_EXMP("ae73338b7927df71b6ed477937625c230172219306750ba97995fb5109dda703") DOC_END
KV_SERIALIZE(miner_tx_tgc) DOC_DSCR("Miner transaction generation context. Intended for PoS blocks and Zarcanum.") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(block_reward_without_fee) DOC_DSCR("Base block reward excluding any transaction fees.") DOC_EXMP(1000000000000) DOC_END
KV_SERIALIZE(block_reward) DOC_DSCR("Total block reward, including transaction fees if they are given to the miner (legacy), or the base reward if fees are burnt (current state).") DOC_EXMP(1000000000000) DOC_END
KV_SERIALIZE(txs_fee) DOC_DSCR("Total fees from transactions included in the block.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1111,8 +1111,8 @@ namespace currency
std::list<epee::hexemizer> explicit_txs; //hex encoded tx blobs
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_BLOB_AS_HEX_STRING(b) DOC_DSCR("Hex-encoded serialized block.") DOC_END
KV_SERIALIZE(explicit_txs) DOC_DSCR("List of hex-encoded transactions to be explicitly included in the block.") DOC_END
KV_SERIALIZE_BLOB_AS_HEX_STRING(b) DOC_DSCR("Hex-encoded serialized block.") DOC_EXMP("030000000000000000ae73338b7926258a2b5ee340700") DOC_END
KV_SERIALIZE(explicit_txs) DOC_DSCR("List of hex-encoded transactions to be explicitly included in the block.") DOC_EXMP_AGGR({"6258a2b5ee7a9c20"}, {"8e0f0a2cee340700"}) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1143,17 +1143,17 @@ namespace currency
uint64_t reward;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(major_version) DOC_DSCR("Major version of the block.") DOC_END
KV_SERIALIZE(minor_version) DOC_DSCR("Minor version of the block.") DOC_END
KV_SERIALIZE(timestamp) DOC_DSCR("Timestamp of the block creation.") DOC_END
KV_SERIALIZE(prev_hash) DOC_DSCR("Hash of the previous block in the chain.") DOC_END
KV_SERIALIZE(nonce) DOC_DSCR("Nonce used for generating the block to meet the network difficulty.") DOC_END
KV_SERIALIZE(orphan_status) DOC_DSCR("Indicates if the block is an orphan (true) or a normal block (false).") DOC_END
KV_SERIALIZE(height) DOC_DSCR("Height of the block in the blockchain.") DOC_END
KV_SERIALIZE(depth) DOC_DSCR("Depth of the block in the blockchain. Depth 0 indicates the most recent block.") DOC_END
KV_SERIALIZE(hash) DOC_DSCR("Hash of the block.") DOC_END
KV_SERIALIZE(difficulty) DOC_DSCR("Network difficulty target that the block met.") DOC_END
KV_SERIALIZE(reward) DOC_DSCR("Total mining reward of the block including transaction fees (if applicable).") DOC_END
KV_SERIALIZE(major_version) DOC_DSCR("Major version of the block.") DOC_EXMP(3) DOC_END
KV_SERIALIZE(minor_version) DOC_DSCR("Minor version of the block.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(timestamp) DOC_DSCR("Timestamp of the block creation.") DOC_EXMP(1719588270) DOC_END
KV_SERIALIZE(prev_hash) DOC_DSCR("Hash of the previous block in the chain.") DOC_EXMP("a1b4359c02985720b0cf542678e08f0d4075e518fbd0cd54bd280269545e0e6f") DOC_END
KV_SERIALIZE(nonce) DOC_DSCR("Nonce used for generating the block to meet the network difficulty.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(orphan_status) DOC_DSCR("Indicates if the block is an orphan (true) or a normal block (false).") DOC_EXMP(false) DOC_END
KV_SERIALIZE(height) DOC_DSCR("Height of the block in the blockchain.") DOC_EXMP(2697404) DOC_END
KV_SERIALIZE(depth) DOC_DSCR("Depth of the block in the blockchain. Depth 0 indicates the most recent block.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(hash) DOC_DSCR("Hash of the block.") DOC_EXMP("f5df39c4b1590394976aa6e72f04df7836e22dbdfc1e6f61f6cc1b624d83cd94") DOC_END
KV_SERIALIZE(difficulty) DOC_DSCR("Network difficulty target that the block met.") DOC_EXMP("1849593878843995770114") DOC_END
KV_SERIALIZE(reward) DOC_DSCR("Total mining reward of the block including transaction fees (if applicable).") DOC_EXMP(0) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1168,7 +1168,7 @@ namespace currency
block_header_response block_header;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(block_header) DOC_DSCR("Detailed header information of the block.") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1186,7 +1186,7 @@ namespace currency
std::string hash;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(hash) DOC_DSCR("The hash of the block for which the header information is being requested.") DOC_END
KV_SERIALIZE(hash) DOC_DSCR("The hash of the block for which the header information is being requested.") DOC_EXMP("a1b4359c02985720b0cf542678e08f0d4075e518fbd0cd54bd280269545e0e6f") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1196,7 +1196,7 @@ namespace currency
block_header_response block_header;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header) DOC_DSCR("Detailed header information of the block.") DOC_END
KV_SERIALIZE(block_header) DOC_DSCR("Detailed header information of the block.") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1213,7 +1213,7 @@ namespace currency
uint64_t height;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height) DOC_DSCR("The height of the block for which the header information is being requested.") DOC_END
KV_SERIALIZE(height) DOC_DSCR("The height of the block for which the header information is being requested.") DOC_EXMP(2555000) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1223,7 +1223,7 @@ namespace currency
block_header_response block_header;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header) DOC_DSCR("Detailed header information of the block.") DOC_END
KV_SERIALIZE(block_header) DOC_DSCR("Detailed header information of the block.") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1239,7 +1239,7 @@ namespace currency
{
std::string alias;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(alias) DOC_DSCR("The alias name for which details are being requested.") DOC_END
KV_SERIALIZE(alias) DOC_DSCR("The alias name for which details are being requested.") DOC_EXMP("gigabyted") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1249,7 +1249,7 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(alias_details) DOC_DSCR("Contains the detailed information about the specified alias, including the associated wallet address, tracking key, comment etc..") DOC_END
KV_SERIALIZE(alias_details) DOC_DSCR("Contains the detailed information about the specified alias, including the associated wallet address, tracking key, comment etc..") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1265,7 +1265,7 @@ namespace currency
{
std::string alias;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(alias) DOC_DSCR("The alias name for which the registration cost is being queried.") DOC_END
KV_SERIALIZE(alias) DOC_DSCR("The alias name for which the registration cost is being queried.") DOC_EXMP("zxdya6q6whzwqjkmtcsjpc3ku") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1275,7 +1275,7 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(reward) DOC_DSCR("The registration cost for the specified alias.") DOC_END
KV_SERIALIZE(reward) DOC_DSCR("The registration cost for the specified alias.") DOC_EXMP(100000000000) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1299,7 +1299,7 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(aliases) DOC_DSCR("List of alias_rpc_details objects, each containing information about an individual alias.") DOC_END
KV_SERIALIZE(aliases) DOC_DSCR("List of alias_rpc_details objects, each containing information about an individual alias.") DOC_EXMP_AUTO(2) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1317,8 +1317,8 @@ namespace currency
uint64_t count; // The number of aliases to retrieve.
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(offset) DOC_DSCR("The offset in the list of all aliases from which to start retrieving.") DOC_END
KV_SERIALIZE(count) DOC_DSCR("The number of aliases to retrieve from the specified offset.") DOC_END
KV_SERIALIZE(offset) DOC_DSCR("The offset in the list of all aliases from which to start retrieving.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(count) DOC_DSCR("The number of aliases to retrieve from the specified offset.") DOC_EXMP(2) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1328,7 +1328,7 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(aliases) DOC_DSCR("List of alias_rpc_details objects, each containing information about an individual alias retrieved based on the request parameters.") DOC_END
KV_SERIALIZE(aliases) DOC_DSCR("List of alias_rpc_details objects, each containing information about an individual alias retrieved based on the request parameters.") DOC_EXMP_AUTO(2) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1348,7 +1348,7 @@ namespace currency
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(alias_info_list) DOC_DSCR("List of alias_rpc_details objects, each containing detailed information about each alias registered to the specified address.") DOC_END
KV_SERIALIZE(alias_info_list) DOC_DSCR("List of alias_rpc_details objects, each containing detailed information about each alias registered to the specified address.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1387,7 +1387,7 @@ namespace currency
std::list<std::string> tx_to_remove;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_to_remove) DOC_DSCR("List of transaction IDs that are to be removed from the transaction pool.") DOC_END
KV_SERIALIZE(tx_to_remove) DOC_DSCR("List of transaction IDs that are to be removed from the transaction pool.") DOC_EXMP_AGGR("c5efacd06128fc5a73f58392c84534cd1a146de7d47ffbe770486cce5130dc1f","c2f0de2ef4753dc0ec8dd2da5ebf8e77f07d2ac0791357a9e3f2537071b33762") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1445,11 +1445,11 @@ namespace currency
bool is_spent;
uint64_t global_index;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount) DOC_DSCR("The output's amount, 0 for ZC outputs.") DOC_END
KV_SERIALIZE(pub_keys) DOC_DSCR("List of public keys associated with the output.") DOC_END
KV_SERIALIZE(minimum_sigs) DOC_DSCR("Minimum number of signatures required to spend the output, for multisig outputs only.") DOC_END
KV_SERIALIZE(is_spent) DOC_DSCR("Indicates whether the output has been spent.") DOC_END
KV_SERIALIZE(global_index) DOC_DSCR("Global index of the output for this specific amount.") DOC_END
KV_SERIALIZE(amount) DOC_DSCR("The output's amount, 0 for ZC outputs.") DOC_EXMP(9000000000) DOC_END
KV_SERIALIZE(pub_keys) DOC_DSCR("List of public keys associated with the output.") DOC_EXMP_AGGR("7d0c755e7e24a241847176c9a3cf4c970bcd6377018068abe6fe4535b23f5323") DOC_END
KV_SERIALIZE(minimum_sigs) DOC_DSCR("Minimum number of signatures required to spend the output, for multisig outputs only.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(is_spent) DOC_DSCR("Indicates whether the output has been spent.") DOC_EXMP(false) DOC_END
KV_SERIALIZE(global_index) DOC_DSCR("Global index of the output for this specific amount.") DOC_EXMP(0) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1462,11 +1462,11 @@ namespace currency
std::vector<uint64_t> global_indexes;
std::vector<std::string> etc_options;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount) DOC_DSCR("The amount of coins being transacted.") DOC_END
KV_SERIALIZE(amount) DOC_DSCR("The amount of coins being transacted.") DOC_EXMP(1000000000000) DOC_END
KV_SERIALIZE(htlc_origin) DOC_DSCR("Origin hash for HTLC (Hash Time Locked Contract).") DOC_END
KV_SERIALIZE(kimage_or_ms_id) DOC_DSCR("Contains either the key image for the input or the multisig output ID, depending on the input type.") DOC_END
KV_SERIALIZE(global_indexes) DOC_DSCR("List of global indexes indicating the outputs referenced by this input, where only one is actually being spent.") DOC_END
KV_SERIALIZE(multisig_count) DOC_DSCR("Number of multisig signatures used, relevant only for multisig outputs.") DOC_END
KV_SERIALIZE(kimage_or_ms_id) DOC_DSCR("Contains either the key image for the input or the multisig output ID, depending on the input type.") DOC_EXMP("2540e0544b1fed3b104976f803dbd83681335c427f9d601d9d5aecf86ef276d2") DOC_END
KV_SERIALIZE(global_indexes) DOC_DSCR("List of global indexes indicating the outputs referenced by this input, where only one is actually being spent.") DOC_EXMP_AGGR(0,2,12,27) DOC_END
KV_SERIALIZE(multisig_count) DOC_DSCR("Number of multisig signatures used, relevant only for multisig outputs.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(etc_options) DOC_DSCR("Auxiliary options associated with the input, containing additional configuration or data.") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1477,9 +1477,9 @@ namespace currency
std::string short_view;
std::string details_view;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(type) DOC_DSCR("Type of the extra entry in the transaction.") DOC_END
KV_SERIALIZE(short_view) DOC_DSCR("A concise representation of the extra entry.") DOC_END
KV_SERIALIZE(details_view) DOC_DSCR("A detailed representation of the extra entry.") DOC_END
KV_SERIALIZE(type) DOC_DSCR("Type of the extra entry in the transaction.") DOC_EXMP("pub_key") DOC_END
KV_SERIALIZE(short_view) DOC_DSCR("A concise representation of the extra entry.") DOC_EXMP("0feef5e2ea0e88b592c0a0e6639ce73e12ea9b3136d89464748fcb60bb6f18f5") DOC_END
KV_SERIALIZE(details_view) DOC_DSCR("A detailed representation of the extra entry.") DOC_EXMP("") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1501,19 +1501,19 @@ namespace currency
std::string object_in_json;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_BLOB_AS_BASE64_STRING(blob) DOC_DSCR("Serialized form of the transaction, encoded in Base64.") DOC_END
KV_SERIALIZE(blob_size) DOC_DSCR("Size of the serialized transaction in bytes.") DOC_END
KV_SERIALIZE(timestamp) DOC_DSCR("Timestamp when the transaction was created.") DOC_END
KV_SERIALIZE(keeper_block) DOC_DSCR("Block height where the transaction is confirmed, or -1 if it is unconfirmed.") DOC_END
KV_SERIALIZE(fee) DOC_DSCR("Transaction fee in the smallest currency unit.") DOC_END
KV_SERIALIZE(amount) DOC_DSCR("Total output amount of the transaction (legacy, for pre-Zarcanum txs).") DOC_END
KV_SERIALIZE(id) DOC_DSCR("Hash of the transaction.") DOC_END
KV_SERIALIZE(pub_key) DOC_DSCR("Public key associated with the transaction.") DOC_END
KV_SERIALIZE(outs) DOC_DSCR("Outputs of the transaction.") DOC_END
KV_SERIALIZE(ins) DOC_DSCR("Inputs of the transaction.") DOC_END
KV_SERIALIZE(extra) DOC_DSCR("Extra data associated with the transaction.") DOC_END
KV_SERIALIZE(attachments) DOC_DSCR("Additional attachments to the transaction.") DOC_END
KV_SERIALIZE_BLOB_AS_BASE64_STRING(object_in_json) DOC_DSCR("Serialized transaction represented in JSON, encoded in Base64.") DOC_END
KV_SERIALIZE_BLOB_AS_BASE64_STRING(blob) DOC_DSCR("Serialized form of the transaction, encoded in Base64.") DOC_EXMP("ARMBgKCUpY0dBBoAAAAAAAAAABoCAAAAAAAAABoKAAAAAAAAABoPAAAAAAAAACVA4FRLH") DOC_END
KV_SERIALIZE(blob_size) DOC_DSCR("Size of the serialized transaction in bytes.") DOC_EXMP(6794) DOC_END
KV_SERIALIZE(timestamp) DOC_DSCR("Timestamp when the transaction was created.") DOC_EXMP(1557345925) DOC_END
KV_SERIALIZE(keeper_block) DOC_DSCR("Block height where the transaction is confirmed, or -1 if it is unconfirmed.") DOC_EXMP(51) DOC_END
KV_SERIALIZE(fee) DOC_DSCR("Transaction fee in the smallest currency unit.") DOC_EXMP(1000000000) DOC_END
KV_SERIALIZE(amount) DOC_DSCR("Total output amount of the transaction (legacy, for pre-Zarcanum txs).") DOC_EXMP(18999000000000) DOC_END
KV_SERIALIZE(id) DOC_DSCR("Hash of the transaction.") DOC_EXMP("a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8") DOC_END
KV_SERIALIZE(pub_key) DOC_DSCR("Public key associated with the transaction.") DOC_EXMP("0feef5e2ea0e88b592c0a0e6639ce73e12ea9b3136d89464748fcb60bb6f18f5") DOC_END
KV_SERIALIZE(outs) DOC_DSCR("Outputs of the transaction.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(ins) DOC_DSCR("Inputs of the transaction.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(extra) DOC_DSCR("Extra data associated with the transaction.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(attachments) DOC_DSCR("Additional attachments to the transaction.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE_BLOB_AS_BASE64_STRING(object_in_json) DOC_DSCR("Serialized transaction represented in JSON, encoded in Base64.") DOC_EXMP("ewogICJ2ZXJzaW9uIjogMSwgCiAgInZpbiI6IFsgewogICAgIC") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1525,10 +1525,10 @@ namespace currency
uint64_t sz;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id) DOC_DSCR("Hash of the transaction.") DOC_END
KV_SERIALIZE(fee) DOC_DSCR("Transaction fee in the smallest currency unit.") DOC_END
KV_SERIALIZE(total_amount) DOC_DSCR("Total amount transferred in the transaction (legacy, for pre-Zarcanum txs).") DOC_END
KV_SERIALIZE(sz) DOC_DSCR("Size of the transaction in bytes.") DOC_END
KV_SERIALIZE(id) DOC_DSCR("Hash of the transaction.") DOC_EXMP("a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8") DOC_END
KV_SERIALIZE(fee) DOC_DSCR("Transaction fee in the smallest currency unit.") DOC_EXMP(1000000000) DOC_END
KV_SERIALIZE(total_amount) DOC_DSCR("Total amount transferred in the transaction (legacy, for pre-Zarcanum txs).") DOC_EXMP(9000000000) DOC_END
KV_SERIALIZE(sz) DOC_DSCR("Size of the transaction in bytes.") DOC_EXMP(6142) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1561,30 +1561,30 @@ namespace currency
std::string object_in_json;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blob) DOC_DSCR("Serialized form of the block.") DOC_END
KV_SERIALIZE(height) DOC_DSCR("Height of the block in the blockchain.") DOC_END
KV_SERIALIZE(timestamp) DOC_DSCR("Timestamp when the block was created, in PoS blocks used for mining.") DOC_END
KV_SERIALIZE(actual_timestamp) DOC_DSCR("Actual timestamp encoded in the block's extra data for PoS blocks.") DOC_END
KV_SERIALIZE(block_cumulative_size) DOC_DSCR("Cumulative size of the block including all transactions.") DOC_END
KV_SERIALIZE(total_txs_size) DOC_DSCR("Total size of all transactions included in the block.") DOC_END
KV_SERIALIZE(blob) DOC_DSCR("Serialized form of the block.") DOC_EXMP("") DOC_END
KV_SERIALIZE(height) DOC_DSCR("Height of the block in the blockchain.") DOC_EXMP(51) DOC_END
KV_SERIALIZE(timestamp) DOC_DSCR("Timestamp when the block was created, in PoS blocks used for mining.") DOC_EXMP(1557345925) DOC_END
KV_SERIALIZE(actual_timestamp) DOC_DSCR("Actual timestamp encoded in the block's extra data for PoS blocks.") DOC_EXMP(1557345925) DOC_END
KV_SERIALIZE(block_cumulative_size) DOC_DSCR("Cumulative size of the block including all transactions.") DOC_EXMP(6794) DOC_END
KV_SERIALIZE(total_txs_size) DOC_DSCR("Total size of all transactions included in the block.") DOC_EXMP(6794) DOC_END
KV_SERIALIZE(block_tself_size) // TODO ?
KV_SERIALIZE(base_reward) DOC_DSCR("Base mining reward for the block.") DOC_END
KV_SERIALIZE(summary_reward) DOC_DSCR("Total reward for the block, including base reward and transaction fees (legacy).") DOC_END
KV_SERIALIZE(total_fee) DOC_DSCR("Total transaction fees included in the block.") DOC_END
KV_SERIALIZE(penalty) DOC_DSCR("Penalty applied to the reward if the block is larger than median but not large enough to be rejected.") DOC_END
KV_SERIALIZE(id) DOC_DSCR("Unique identifier of the block.") DOC_END
KV_SERIALIZE(prev_id) DOC_DSCR("Hash of the previous block in the chain.") DOC_END
KV_SERIALIZE(base_reward) DOC_DSCR("Base mining reward for the block.") DOC_EXMP(1000000000000) DOC_END
KV_SERIALIZE(summary_reward) DOC_DSCR("Total reward for the block, including base reward and transaction fees (legacy).") DOC_EXMP(1001000000000) DOC_END
KV_SERIALIZE(total_fee) DOC_DSCR("Total transaction fees included in the block.") DOC_EXMP(1000000000) DOC_END
KV_SERIALIZE(penalty) DOC_DSCR("Penalty applied to the reward if the block is larger than median but not large enough to be rejected.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(id) DOC_DSCR("Unique identifier of the block.") DOC_EXMP("af05b814c75e10872afc0345108e830884bc4c32091db783505abe3dac9929cf") DOC_END
KV_SERIALIZE(prev_id) DOC_DSCR("Hash of the previous block in the chain.") DOC_EXMP("37fe382c755bb8869e4f5255f2aed6a8fb503e195bb4180b65b8e1450b84cafe") DOC_END
KV_SERIALIZE(pow_seed) // TODO
KV_SERIALIZE(cumulative_diff_adjusted) DOC_DSCR("Adjusted cumulative difficulty of the blockchain up to this block.") DOC_END
KV_SERIALIZE(cumulative_diff_precise) DOC_DSCR("Precise cumulative difficulty of the blockchain up to this block.") DOC_END
KV_SERIALIZE(difficulty) DOC_DSCR("Mining difficulty of the block.") DOC_END
KV_SERIALIZE(already_generated_coins) DOC_DSCR("Total amount of coins generated in the blockchain up to this block.") DOC_END
KV_SERIALIZE(this_block_fee_median) DOC_DSCR("Median transaction fee of the transactions within this block.") DOC_END
KV_SERIALIZE(cumulative_diff_adjusted) DOC_DSCR("Adjusted cumulative difficulty of the blockchain up to this block.") DOC_EXMP("42413051198") DOC_END
KV_SERIALIZE(cumulative_diff_precise) DOC_DSCR("Precise cumulative difficulty of the blockchain up to this block.") DOC_EXMP("28881828324942") DOC_END
KV_SERIALIZE(difficulty) DOC_DSCR("Mining difficulty of the block.") DOC_EXMP("951296929031") DOC_END
KV_SERIALIZE(already_generated_coins) DOC_DSCR("Total amount of coins generated in the blockchain up to this block.") DOC_EXMP("17517253670000000000") DOC_END
KV_SERIALIZE(this_block_fee_median) DOC_DSCR("Median transaction fee of the transactions within this block.") DOC_EXMP(1000000000) DOC_END
KV_SERIALIZE(effective_fee_median) // TODO
KV_SERIALIZE(transactions_details) DOC_DSCR("Detailed information about each transaction included in the block.") DOC_END
KV_SERIALIZE(type) DOC_DSCR("Type of the block.") DOC_END
KV_SERIALIZE(is_orphan) DOC_DSCR("Indicates whether the block is an orphan.") DOC_END
KV_SERIALIZE(miner_text_info) DOC_DSCR("Additional textual information provided by the miner of the block.") DOC_END
KV_SERIALIZE(transactions_details) DOC_DSCR("Detailed information about each transaction included in the block.") DOC_EXMP_AUTO(1) DOC_END
KV_SERIALIZE(type) DOC_DSCR("Type of the block.") DOC_EXMP(1) DOC_END
KV_SERIALIZE(is_orphan) DOC_DSCR("Indicates whether the block is an orphan.") DOC_EXMP(false) DOC_END
KV_SERIALIZE(miner_text_info) DOC_DSCR("Additional textual information provided by the miner of the block.") DOC_EXMP("") DOC_END
KV_SERIALIZE(object_in_json) DOC_DSCR("Serialized representation of the block in JSON format.") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1603,8 +1603,8 @@ namespace currency
bool ignore_transactions;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height_start) DOC_DSCR("The starting block height from which block details are retrieved.") DOC_END
KV_SERIALIZE(count) DOC_DSCR("The number of blocks to retrieve from the starting height.") DOC_END
KV_SERIALIZE(height_start) DOC_DSCR("The starting block height from which block details are retrieved.") DOC_EXMP(51) DOC_END
KV_SERIALIZE(count) DOC_DSCR("The number of blocks to retrieve from the starting height.") DOC_EXMP(1) DOC_END
KV_SERIALIZE(ignore_transactions) // TODO
END_KV_SERIALIZE_MAP()
};
@ -1616,7 +1616,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(blocks) DOC_DSCR("List of blocks with detailed information, starting from the specified height.") DOC_END
KV_SERIALIZE(blocks) DOC_DSCR("List of blocks with detailed information, starting from the specified height.") DOC_EXMP_AUTO(1) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1633,8 +1633,8 @@ namespace currency
uint64_t count;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(offset) DOC_DSCR("The offset in the list of alternative blocks from which to start retrieval.") DOC_END
KV_SERIALIZE(count) DOC_DSCR("The number of alternative blocks to retrieve from the specified offset.") DOC_END
KV_SERIALIZE(offset) DOC_DSCR("The offset in the list of alternative blocks from which to start retrieval.") DOC_EXMP(0) DOC_END
KV_SERIALIZE(count) DOC_DSCR("The number of alternative blocks to retrieve from the specified offset.") DOC_EXMP(1) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1645,7 +1645,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(blocks) DOC_DSCR("List of alternative blocks with detailed information, retrieved based on the specified parameters.") DOC_END
KV_SERIALIZE(blocks) DOC_DSCR("List of alternative blocks with detailed information, retrieved based on the specified parameters.") DOC_EXMP_AUTO(1) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1661,7 +1661,7 @@ namespace currency
crypto::hash id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(id) DOC_DSCR("The hash ID of the block for which detailed information is being requested.") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(id) DOC_DSCR("The hash ID of the block for which detailed information is being requested.") DOC_EXMP("4cf2c7c7e16d1a2a0771cd552c696dd94e7db4e1031982ed88eff99d5006ee4a") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1688,7 +1688,7 @@ namespace currency
std::list<std::string> ids;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(ids) DOC_DSCR("List of transaction IDs.") DOC_END
KV_SERIALIZE(ids) DOC_DSCR("List of transaction IDs.") DOC_EXMP_AGGR("bd9a89f95c9115d29540c6778dab9d9798eb251143dcd4b8960fcd9730a1471c","1c938f04c935d976310c4338fc570ea20777951471609f3edecb341ea4932b0a") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1699,7 +1699,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(txs) DOC_DSCR("List of transactions with detailed information.") DOC_END
KV_SERIALIZE(txs) DOC_DSCR("List of transactions with detailed information.") DOC_EXMP_AUTO(1) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1715,7 +1715,7 @@ namespace currency
std::list<std::string> ids;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(ids) DOC_DSCR("List of transaction IDs.") DOC_END
KV_SERIALIZE(ids) DOC_DSCR("List of transaction IDs.") DOC_EXMP_AGGR("bd9a89f95c9115d29540c6778dab9d9798eb251143dcd4b8960fcd9730a1471c","1c938f04c935d976310c4338fc570ea20777951471609f3edecb341ea4932b0a") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1726,7 +1726,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(txs) DOC_DSCR("List of transactions with detailed information.") DOC_END
KV_SERIALIZE(txs) DOC_DSCR("List of transactions with detailed information.") DOC_EXMP_AUTO(1) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1750,7 +1750,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(ids) DOC_DSCR("List of all transaction IDs currently in the transaction pool.") DOC_END
KV_SERIALIZE(ids) DOC_DSCR("List of all transaction IDs currently in the transaction pool.") DOC_EXMP_AUTO(1) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1796,7 +1796,7 @@ namespace currency
std::string tx_hash;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash) DOC_DSCR("The hash of the transaction for which detailed information is being requested.") DOC_END
KV_SERIALIZE(tx_hash) DOC_DSCR("The hash of the transaction for which detailed information is being requested.") DOC_EXMP("d46c415c3aa3f3e17bd0bf85ffb813cacf4d9595d2d5392f42dacbaffcffdc70") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1807,7 +1807,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(tx_info) DOC_DSCR("Detailed information about the transaction.") DOC_END
KV_SERIALIZE(tx_info) DOC_DSCR("Detailed information about the transaction.") DOC_EXMP_AUTO() DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1828,7 +1828,7 @@ namespace currency
std::string id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id) DOC_DSCR("The identifier used to search across various types of entities.") DOC_END
KV_SERIALIZE(id) DOC_DSCR("The identifier used to search across various types of entities.") DOC_EXMP("729811f9340537e8d5641949e6cc58261f91f109687a706f39bae9514757e819") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -1839,7 +1839,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(types_found) DOC_DSCR("List of entity types where the identifier was found.") DOC_END
KV_SERIALIZE(types_found) DOC_DSCR("List of entity types where the identifier was found.") DOC_EXMP_AGGR("key_image") DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1891,7 +1891,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
KV_SERIALIZE(expiration_median) DOC_DSCR("The median timestamp from the last N blocks, used to determine if transactions are expired based on their timestamp.") DOC_END
KV_SERIALIZE(expiration_median) DOC_DSCR("The median timestamp from the last N blocks, used to determine if transactions are expired based on their timestamp.") DOC_EXMP(1719591540) DOC_END
END_KV_SERIALIZE_MAP()
};
};
@ -1910,10 +1910,10 @@ namespace currency
std::string alias;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(buff) DOC_DSCR("Base64 encoded data for which the signature is to be validated.") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(sig) DOC_DSCR("Schnorr signature to validate, encoded as a hexadecimal string.") DOC_END
KV_SERIALIZE(buff) DOC_DSCR("Base64 encoded data for which the signature is to be validated.") DOC_EXMP("SSBkaWRuJ3QgZXhwZWN0IGFueW9uZSB0byBkZWNyeXB0IHRoaXMgZGF0YSwgc2luY2UgaXQncyBqdXN0IGFuIGV4YW1wbGUuIEJ1dCB5b3UgZGVjcnlwdGVkIGl0ISBJJ20gYW1hemVkLg==") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(sig) DOC_DSCR("Schnorr signature to validate, encoded as a hexadecimal string.") DOC_EXMP("5c202d4bf82c2dd3c6354e2f02826ca72c797950dbe8db5bc5e3b2e60290a407ac2ef85bfc905ace8fe3b3819217084c00faf7237fee3ad2f6a7f662636cd20f") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(pkey) DOC_DSCR("Public key used for signature verification, encoded as a hexadecimal string. If null or not set, the public key is retrieved using the provided alias.") DOC_END
KV_SERIALIZE(alias) DOC_DSCR("Alias to retrieve the associated public spend key if no explicit public key is provided for verification.") DOC_END
KV_SERIALIZE(alias) DOC_DSCR("Alias to retrieve the associated public spend key if no explicit public key is provided for verification.") DOC_EXMP("sowle") DOC_END
END_KV_SERIALIZE_MAP()
};

View file

@ -290,7 +290,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, ph::_1), "start_mining <threads_count> - Start mining in daemon");
m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, ph::_1), "Stop mining in daemon");
m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, ph::_1), "Resynchronize transactions and balance");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "[force_all] Show current wallet balance, with 'force_all' param it displays all assets without filtering against whitelists");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "[raw] Show current wallet balance, with 'raw' param it displays all assets without filtering against whitelists");
m_cmd_binder.set_handler("show_staking_history", boost::bind(&simple_wallet::show_staking_history, this, ph::_1), "show_staking_history [2] - Show staking transfers, if option provided - number of days for history to display");
m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, ph::_1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability");
m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, ph::_1), "incoming_transfers counts");
@ -339,6 +339,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("emit_asset", boost::bind(&simple_wallet::emit_asset, this, ph::_1), "emit_asset <asset_id> <amount> - Emmit more coins for the asset, possible only if current wallet is a maintainer for the asset");
m_cmd_binder.set_handler("burn_asset", boost::bind(&simple_wallet::burn_asset, this, ph::_1), "burn_asset <asset_id> <amount> - Burn coins for the asset, possible only if current wallet is a maintainer for the asset AND possess given amount of coins to burn");
m_cmd_binder.set_handler("update_asset", boost::bind(&simple_wallet::update_asset, this, ph::_1), "update_asset <asset_id> <path_to_metadata_file> - Update asset descriptor's metadata, possible only if current wallet is a maintainer for the asset");
m_cmd_binder.set_handler("transfer_asset_ownership", boost::bind(&simple_wallet::transfer_asset_ownership, this, ph::_1), "transfer_asset_ownership <asset_id> <new_owner_public_key> - Update asset descriptor's owner field, so the asset ownership is transfered to new owner");
m_cmd_binder.set_handler("add_custom_asset_id", boost::bind(&simple_wallet::add_custom_asset_id, this, ph::_1), "Approve asset id to be recognized in the wallet and returned in balances");
m_cmd_binder.set_handler("remove_custom_asset_id", boost::bind(&simple_wallet::remove_custom_asset_id, this, ph::_1), "Cancel previously made approval for asset id");
@ -347,6 +348,9 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("get_ionic_swap_proposal_info", boost::bind(&simple_wallet::get_ionic_swap_proposal_info, this, ph::_1), "get_ionic_swap_proposal_info <hex_encoded_raw_proposal.txt> - Extracts and display information from ionic_swap proposal raw data");
m_cmd_binder.set_handler("accept_ionic_swap_proposal", boost::bind(&simple_wallet::accept_ionic_swap_proposal, this, ph::_1), "accept_ionic_swap_proposal <hex_encoded_raw_proposal.txt> - Accept ionic_swap proposal and generates exchange transaction");
m_cmd_binder.set_handler("call_rpc", boost::bind(&simple_wallet::call_rpc, this, ph::_1), "call_rpc <json_rpc_method> <request_body_optional> - Invokes rpc request to the wallet");
}
//----------------------------------------------------------------------------------------------------
simple_wallet::~simple_wallet()
@ -812,38 +816,45 @@ void simple_wallet::on_new_block(uint64_t height, const currency::block& block)
//----------------------------------------------------------------------------------------------------
std::string print_money_trailing_zeros_replaced_with_spaces(uint64_t amount, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT)
{
std::string s = print_money(amount);
std::string s = print_money(amount, decimal_point);
size_t p = s.find_last_not_of('0');
if (p != std::string::npos)
{
if (s[p] == '.')
++p;
size_t l = s.length() - p - 1;
return s.replace(p + 1, l, l, ' ');
s.replace(p + 1, l, l, ' ');
if (decimal_point < CURRENCY_DISPLAY_DECIMAL_POINT)
s += std::string(CURRENCY_DISPLAY_DECIMAL_POINT - decimal_point, ' ');
}
return s;
}
//----------------------------------------------------------------------------------------------------
std::string simple_wallet::get_tocken_info_string(const crypto::public_key& asset_id, uint64_t& decimal_points)
std::string simple_wallet::get_token_info_string(const crypto::public_key& asset_id, uint64_t& decimal_points)
{
std::string token_info = "ZANO";
decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT;
if (asset_id != currency::native_coin_asset_id)
{
currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb);
bool whitelisted = false;
if (!m_wallet->get_asset_id_info(asset_id, adb, whitelisted))
uint32_t asset_info_flags{};
if (!m_wallet->get_asset_info(asset_id, adb, asset_info_flags))
{
token_info = "!UNKNOWN!";
}
else {
else
{
decimal_points = adb.decimal_point;
token_info = adb.ticker;
if (whitelisted)
if (asset_info_flags & tools::wallet2::aif_whitelisted)
{
token_info += "[*]";
}
else if (asset_info_flags & tools::wallet2::aif_own)
{
token_info += "[$]";
}
else
{
token_info += std::string("[") + epee::string_tools::pod_to_hex(asset_id) + "]";
@ -860,7 +871,7 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf
{
epee::log_space::console_colors color = !wti.has_outgoing_entries() ? epee::log_space::console_color_green : epee::log_space::console_color_magenta;
uint64_t decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT;
std::string token_info = get_tocken_info_string(wti.subtransfers[0].asset_id, decimal_points);
std::string token_info = get_token_info_string(wti.subtransfers[0].asset_id, decimal_points);
message_writer(color, false) <<
"height " << wti.height <<
", tx " << wti.tx_hash <<
@ -875,10 +886,10 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf
{
epee::log_space::console_colors color = st.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta;
uint64_t decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT;
std::string token_info = get_tocken_info_string(st.asset_id, decimal_points);
std::string token_info = get_token_info_string(st.asset_id, decimal_points);
message_writer(epee::log_space::console_color_cyan, false) << " "
<< std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(st.amount, decimal_points) << (st.is_income ? " received," : " spent") << " " << token_info;
message_writer(epee::log_space::console_color_cyan, false) << " "
<< std::right << std::setw(24) << print_money_trailing_zeros_replaced_with_spaces(st.amount, decimal_points) << std::left << (st.is_income ? " received," : " spent") << " " << token_info;
}
}
@ -1055,7 +1066,7 @@ bool simple_wallet::print_wti(const tools::wallet_public::wallet_transfer_info&
{
epee::log_space::console_colors cl = st.is_income ? epee::log_space::console_color_green: epee::log_space::console_color_magenta;
uint64_t decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT;
std::string token_info = get_tocken_info_string(st.asset_id, decimal_points);
std::string token_info = get_token_info_string(st.asset_id, decimal_points);
success_msg_writer(cl)
<< (st.is_income ? "Received " : "Sent ")
@ -1566,7 +1577,10 @@ bool preprocess_asset_id(std::string& address_arg, crypto::public_key& asset_id)
{
auto p = address_arg.find(':');
if (p == std::string::npos)
{
asset_id = currency::native_coin_asset_id;
return true;
}
std::string asset_id_str = address_arg.substr(0, p);
std::string address_itself = address_arg.substr(p+1, address_arg.size());
if (!epee::string_tools::parse_tpod_from_hex_string(asset_id_str, asset_id))
@ -1625,19 +1639,28 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
currency::tx_destination_entry de = AUTO_VAL_INIT(de);
de.addr.resize(1);
bool ok = currency::parse_amount(de.amount, local_args[i + 1]);
if (!ok || 0 == de.amount)
{
fail_msg_writer() << "amount is wrong: " << local_args[i] << ' ' << local_args[i + 1] <<
", expected number from 0 to " << print_money(std::numeric_limits<uint64_t>::max());
return true;
}
if (!preprocess_asset_id(local_args[i], de.asset_id))
{
fail_msg_writer() << "address is wrong: " << local_args[i];
return true;
}
uint32_t asset_flags = 0;
asset_descriptor_base asset_info{};
if (!m_wallet->get_asset_info(de.asset_id, asset_info, asset_flags))
{
fail_msg_writer() << "unknown asset id: " << de.asset_id;
return true;
}
bool ok = currency::parse_amount(local_args[i + 1], de.amount, asset_info.decimal_point);
if (!ok || 0 == de.amount)
{
fail_msg_writer() << "amount is wrong: " << local_args[i] << ' ' << local_args[i + 1] <<
", expected number from 0 to " << print_money_brief(std::numeric_limits<uint64_t>::max(), asset_info.decimal_point) << " with maximum " << (int)asset_info.decimal_point << " digits after decimal point";
return true;
}
//check if address looks like wrapped address
if (is_address_like_wrapped(local_args[i]))
@ -2086,6 +2109,46 @@ bool simple_wallet::deploy_new_asset(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::call_rpc(const std::vector<std::string>& args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (!args.size() || args.size() > 2)
{
fail_msg_writer() << "invalid arguments count: " << args.size() << ", expected 1 or 2 (path to rpc request)";
return true;
}
std::string method = args[0];
std::string method_body_request = "{}";
if (args.size() > 1)
{
bool r = epee::file_io_utils::load_file_to_string(args[1], method_body_request);
if (!r)
{
fail_msg_writer() << "invalid path: " << args[1] << ", failed to load body";
return true;
}
}
std::string req_full = "{\"id\": 0,\"jsonrpc\" : \"\", \"method\": \"";
req_full += method + "\",\"params\" : " + method_body_request + "}";
epee::net_utils::http::http_request_info query_info;
query_info.m_URI = "/json_rpc";
query_info.m_body = req_full;
epee::net_utils::http::http_response_info response;
tools::wallet_rpc_server::connection_context conn_context(RPC_INTERNAL_UI_CONTEXT, 0, 0, false);
tools::wallet_rpc_server srv(m_wallet);
srv.handle_http_request(query_info, response, conn_context);
success_msg_writer(true) << "Response code: " << response.m_response_code << ", body: " << ENDL << response.m_body;
SIMPLE_WALLET_CATCH_TRY_ENTRY();
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::emit_asset(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
@ -2240,6 +2303,55 @@ bool simple_wallet::update_asset(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer_asset_ownership(const std::vector<std::string>& args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (args.size() != 2)
{
fail_msg_writer() << "invalid arguments count: " << args.size() << ", expected 2";
return true;
}
crypto::public_key asset_id = currency::null_pkey;
bool r = epee::string_tools::parse_tpod_from_hex_string(args[0], asset_id);
if (!r)
{
fail_msg_writer() << "Failed to load asset_id from: " << args[0];
return true;
}
crypto::public_key new_owner = currency::null_pkey;
r = epee::string_tools::parse_tpod_from_hex_string(args[1], new_owner);
if (!r)
{
fail_msg_writer() << "Failed to load new owner public key from: " << args[1];
return true;
}
currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb);
r = m_wallet->daemon_get_asset_info(asset_id, adb);
if (!r)
{
fail_msg_writer() << "Unknown asset: " << args[0];
return true;
}
currency::transaction result_tx = AUTO_VAL_INIT(result_tx);
m_wallet->transfer_asset_ownership(asset_id, new_owner, result_tx);
success_msg_writer(true) << "Asset owner update tx sent: " << get_transaction_hash(result_tx) << " (unconfirmed) : " << ENDL
<< "Asset ID: " << asset_id << ENDL
<< "Title: " << adb.full_name << ENDL
<< "Ticker: " << adb.ticker << ENDL
<< "Emitted: " << print_fixed_decimal_point(adb.current_supply, adb.decimal_point) << ENDL
<< "Max emission: " << print_fixed_decimal_point(adb.total_max_supply, adb.decimal_point) << ENDL
;
SIMPLE_WALLET_CATCH_TRY_ENTRY();
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::add_custom_asset_id(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
@ -2492,7 +2604,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args)
}
uint64_t amount = 0;
r = currency::parse_amount(amount, args[2]);
r = currency::parse_amount(args[2], amount);
if (!r || amount == 0)
{
fail_msg_writer() << "incorrect amount: " << args[2];
@ -3027,7 +3139,7 @@ int main(int argc, char* argv[])
uint64_t max_amount = 0;
CHECK_AND_ASSERT_MES(epee::string_tools::string_to_num_fast(params[0], outs_min) && outs_min > 0 && outs_min < 256, EXIT_FAILURE, "incorrect param: " << params[0]);
CHECK_AND_ASSERT_MES(epee::string_tools::string_to_num_fast(params[1], outs_max) && outs_max > 0 && outs_max < 256, EXIT_FAILURE, "incorrect param: " << params[1]);
CHECK_AND_ASSERT_MES(currency::parse_amount(max_amount, params[2]), EXIT_FAILURE, "incorrect param: " << params[2]);
CHECK_AND_ASSERT_MES(currency::parse_amount(params[2], max_amount), EXIT_FAILURE, "incorrect param: " << params[2]);
wal.set_defragmentation_tx_settings(true, outs_min, outs_max, max_amount);
}
}

View file

@ -91,12 +91,13 @@ namespace currency
bool tor_enable(const std::vector<std::string> &args);
bool tor_disable(const std::vector<std::string> &args);
bool deploy_new_asset(const std::vector<std::string> &args);
bool call_rpc(const std::vector<std::string>& args);
bool add_custom_asset_id(const std::vector<std::string> &args);
bool remove_custom_asset_id(const std::vector<std::string> &args);
bool emit_asset(const std::vector<std::string> &args);
bool burn_asset(const std::vector<std::string> &args);
bool update_asset(const std::vector<std::string> &args);
bool transfer_asset_ownership(const std::vector<std::string>& args);
//----------------------------------------------------------------------------------------------------
bool generate_ionic_swap_proposal(const std::vector<std::string> &args);
bool get_ionic_swap_proposal_info(const std::vector<std::string> &args);
@ -109,7 +110,7 @@ namespace currency
uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon();
std::string get_tocken_info_string(const crypto::public_key& asset_id, uint64_t& decimal_point);
std::string get_token_info_string(const crypto::public_key& asset_id, uint64_t& decimal_point);
bool print_wti(const tools::wallet_public::wallet_transfer_info& wti);
bool check_password_for_operation();
crypto::hash get_hash_from_pass_and_salt(const std::string& pass, uint64_t salt);

View file

@ -8,6 +8,6 @@
#define PROJECT_REVISION "0"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 317
#define PROJECT_VERSION_BUILD_NO 324
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -3813,40 +3813,76 @@ bool wallet2::balance(std::list<wallet_public::asset_balance_entry>& balances, u
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_asset_id_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, bool& whitelist_) const
bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags) const
{
asset_flags = aif_none;
if (asset_id == currency::native_coin_asset_id)
{
asset_info = currency::get_native_coin_asset_descriptor();
whitelist_ = true;
asset_flags |= aif_whitelisted;
return true;
}
//check if asset is whitelisted or customly added
whitelist_ = false;
// whitelisted?
auto it_white = m_whitelisted_assets.find(asset_id);
if (it_white == m_whitelisted_assets.end())
{
//check if it custom asset
auto it_cust = m_custom_assets.find(asset_id);
if (it_cust == m_custom_assets.end())
{
return false;
}
else
{
asset_info = it_cust->second;
}
}
else
if (it_white != m_whitelisted_assets.end())
{
asset_info = it_white->second;
whitelist_ = true;
asset_flags |= aif_whitelisted;
return true;
}
// custom asset?
auto it_cust = m_custom_assets.find(asset_id);
if (it_cust != m_custom_assets.end())
{
asset_info = it_cust->second;
return true;
}
auto it_own = m_own_asset_descriptors.find(asset_id);
if (it_own != m_own_asset_descriptors.end())
{
asset_info = it_own->second;
asset_flags |= aif_own;
return true;
}
return false;
}
//----------------------------------------------------------------------------------------------------
size_t wallet2::get_asset_decimal_point(const crypto::public_key& asset_id, size_t result_if_not_found /* = 0 */) const
{
if (asset_id == currency::native_coin_asset_id)
return currency::get_native_coin_asset_descriptor().decimal_point;
// whitelisted?
auto it_white = m_whitelisted_assets.find(asset_id);
if (it_white != m_whitelisted_assets.end())
return it_white->second.decimal_point;
// custom asset?
auto it_cust = m_custom_assets.find(asset_id);
if (it_cust != m_custom_assets.end())
return it_cust->second.decimal_point;
auto it_own = m_own_asset_descriptors.find(asset_id);
if (it_own != m_own_asset_descriptors.end())
return it_own->second.decimal_point;
return result_if_not_found; // if not overriden, use the 0 decimal point (raw numbers) as the default
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_asset_decimal_point(const crypto::public_key& asset_id, size_t* p_decimal_point_result) const
{
size_t decimal_point = get_asset_decimal_point(asset_id, SIZE_MAX);
if (decimal_point == SIZE_MAX)
return false;
if (p_decimal_point_result != nullptr)
*p_decimal_point_result = decimal_point;
return true;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::balance() const
{
uint64_t stub = 0;
@ -3951,7 +3987,7 @@ bool wallet2::generate_utxo_defragmentation_transaction_if_needed(currency::tran
//----------------------------------------------------------------------------------------------------
std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool include_unspent /*= true*/, bool show_only_unknown /*= false*/, const std::string& filter_asset_ticker /*= std::string{}*/) const
{
static const char* header = "index amount ticker g_index flags block tx out# asset id";
static const char* header = " index amount ticker g_index flags block tx out# asset id";
std::stringstream ss;
ss << header << ENDL;
size_t count = 0;
@ -3963,10 +3999,11 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu
if ((td.is_spent() && !include_spent) || (!td.is_spent() && !include_unspent))
continue;
bool is_locked = !is_transfer_unlocked(td);
bool native_coin = td.is_native_coin();
asset_descriptor_base adb{};
bool whitelisted = false;
if (get_asset_id_info(td.get_asset_id(), adb, whitelisted) == show_only_unknown)
uint32_t asset_info_flags{};
if (get_asset_info(td.get_asset_id(), adb, asset_info_flags) == show_only_unknown)
{
if (!show_only_unknown)
++unknown_assets_outs_count;
@ -3976,7 +4013,7 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu
if (!filter_asset_ticker.empty() && adb.ticker != filter_asset_ticker)
continue;
ss << std::right <<
ss << std::right << (is_locked ? "*" : " ") <<
std::setw(5) << i << " " <<
std::setw(21) << print_asset_money(td.m_amount, adb.decimal_point) << " " <<
std::setw(6) << std::left << (native_coin ? std::string(" ") : adb.ticker) << " " << std::right <<
@ -4007,9 +4044,10 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu
std::string wallet2::get_balance_str() const
{
// balance unlocked / [balance total] ticker asset id
// 1391306.970000000000 / 1391306.970000000000 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 1391306.97 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 106.971 / 206.4 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 0.21 / 98.51 DP2 a6974d5874e97e5f4ed5ad0a62f0975edbccb1bb55502fc75c7fe808f12f44d3
// 190.123456789012 / 199.123456789012 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 98.0 BGTVUW af2b12f3033337f9aea1845a6bc3fc966ed4d13227a3ace7706fca7dbcdaa7e2
// 1000.034 DP3 d4aba1020f26927571771e04b585b4ffb211f52708d5e4c465bbdfa4a12e6271
static const char* header = " balance unlocked / [balance total] ticker asset id";
std::stringstream ss;
@ -4033,12 +4071,16 @@ std::string wallet2::get_balance_str() const
//----------------------------------------------------------------------------------------------------
std::string wallet2::get_balance_str_raw() const
{
// balance unlocked / [balance total] ticker asset id
// 1391306.970000000000 / 1391306.970000000000 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 1391306.97 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 106.971 / 206.4 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// balance unlocked / [balance total] DP asset id
// 0.21 / 98.51 2 a6974d5874e97e5f4ed5ad0a62f0975edbccb1bb55502fc75c7fe808f12f44d3
// 190.123456789012 / 199.123456789012 12 d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 98.0 12 af2b12f3033337f9aea1845a6bc3fc966ed4d13227a3ace7706fca7dbcdaa7e2
// 1000.034 3 d4aba1020f26927571771e04b585b4ffb211f52708d5e4c465bbdfa4a12e6271
//WHITELIST:
// 7d3f348fbebfffc4e61a3686189cf870ea393e1c88b8f636acbfdacf9e4b2db2 CT
// ...
static const char* header = " balance unlocked / [balance total] asset id";
static const char* header = " balance unlocked / [balance total] DP asset id";
std::stringstream ss;
ss << header << ENDL;
@ -4048,32 +4090,39 @@ std::string wallet2::get_balance_str_raw() const
for(const auto& entry : balances_map)
{
ss << " " << std::left << std::setw(20) << print_fixed_decimal_point_with_trailing_spaces(entry.second.unlocked, 12);
size_t decimal_point = 0;
bool has_known_decimal_point = get_asset_decimal_point(entry.first, &decimal_point);
ss << " " << std::left << std::setw(20) << print_fixed_decimal_point_with_trailing_spaces(entry.second.unlocked, decimal_point);
if(entry.second.total == entry.second.unlocked)
ss << " ";
else
ss << " / " << std::setw(20) << print_fixed_decimal_point_with_trailing_spaces(entry.second.total, 12);
ss << " " << std::setw(8) << std::left << entry.first << ENDL;
ss << " / " << std::setw(20) << print_fixed_decimal_point_with_trailing_spaces(entry.second.total, decimal_point);
if (has_known_decimal_point)
ss << std::setw(2) << std::right << decimal_point;
else
ss << "??";
ss << " " << entry.first << ENDL;
}
//print whitelist
ss << "WHITELIST: " << ENDL;
for(const auto& entry : m_whitelisted_assets)
{
ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL;
}
// print whitelist
// print custom list
ss << "CUSTOM LIST: " << ENDL;
for(const auto& entry : m_custom_assets)
{
ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL;
}
// print own list
ss << "OWN DESCRIPTORS LIST: " << ENDL;
for(const auto& entry : m_own_asset_descriptors)
@ -4782,7 +4831,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful
crypto::hash hash_for_zarcanum_sig = get_block_hash(b);
WLT_CHECK_AND_ASSERT_MES(miner_tx_tgc.pseudo_out_amount_blinding_masks_sum.is_zero(), false, "pseudo_out_amount_blinding_masks_sum is nonzero"); // it should be zero because there's only one input (stake), and thus one pseudo out
WLT_CHECK_AND_ASSERT_MES(miner_tx_tgc.pseudo_out_amount_blinding_masks_sum.is_zero(), false, "pseudo_out_amount_blinding_masks_sum is nonzero"); // it should be zero because there's only one ZC input (stake), and thus only one pseudo out (the sum is non-zero iff POC > 1)
crypto::scalar_t pseudo_out_amount_blinding_mask = miner_tx_tgc.amount_blinding_masks_sum; // sum of outputs' amount blinding masks
miner_tx_tgc.pseudo_outs_blinded_asset_ids.emplace_back(currency::native_coin_asset_id_pt); // for Zarcanum stake inputs pseudo outputs commitments has explicit native asset id
@ -5396,13 +5445,28 @@ bool wallet2::daemon_get_asset_info(const crypto::public_key& asset_id, currency
return true;
}
//----------------------------------------------------------------------------------------------------
void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward)
void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee)
{
COMMAND_RPC_GET_ALIAS_DETAILS::request req;
req.alias = ai.m_alias;
COMMAND_RPC_GET_ALIAS_DETAILS::response rsp = AUTO_VAL_INIT(rsp);
bool r = m_core_proxy->call_COMMAND_RPC_GET_ALIAS_DETAILS(req, rsp);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to call_COMMAND_RPC_GET_ALIAS_DETAILS");
CHECK_AND_ASSERT_THROW_MES(rsp.status == API_RETURN_CODE_OK, "call_COMMAND_RPC_GET_ALIAS_DETAILS response: " << rsp.status);
currency::account_public_address addr = AUTO_VAL_INIT(addr);
currency::get_account_address_from_str(addr, rsp.alias_details.address);
CHECK_AND_ASSERT_THROW_MES(m_account.get_public_address().spend_public_key == addr.spend_public_key &&
m_account.get_public_address().view_public_key == addr.view_public_key, "call_COMMAND_RPC_GET_ALIAS_DETAILS: ownership is not confirmed");
if (!validate_alias_name(ai.m_alias))
{
throw std::runtime_error(std::string("wrong alias characters: ") + ai.m_alias);
}
bool r = currency::sign_extra_alias_entry(ai, m_account.get_keys().account_address.spend_public_key, m_account.get_keys().spend_secret_key);
r = currency::sign_extra_alias_entry(ai, m_account.get_keys().account_address.spend_public_key, m_account.get_keys().spend_secret_key);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to sign alias update");
WLT_LOG_L2("Generated update alias info: " << ENDL
<< "alias: " << ai.m_alias << ENDL
@ -6040,8 +6104,8 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo
r = t_unserializable_object_from_blob(ionic_context, decrypted_raw_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to unserialize decrypted ionic_context");
r = validate_tx_output_details_againt_tx_generation_context(tx, ionic_context.gen_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to validate decrypted ionic_context");
r = validate_tx_details_against_tx_generation_context(tx, ionic_context.gen_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "validate_tx_details_against_tx_generation_context failed");
std::unordered_map<crypto::public_key, uint64_t> amounts_provided_by_a;
@ -6079,7 +6143,7 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo
//THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.input_amounts.size() == tx.vin.size(), "Tx gen context has mismatch with tx(amount != amount)");
for (i = 0; i != tx.vin.size(); i++)
{
size_t mx = 0;
//size_t mx = 0;
uint64_t amount = 0;
crypto::public_key in_asset_id = currency::native_coin_asset_id;
if (tx.vin[i].type() == typeid(txin_zc_input))
@ -6087,12 +6151,12 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo
in_asset_id = ionic_context.gen_context.real_zc_ins_asset_ids[zc_current_index].to_public_key();
amount = ionic_context.gen_context.zc_input_amounts[zc_current_index];
zc_current_index++;
mx = boost::get<currency::txin_zc_input>(tx.vin[i]).key_offsets.size() - 1;
//mx = boost::get<currency::txin_zc_input>(tx.vin[i]).key_offsets.size() - 1;
}
else if (tx.vin[i].type() == typeid(txin_to_key))
{
amount = boost::get<txin_to_key>(tx.vin[i]).amount;
mx = boost::get<currency::txin_to_key>(tx.vin[i]).key_offsets.size() - 1;
//mx = boost::get<currency::txin_to_key>(tx.vin[i]).key_offsets.size() - 1;
}
else
{
@ -6184,7 +6248,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
{
if (balances[item.asset_id].unlocked < item.amount)
{
WLT_THROW_IF_FALSE_WALLET_EX_MES(false, error::not_enough_money, "", balances[item.asset_id].unlocked, item.amount, 0 /*fee*/, item.asset_id);
WLT_THROW_IF_FALSE_WALLET_EX_MES(false, error::not_enough_money, "", balances[item.asset_id].unlocked, item.amount, 0 /*fee*/, item.asset_id, get_asset_decimal_point(item.asset_id));
}
if (item.asset_id == currency::native_coin_asset_id)
{
@ -6537,10 +6601,13 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys
src.real_output = interted_it - src.outputs.begin();
src.real_output_in_tx_index = td.m_internal_output_index;
std::stringstream ss;
ss << "source entry [" << i << "], td_idx: " << J << ", ";
print_source_entry(ss, src);
WLT_LOG_L1(ss.str());
if (epee::log_space::get_set_log_detalisation_level() >= LOG_LEVEL_1)
{
std::stringstream ss;
ss << "source entry [" << i << "], td_idx: " << J << ", ";
print_source_entry(ss, src);
WLT_LOG_L1(ss.str());
}
++i;
}
@ -7036,10 +7103,17 @@ bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money
{
if(item.second.needed_amount == 0)
continue;
auto asset_cashe_it = m_found_free_amounts.find(item.first);
WLT_THROW_IF_FALSE_WALLET_EX_MES(asset_cashe_it != m_found_free_amounts.end(), error::not_enough_money, "", item.second.found_amount, item.second.needed_amount, 0, item.first);
item.second.found_amount = select_indices_for_transfer(selected_indexes, asset_cashe_it->second, item.second.needed_amount, fake_outputs_count);
WLT_THROW_IF_FALSE_WALLET_EX_MES(item.second.found_amount >= item.second.needed_amount, error::not_enough_money, "", item.second.found_amount, item.second.needed_amount, 0, item.first);
const crypto::public_key asset_id = item.first;
asset_descriptor_base asset_info{};
uint32_t asset_flags = 0;
if (!get_asset_info(asset_id, asset_info, asset_flags))
WLT_LOG_L1("select_indices_for_transfer: unknown asset id: " << asset_id);
auto asset_cache_it = m_found_free_amounts.find(asset_id);
WLT_THROW_IF_FALSE_WALLET_EX_MES(asset_cache_it != m_found_free_amounts.end(), error::not_enough_money, "", item.second.found_amount, item.second.needed_amount, 0, asset_id, asset_info.decimal_point);
item.second.found_amount = select_indices_for_transfer(selected_indexes, asset_cache_it->second, item.second.needed_amount, fake_outputs_count, asset_id, asset_info.decimal_point);
WLT_THROW_IF_FALSE_WALLET_EX_MES(item.second.found_amount >= item.second.needed_amount, error::not_enough_money, "", item.second.found_amount, item.second.needed_amount, 0, asset_id, asset_info.decimal_point);
}
if (m_current_context.pconstruct_tx_param && m_current_context.pconstruct_tx_param->need_at_least_1_zc)
{
@ -7061,11 +7135,13 @@ bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money
return true;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_indexes, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count_)
uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_indexes, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count_,
const crypto::public_key& asset_id, size_t decimal_point)
{
WLT_LOG_GREEN("Selecting indices for transfer of " << print_money_brief(needed_money) << " with " << fake_outputs_count_ << " fake outs, found_free_amounts.size()=" << found_free_amounts.size() << "...", LOG_LEVEL_0);
WLT_LOG_GREEN("Selecting indices for transfer of " << print_money_brief(needed_money, decimal_point) << " with " << fake_outputs_count_ << " fake outs, found_free_amounts.size()=" << found_free_amounts.size() <<
(asset_id == native_coin_asset_id ? std::string() : std::string(", asset_id: ") + crypto::pod_to_hex(asset_id)) << "...", LOG_LEVEL_0);
uint64_t found_money = 0;
//uint64_t found_zc_input = false;
size_t outputs_found = 0;
std::string selected_amounts_str;
while (found_money < needed_money && found_free_amounts.size())
{
@ -7085,7 +7161,8 @@ uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_in
found_money += it->first;
selected_indexes.push_back(*it->second.begin());
WLT_LOG_L2("Selected index: " << *it->second.begin() << ", transfer_details: " << ENDL << epee::serialization::store_t_to_json(m_transfers[*it->second.begin()]));
selected_amounts_str += (selected_amounts_str.empty() ? "" : "+") + print_money_brief(it->first);
selected_amounts_str += (selected_amounts_str.empty() ? "" : "+") + print_money_brief(it->first, decimal_point);
++outputs_found;
}
it->second.erase(it->second.begin());
if (!it->second.size())
@ -7093,7 +7170,8 @@ uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_in
}
WLT_LOG_GREEN("Found " << print_money_brief(found_money) << " as " << selected_indexes.size() << " out(s): " << selected_amounts_str << ", found_free_amounts.size()=" << found_free_amounts.size(), LOG_LEVEL_0);
WLT_LOG_GREEN("Found " << print_money_brief(found_money, decimal_point) << " as " << outputs_found << " out(s): " << selected_amounts_str << ", found_free_amounts.size()=" << found_free_amounts.size() <<
(asset_id == native_coin_asset_id ? std::string() : std::string(", asset_id: ") + crypto::pod_to_hex(asset_id)), LOG_LEVEL_0);
return found_money;
}
//----------------------------------------------------------------------------------------------------
@ -7317,13 +7395,15 @@ void wallet2::print_source_entry(std::stringstream& output, const currency::tx_s
for(auto& el : src.outputs)
ss << el.out_reference << " ";
output << "amount: " << print_money_brief(src.amount) << (src.is_zc() ? " (hidden)" : "")
<< ", real_output: " << src.real_output
output << "amount: " << print_money_brief(src.amount, get_asset_decimal_point(src.asset_id)) << (src.is_zc() ? "" : " (bare)");
if (src.asset_id != currency::native_coin_asset_id)
output << " (" << print16(src.asset_id) << ")";
output << ", real_output: " << src.real_output
<< ", real_output_in_tx_index: " << src.real_output_in_tx_index
<< ", indexes: " << ss.str();
if (src.asset_id != currency::native_coin_asset_id)
output << ", asset_id: " << print16(src.asset_id);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const
@ -7585,7 +7665,8 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f
}
//TIME_MEASURE_FINISH_MS(sign_ms_input_time);
THROW_IF_FALSE_WALLET_EX(get_object_blobsize(result.tx) < CURRENCY_MAX_TRANSACTION_BLOB_SIZE, error::tx_too_big, result.tx, m_upper_transaction_size_limit);
size_t tx_blob_size = tx_to_blob(result.tx).size();
THROW_IF_FALSE_WALLET_EX(tx_blob_size < CURRENCY_MAX_TRANSACTION_BLOB_SIZE, error::tx_too_big, result.tx, m_upper_transaction_size_limit);
if (store_tx_secret_key)
m_tx_keys.insert(std::make_pair(get_transaction_hash(result.tx), result.one_time_key));
@ -7803,7 +7884,7 @@ void wallet2::transfer(construct_tx_param& ctp,
void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public_address& destination_addr, uint64_t threshold_amount, const currency::payment_id_t& payment_id,
uint64_t fee, size_t& outs_total, uint64_t& amount_total, size_t& outs_swept, uint64_t& amount_swept, currency::transaction* p_result_tx /* = nullptr */, std::string* p_filename_or_unsigned_tx_blob_str /* = nullptr */)
{
static const size_t estimated_bytes_per_input = 78;
static const size_t estimated_bytes_per_input = 85;
const size_t estimated_max_inputs = static_cast<size_t>(CURRENCY_MAX_TRANSACTION_BLOB_SIZE / (estimated_bytes_per_input * (fake_outs_count + 1.5))); // estimated number of maximum tx inputs under the tx size limit
const size_t tx_sources_for_querying_random_outs_max = estimated_max_inputs * 2;
@ -7818,9 +7899,10 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
for (uint64_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
size_t fake_outs_count_for_td = is_auditable() ? 0 : (td.is_zc() ? m_core_runtime_config.hf4_minimum_mixins : fake_outs_count);
uint64_t amount = td.amount();
if (amount < threshold_amount &&
is_transfer_ready_to_go(td, fake_outs_count))
if (amount < threshold_amount && td.is_native_coin() &&
is_transfer_ready_to_go(td, fake_outs_count_for_td))
{
selected_transfers.push_back(i);
outs_total += 1;
@ -7896,9 +7978,12 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
auto try_construct_tx = [this, &selected_transfers, &rpc_get_random_outs_resp, &fake_outs_count, &fee, &destination_addr]
(size_t st_index_upper_boundary, currency::finalize_tx_param& ftp, uint64_t& amount_swept) -> try_construct_result_t
{
// prepare inputs
amount_swept = 0;
ftp.gen_context = tx_generation_context{};
ftp.sources.clear();
ftp.prepared_destinations.clear();
// prepare inputs
ftp.sources.resize(st_index_upper_boundary);
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(st_index_upper_boundary <= selected_transfers.size(), "index_upper_boundary = " << st_index_upper_boundary << ", selected_transfers.size() = " << selected_transfers.size());
for (size_t st_index = 0; st_index < st_index_upper_boundary; ++st_index)
@ -7993,7 +8078,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
size_t st_index_upper_boundary = std::min(selected_transfers.size(), estimated_max_inputs);
try_construct_result_t res = try_construct_tx(st_index_upper_boundary, ftp, amount_swept);
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(res != rc_too_few_outputs, st_index_upper_boundary << " biggest unspent outputs have total amount of " << print_money_brief(amount_swept)
<< " which is less than required fee: " << print_money_brief(fee) << ", transaction cannot be constructed");
@ -8067,10 +8152,10 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
transaction local_tx;
transaction* p_tx = p_result_tx != nullptr ? p_result_tx : &local_tx;
*p_tx = AUTO_VAL_INIT_T(transaction);
*p_tx = transaction{};
try
{
crypto::secret_key sk = AUTO_VAL_INIT(sk);
crypto::secret_key sk{};
finalize_transaction(ftp, *p_tx, sk, true);
}
catch (...)

View file

@ -416,7 +416,7 @@ namespace tools
void cancel_offer_by_id(const crypto::hash& tx_id, uint64_t of_ind, uint64_t fee, currency::transaction& tx);
void update_offer_by_id(const crypto::hash& tx_id, uint64_t of_ind, const bc_services::offer_details_ex& od, currency::transaction& res_tx);
void request_alias_registration(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward = 0, const crypto::secret_key& authority_key = currency::null_skey); // if the given reward is 0, then the actual reward value will be requested via RPC
void request_alias_update(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward);
void request_alias_update(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee);
bool check_available_sources(std::list<uint64_t>& amounts);
void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id);
@ -441,7 +441,12 @@ namespace tools
uint64_t balance(uint64_t& unloked) const;
uint64_t unlocked_balance() const;
bool get_asset_id_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, bool& whitelist_) const;
enum asset_info_flags_t : uint32_t { aif_none = 0, aif_whitelisted = 1 << 0, aif_own = 1 << 1 };
bool get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags) const;
size_t get_asset_decimal_point(const crypto::public_key& asset_id, size_t result_if_not_found = 0) const;
bool get_asset_decimal_point(const crypto::public_key& asset_id, size_t* p_decimal_point_result) const;
void transfer(uint64_t amount, const currency::account_public_address& acc, const crypto::public_key& asset_id = currency::native_coin_asset_id);
void transfer(uint64_t amount, size_t fake_outs_count, const currency::account_public_address& acc, uint64_t fee = TX_DEFAULT_FEE, const crypto::public_key& asset_id = currency::native_coin_asset_id);
void transfer(uint64_t amount, const currency::account_public_address& acc, currency::transaction& result_tx, const crypto::public_key& asset_id = currency::native_coin_asset_id);
@ -604,7 +609,7 @@ namespace tools
bool is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count) const;
bool is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count) const;
uint64_t select_indices_for_transfer(std::vector<uint64_t>& ind, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count);
uint64_t select_indices_for_transfer(std::vector<uint64_t>& ind, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count, const crypto::public_key& asset_id, size_t decimal_point);
bool select_indices_for_transfer(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes);
//PoS

View file

@ -350,12 +350,13 @@ namespace tools
//----------------------------------------------------------------------------------------------------
struct not_enough_money : public transfer_error
{
not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee, const crypto::public_key& asset_id)
not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee, const crypto::public_key& asset_id, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT)
: transfer_error(std::move(loc), "")
, m_available(availbable)
, m_tx_amount(tx_amount)
, m_fee(fee)
, m_asset_id(asset_id)
, m_decimal_point(decimal_point)
{
}
@ -367,9 +368,9 @@ namespace tools
{
std::ostringstream ss;
ss << transfer_error::to_string() <<
"available: " << currency::print_money_brief(m_available) <<
", required: " << currency::print_money_brief(m_tx_amount + m_fee) <<
" = " << currency::print_money_brief(m_tx_amount) << " + " << currency::print_money_brief(m_fee) << " (fee)";
"available: " << currency::print_money_brief(m_available, m_decimal_point) <<
", required: " << currency::print_money_brief(m_tx_amount + m_fee, m_decimal_point) <<
" = " << currency::print_money_brief(m_tx_amount, m_decimal_point) << " + " << currency::print_money_brief(m_fee) << " (fee)";
if (m_asset_id != currency::native_coin_asset_id)
ss << ", asset_id: " << m_asset_id;
return ss.str();
@ -380,6 +381,7 @@ namespace tools
uint64_t m_tx_amount;
uint64_t m_fee;
crypto::public_key m_asset_id;
size_t m_decimal_point;
};
struct no_zc_inputs : public transfer_error

View file

@ -633,6 +633,29 @@ namespace wallet_public
};
};
struct COMMAND_RPC_UPDATE_ALIAS
{
DOC_COMMAND("Update an alias details/transwer alias ownership");
struct request
{
currency::alias_rpc_details al;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(al) DOC_DSCR("Alias details") DOC_END
END_KV_SERIALIZE_MAP()
};
struct response
{
crypto::hash tx_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("If success - transactions that performs registration(alias becomes available after few confirmations)") DOC_EXMP("97d91442f8f3c22683585eaa60b53757d49bf046a96269cef45c1bc9ff7300cc") DOC_END
END_KV_SERIALIZE_MAP()
};
};
struct transfer_destination
{

View file

@ -968,6 +968,31 @@ namespace tools
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_update_alias(const wallet_public::COMMAND_RPC_UPDATE_ALIAS::request& req, wallet_public::COMMAND_RPC_UPDATE_ALIAS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::extra_alias_entry ai = AUTO_VAL_INIT(ai);
if (!alias_rpc_details_to_alias_info(req.al, ai))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS";
return false;
}
if (!currency::validate_alias_name(ai.m_alias))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS - Wrong alias name";
return false;
}
currency::transaction tx = AUTO_VAL_INIT(tx);
w.get_wallet()->request_alias_update(ai, tx, w.get_wallet()->get_default_fee());
res.tx_id = get_transaction_hash(tx);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_contracts_send_proposal(const wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL::request& req, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
@ -1199,7 +1224,7 @@ namespace tools
currency::assets_map_to_assets_list(res.global_whitelist, w.get_wallet()->get_global_whitelist());
currency::assets_map_to_assets_list(res.own_assets, w.get_wallet()->get_own_assets());
const auto global_whitelist = w.get_wallet()->get_global_whitelist();
//const auto global_whitelist = w.get_wallet()->get_global_whitelist();
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
@ -1246,7 +1271,7 @@ namespace tools
std::string embedded_payment_id;
//check if address looks like wrapped address
WLT_THROW_IF_FALSE_WITH_CODE(!currency::is_address_like_wrapped(it->address), "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
WLT_THROW_IF_FALSE_WITH_CODE(!w.get_wallet()->get_transfer_address(it->address, de.addr.back(), embedded_payment_id), "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
WLT_THROW_IF_FALSE_WITH_CODE(w.get_wallet()->get_transfer_address(it->address, de.addr.back(), embedded_payment_id), "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
WLT_THROW_IF_FALSE_WITH_CODE(embedded_payment_id.size() == 0, "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
de.amount = it->amount;
de.asset_id = it->asset_id;

View file

@ -116,6 +116,8 @@ namespace tools
MAP_JON_RPC_WE("get_seed_phrase_info", on_get_seed_phrase_info, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO)
MAP_JON_RPC_WE("get_mining_history", on_get_mining_history, wallet_public::COMMAND_RPC_GET_MINING_HISTORY)
MAP_JON_RPC_WE("register_alias", on_register_alias, wallet_public::COMMAND_RPC_REGISTER_ALIAS)
MAP_JON_RPC_WE("update_alias", on_update_alias, wallet_public::COMMAND_RPC_UPDATE_ALIAS)
//contracts API
//MAP_JON_RPC_WE("contracts_send_proposal", on_contracts_send_proposal, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL)
//MAP_JON_RPC_WE("contracts_accept_proposal", on_contracts_accept_proposal, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL)
@ -186,7 +188,8 @@ namespace tools
bool on_search_for_transactions2(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_mining_history(const wallet_public::COMMAND_RPC_GET_MINING_HISTORY::request& req, wallet_public::COMMAND_RPC_GET_MINING_HISTORY::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_register_alias(const wallet_public::COMMAND_RPC_REGISTER_ALIAS::request& req, wallet_public::COMMAND_RPC_REGISTER_ALIAS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_update_alias(const wallet_public::COMMAND_RPC_UPDATE_ALIAS::request& req, wallet_public::COMMAND_RPC_UPDATE_ALIAS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_contracts_send_proposal(const wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL::request& req, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_contracts_accept_proposal(const wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL::request& req, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx);

View file

@ -1459,7 +1459,7 @@ std::string wallets_manager::request_alias_registration(const currency::alias_rp
return API_RETURN_CODE_ALREADY_EXISTS;
}
std::string wallets_manager::request_alias_update(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx, uint64_t reward)
std::string wallets_manager::request_alias_update(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx)
{
currency::extra_alias_entry ai = AUTO_VAL_INIT(ai);
if (!currency::alias_rpc_details_to_alias_info(al, ai))
@ -1480,7 +1480,7 @@ std::string wallets_manager::request_alias_update(const currency::alias_rpc_deta
std::string api_return_code_result = API_RETURN_CODE_FAIL;
do_exception_safe_call(
[&]() {
w->get()->request_alias_update(ai, res_tx, fee, reward);
w->get()->request_alias_update(ai, res_tx, fee);
api_return_code_result = API_RETURN_CODE_OK;
},
[&]() { return get_wallet_log_prefix(wallet_id) + "request_alias_update error: "; },
@ -1539,7 +1539,7 @@ std::string wallets_manager::transfer(uint64_t wallet_id, const view::transfer_p
}
if(!currency::parse_amount(dsts.back().amount, d.amount))
if(!currency::parse_amount(d.amount, dsts.back().amount))
{
return API_RETURN_CODE_BAD_ARG_WRONG_AMOUNT;
}

View file

@ -126,7 +126,7 @@ public:
std::string get_alias_info_by_address(const std::string& addr, currency::alias_rpc_details& res_details);
std::string get_alias_info_by_name(const std::string& name, currency::alias_rpc_details& res_details);
std::string request_alias_registration(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx, uint64_t reward);
std::string request_alias_update(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx, uint64_t reward);
std::string request_alias_update(const currency::alias_rpc_details& al, uint64_t wallet_id, uint64_t fee, currency::transaction& res_tx);
std::string get_alias_coast(const std::string& a, uint64_t& coast);
std::string validate_address(const std::string& addr, std::string& payment_id);
std::string resync_wallet(uint64_t wallet_id);

View file

@ -422,6 +422,15 @@ bool chain_switching_when_gindex_spent_in_both_chains::generate(std::vector<test
GENERATE_ACCOUNT(miner_acc);
GENERATE_ACCOUNT(alice_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
if (m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 2))
{
// HF4 requires tests_random_split_strategy (for 2 outputs minimum)
test_gentime_settings tgts = generator.get_test_gentime_settings();
tgts.split_strategy = tests_random_split_strategy;
generator.set_test_gentime_settings(tgts);
}
MAKE_NEXT_BLOCK(events, blk_1, blk_0, alice_acc);
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
@ -499,6 +508,8 @@ bool alt_blocks_validation_and_same_new_amount_in_two_txs::generate(std::vector<
GENERATE_ACCOUNT(miner_acc);
GENERATE_ACCOUNT(alice_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc);
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
@ -516,26 +527,27 @@ bool alt_blocks_validation_and_same_new_amount_in_two_txs::generate(std::vector<
// make two txs with one output (huge fee, probably - doesn't matter) with amount that is never seen before
std::vector<tx_source_entry> sources;
r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), new_amount + TESTS_DEFAULT_FEE, 0);
r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), new_amount + 2*TESTS_DEFAULT_FEE, 0);
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
std::vector<tx_destination_entry> destinations;
destinations.push_back(tx_destination_entry(new_amount, miner_acc.get_public_address())); // no cashback, just payment
destinations.push_back(tx_destination_entry(new_amount, miner_acc.get_public_address()));
destinations.push_back(tx_destination_entry(TESTS_DEFAULT_FEE, miner_acc.get_public_address())); //just to make two outputs (to please HF4 rules)
transaction tx_1 = AUTO_VAL_INIT(tx_1);
uint64_t tx_version = get_tx_version(get_block_height(blk_3), m_hardforks);
r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, tx_version, 0);
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
events.push_back(tx_1);
ADD_CUSTOM_EVENT(events, tx_1);
// second tx
sources.clear();
r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), new_amount + TESTS_DEFAULT_FEE, 0, sources);
r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), new_amount + 2*TESTS_DEFAULT_FEE, 0, sources);
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
transaction tx_2 = AUTO_VAL_INIT(tx_2);
// use the same destinations
tx_version = get_tx_version(get_block_height(blk_3), m_hardforks);
r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_2, tx_version, 0);
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
events.push_back(tx_2);
ADD_CUSTOM_EVENT(events, tx_2);
// make an alt block with these txs
MAKE_NEXT_BLOCK_TX_LIST(events, blk_3a, blk_2a, miner_acc, std::list<transaction>({ tx_1, tx_2 }));
@ -565,10 +577,19 @@ alt_blocks_with_the_same_txs::alt_blocks_with_the_same_txs()
bool alt_blocks_with_the_same_txs::generate(std::vector<test_event_entry>& events) const
{
// Test idea: check that many two alt blocks having the same tx are correctly handled with respect to is_tx_related_to_altblock()
// Test idea: check that two alt blocks having the same tx are correctly handled with respect to is_tx_related_to_altblock()
GENERATE_ACCOUNT(miner_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
if (m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 2))
{
// HF4 requires tests_random_split_strategy (for 2 outputs minimum)
test_gentime_settings tgts = generator.get_test_gentime_settings();
tgts.split_strategy = tests_random_split_strategy;
generator.set_test_gentime_settings(tgts);
}
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc);
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
@ -634,15 +655,24 @@ bool chain_switching_when_out_spent_in_alt_chain_mixin::generate(std::vector<tes
GENERATE_ACCOUNT(alice_acc);
GENERATE_ACCOUNT(bob_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
if (m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 2))
{
// HF4 requires tests_random_split_strategy (for 2 outputs minimum)
test_gentime_settings tgts = generator.get_test_gentime_settings();
tgts.split_strategy = tests_random_split_strategy;
generator.set_test_gentime_settings(tgts);
}
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc);
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// 0 1 11 12 13 14
// (0 )- (1 )-...(1r)- (2 )- (3 )- <-- main chain
// 0 1 11 12 22 23 24
// (0 )- (1 )-...(1r)- (2 )-...(2r)- (3 )- <-- main chain
// \
// \
// \- (2a)- (3a)- (4a)-
// tx_0 <- tx_1 // tx_1 spends output from tx_0
// \- (2a)-...(2ar)- (3a)- (4a)-
// tx_0 <-------- tx_1 // tx_1 spends output from tx_0
// send batch of 10 x 5 test coins to Alice for easier tx_1 construction (and to generate free decoys)
transaction tx_0;
@ -652,17 +682,21 @@ bool chain_switching_when_out_spent_in_alt_chain_mixin::generate(std::vector<tes
events.push_back(tx_0);
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc);
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
REWIND_BLOCKS_N(events, blk_2r, blk_2, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
MAKE_NEXT_BLOCK(events, blk_3, blk_2r, miner_acc);
// altchain
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner_acc, tx_0);
REWIND_BLOCKS_N(events, blk_2ar, blk_2a, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
// make sure Alice received exactly 50 test coins
CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_2a, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_2ar, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(50));
// Alice spends her 5 test coins received by tx_0
MAKE_TX_FEE_MIX(events, tx_1, alice_acc, bob_acc, MK_TEST_COINS(4), TESTS_DEFAULT_FEE, 3 /* nmix */, blk_2a);
MAKE_TX_FEE_MIX(events, tx_1, alice_acc, bob_acc, MK_TEST_COINS(4), TESTS_DEFAULT_FEE, 3 /* nmix */, blk_2ar);
events.pop_back(); // pop back tx_1 as it won't go into the tx pool normally because of alt chain
// simulate handling a block with that tx: handle tx like going with the block...
@ -670,7 +704,7 @@ bool chain_switching_when_out_spent_in_alt_chain_mixin::generate(std::vector<tes
events.push_back(tx_1);
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
MAKE_NEXT_BLOCK_TX1(events, blk_3a, blk_2a, miner_acc, tx_1);
MAKE_NEXT_BLOCK_TX1(events, blk_3a, blk_2ar, miner_acc, tx_1);
MAKE_NEXT_BLOCK(events, blk_4a, blk_3a, miner_acc);
// make sure Alice has correct balance
@ -687,7 +721,7 @@ bool chain_switching_when_out_spent_in_alt_chain_mixin::generate(std::vector<tes
bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector<test_event_entry>& events) const
{
random_state_test_restorer::reset_random(0); // to make the test deterministic
//random_state_test_restorer::reset_random(0); // to make the test deterministic
uint64_t ts = 1450000000;
test_core_time::adjust(ts);
@ -701,15 +735,24 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector<te
bob_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
if (m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 2))
{
// HF4 requires tests_random_split_strategy (for 2 outputs minimum)
test_gentime_settings tgts = generator.get_test_gentime_settings();
tgts.split_strategy = tests_random_split_strategy;
generator.set_test_gentime_settings(tgts);
}
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc);
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// 0 1 11 12 13 14
// (0 )- (1 )-...(1r)- (2 )- (3 )- <- main chain
// 0 1 11 12 22 23 24
// (0 )- (1 )-...(1r)- (2 )-...(2r)- (3 )- <-- main chain
// \
// \
// \- (2a)- (3a)- (4a)-
// tx_0 <- tx_1 // tx_1 spends an output from tx_0 using ref_by_id and mixins
// \- (2a)-...(2ar)- (3a)- (4a)-
// tx_0 <-------- tx_1 // tx_1 spends an output from tx_0 using ref_by_id and mixins
// send batch of 10 x 5 test coins to Alice for easier tx_0 construction
transaction tx_0;
@ -722,24 +765,29 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector<te
count_ref_by_id_and_gindex_refs_for_tx_inputs(tx_0, refs_count, gindex_count);
CHECK_AND_ASSERT_MES(refs_count == 1 && gindex_count == 0, false, "incorrect input references: " << refs_count << ", " << gindex_count);
events.push_back(tx_0);
ADD_CUSTOM_EVENT(events, tx_0);
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc);
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
REWIND_BLOCKS_N(events, blk_2r, blk_2, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
MAKE_NEXT_BLOCK(events, blk_3, blk_2r, miner_acc);
// altchain
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner_acc, tx_0);
REWIND_BLOCKS_N(events, blk_2ar, blk_2a, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
// make sure Alice received exactly 50 test coins
CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_2a, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_2ar, 2*CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(50));
// Alice spends her 5 test coins received by tx_0
transaction tx_1;
std::vector<tx_destination_entry> destinations;
destinations.push_back(tx_destination_entry(MK_TEST_COINS(4), bob_acc.get_public_address()));
destinations.push_back(tx_destination_entry(MK_TEST_COINS(3), bob_acc.get_public_address()));
destinations.push_back(tx_destination_entry(MK_TEST_COINS(1), bob_acc.get_public_address()));
size_t nmix = 3;
r = construct_tx_to_key(m_hardforks, events, tx_1, blk_2a, alice_acc, destinations, TESTS_DEFAULT_FEE, nmix, 0, empty_extra, empty_attachment, true, true, true);
r = construct_tx_to_key(m_hardforks, events, tx_1, blk_2ar, alice_acc, destinations, TESTS_DEFAULT_FEE, nmix, 0, empty_extra, empty_attachment, true, true, true /* use_ref_by_id */);
CHECK_AND_ASSERT_MES(r, false, "construct_tx_to_key failed");
// make sure tx_1 really use ref_by_id
@ -748,17 +796,22 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector<te
CHECK_AND_ASSERT_MES(refs_count == nmix + 1 && gindex_count == 0, false, "incorrect input references: " << refs_count << ", " << gindex_count);
// simulate handling a block with that tx: handle tx like going with the block...
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
events.push_back(tx_1);
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
ADD_CUSTOM_EVENT(events, event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
ADD_CUSTOM_EVENT(events, tx_1);
ADD_CUSTOM_EVENT(events, event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
MAKE_NEXT_BLOCK_TX1(events, blk_3a, blk_2a, miner_acc, tx_1);
MAKE_NEXT_BLOCK_TX1(events, blk_3a, blk_2ar, miner_acc, tx_1);
MAKE_NEXT_BLOCK(events, blk_4a, blk_3a, miner_acc);
// make sure Alice has correct balance
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_4a, 2);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(45));
// make sure Bob has correct balance
CREATE_TEST_WALLET(bob_wlt, bob_acc, blk_0);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_4a, 2*CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(bob_wlt, MK_TEST_COINS(4));
// make sure chain successfully switched
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_4a), get_block_hash(blk_4a)));

View file

@ -2016,14 +2016,13 @@ bool find_global_index_for_output(const std::vector<test_event_entry>& events, c
std::map<uint64_t, uint64_t> global_outputs; // amount -> outs count
auto process_tx = [&reference_tx, &reference_tx_out_index, &global_outputs](const currency::transaction& tx) -> uint64_t
{
for (size_t tx_out_index = 0; tx_out_index < tx.vout.size(); ++tx_out_index) {
const tx_out_bare &out = boost::get<tx_out_bare>(tx.vout[tx_out_index]);
if (out.target.type() == typeid(txout_to_key)) {
uint64_t global_out_index = global_outputs[out.amount]++;
for (size_t tx_out_index = 0; tx_out_index < tx.vout.size(); ++tx_out_index)
{
uint64_t amount = get_amount_from_variant(tx.vout[tx_out_index]);
uint64_t global_out_index = global_outputs[amount]++;
if (tx_out_index == reference_tx_out_index && tx == reference_tx)
return global_out_index;
}
if (tx_out_index == reference_tx_out_index && tx == reference_tx)
return global_out_index;
}
return UINT64_MAX;
};
@ -2238,32 +2237,105 @@ bool refresh_wallet_and_check_balance(const char* intro_log_message, const char*
return true;
}
bool generate_pos_block_with_given_coinstake(test_generator& generator, const std::vector<test_event_entry> &events, const currency::account_base& miner, const currency::block& prev_block, const currency::transaction& stake_tx, size_t stake_output_idx, currency::block& result, uint64_t stake_output_gidx /* = UINT64_MAX */)
bool decode_output_amount_and_asset_id(const crypto::secret_key& view_secret_key, const crypto::public_key& tx_pub_key, const tx_out_v& out_v, size_t output_index, uint64_t &amount, crypto::public_key* p_asset_id = nullptr)
{
VARIANT_SWITCH_BEGIN(out_v)
VARIANT_CASE_CONST(currency::tx_out_bare, ob)
if (p_asset_id)
*p_asset_id = native_coin_asset_id;
amount = ob.amount;
return true;
VARIANT_CASE_CONST(currency::tx_out_zarcanum, oz)
crypto::key_derivation derivation{};
CHECK_AND_ASSERT_MES(crypto::generate_key_derivation(tx_pub_key, view_secret_key, derivation), false, "generate_key_derivation failed");
crypto::public_key decoded_asset_id{};
crypto::scalar_t amount_blinding_mask{};
crypto::scalar_t asset_id_blinding_mask{};
CHECK_AND_ASSERT_MES(decode_output_amount_and_asset_id(oz, derivation, output_index, amount, decoded_asset_id, amount_blinding_mask, asset_id_blinding_mask), false, "decode_output_amount_and_asset_id failed (wrong keys?)");
if (p_asset_id)
*p_asset_id = decoded_asset_id;
return true;
VARIANT_CASE_OTHER()
CHECK_AND_ASSERT_MES(false, false, "unexpected output type: " << VARIANT_OBJ_TYPENAME);
VARIANT_SWITCH_END()
}
bool decode_output_amount_and_asset_id(const account_base& acc, const transaction& tx, size_t output_index, uint64_t &amount, crypto::public_key* p_asset_id /*= nullptr*/)
{
return decode_output_amount_and_asset_id(acc.get_keys().view_secret_key, get_tx_pub_key_from_extra(tx), tx.vout[output_index], output_index, amount, p_asset_id);
}
uint64_t decode_native_output_amount_or_throw(const account_base& acc, const transaction& tx, size_t output_index)
{
crypto::public_key asset_id{};
uint64_t amount = UINT64_MAX;
bool r = decode_output_amount_and_asset_id(acc.get_keys().view_secret_key, get_tx_pub_key_from_extra(tx), tx.vout[output_index], output_index, amount, &asset_id);
CHECK_AND_ASSERT_THROW_MES(r, "decode_output_amount_and_asset_id failed");
r = (asset_id == native_coin_asset_id);
CHECK_AND_ASSERT_THROW_MES(r, "wrong asset_id: not native coin");
return amount;
}
bool generate_pos_block_with_given_coinstake(test_generator& generator, const std::vector<test_event_entry> &events, const currency::account_base& miner, const currency::block& prev_block,
const currency::transaction& stake_tx, size_t stake_output_idx, currency::block& result, uint64_t stake_output_gidx /* = UINT64_MAX */)
{
bool r = false;
crypto::hash prev_id = get_block_hash(prev_block);
size_t height = get_block_height(prev_block) + 1;
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
//currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
currency::wide_difficulty_type pos_diff{};
crypto::hash last_pow_block_hash{}, last_pos_block_kernel_hash{};
r = generator.get_params_for_next_pos_block(prev_id, pos_diff, last_pow_block_hash, last_pos_block_kernel_hash);
CHECK_AND_ASSERT_MES(r, false, "get_params_for_next_pos_block failed");
try
{
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake_tx);
if (stake_output_gidx == UINT64_MAX)
{
bool r = find_global_index_for_output(events, prev_id, stake_tx, stake_output_idx, stake_output_gidx);
r = find_global_index_for_output(events, prev_id, stake_tx, stake_output_idx, stake_output_gidx);
CHECK_AND_ASSERT_MES(r, false, "find_global_index_for_output failed");
}
uint64_t stake_output_amount =boost::get<currency::tx_out_bare>( stake_tx.vout[stake_output_idx]).amount;
uint64_t stake_output_amount = decode_native_output_amount_or_throw(miner, stake_tx, stake_output_idx);
crypto::key_image stake_output_key_image;
keypair kp;
generate_key_image_helper(miner.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake_tx.vout[stake_output_idx]).target).key;
pos_block_builder pb;
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
pb.step2_set_txs(std::vector<transaction>());
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner.get_public_address());
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, miner);
if (pb.m_context.zarcanum)
{
std::vector<tx_source_entry> sources;
r = fill_tx_sources(sources, events, prev_block, miner.get_keys(), UINT64_MAX /* <- to get all possible entries*/, 0 /* nmix */, false /* check_for_spends*/, false /* check_for_unlocktime*/, false);
//CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
bool found = false;
for(const auto& se : sources)
{
if (se.real_output_in_tx_index == stake_output_idx && se.real_out_tx_key == stake_tx_pub_key)
{
found = true;
pb.step3a(pos_diff, last_pow_block_hash, last_pos_block_kernel_hash);
pb.step3b(se.amount, stake_output_key_image, se.real_out_tx_key, se.real_output_in_tx_index, se.real_out_amount_blinding_mask, miner.get_keys().view_secret_key,
stake_output_gidx, prev_block.timestamp, POS_SCAN_WINDOW, POS_SCAN_STEP);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner.get_public_address());
pb.step5_sign(se, miner.get_keys());
break;
}
}
CHECK_AND_ASSERT_MES(found, false, "required source entry could not be found (difficult case, ask sowle)");
}
else
{
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, pos_diff, last_pow_block_hash, last_pos_block_kernel_hash, prev_block.timestamp);
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner.get_public_address());
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake_tx.vout[stake_output_idx]).target).key;
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, miner);
}
result = pb.m_block;
return true;

View file

@ -741,6 +741,10 @@ bool refresh_wallet_and_check_balance(const char* intro_log_message, const char*
uint64_t expected_awaiting_out = UINT64_MAX);
uint64_t get_last_block_of_type(bool looking_for_pos, const test_generator::blockchain_vector& blck_chain);
bool decode_output_amount_and_asset_id(const currency::account_base& acc, const currency::transaction& tx, size_t output_index, uint64_t &amount, crypto::public_key* p_asset_id = nullptr);
uint64_t decode_native_output_amount_or_throw(const currency::account_base& acc, const currency::transaction& tx, size_t output_index);
bool generate_pos_block_with_given_coinstake(test_generator& generator, const std::vector<test_event_entry> &events, const currency::account_base& miner, const currency::block& prev_block, const currency::transaction& stake_tx, size_t stake_output_idx, currency::block& result, uint64_t stake_output_gidx = UINT64_MAX);
bool check_ring_signature_at_gen_time(const std::vector<test_event_entry>& events, const crypto::hash& last_block_id, const currency::txin_to_key& in_t_k,
const crypto::hash& hash_for_sig, const std::vector<crypto::signature> &sig);
@ -1021,11 +1025,18 @@ inline void count_ref_by_id_and_gindex_refs_for_tx_inputs(const currency::transa
refs_by_gindex = 0;
for (auto& in : tx.vin)
{
if (in.type() != typeid(currency::txin_to_key))
const currency::referring_input* p_ri = nullptr;
VARIANT_SWITCH_BEGIN(in)
VARIANT_CASE_CONST(currency::txin_to_key, intk)
p_ri = &intk;
VARIANT_CASE_CONST(currency::txin_zc_input, inzc)
p_ri = &inzc;
VARIANT_SWITCH_END()
if (!p_ri)
continue;
const currency::txin_to_key& in2key = boost::get<currency::txin_to_key>(in);
for (auto& ko : in2key.key_offsets)
for (auto& ko : p_ri->key_offsets)
{
if (ko.type() == typeid(currency::ref_by_id))
++refs_by_id;

View file

@ -26,7 +26,7 @@ namespace
const command_line::arg_descriptor<bool> arg_play_test_data ("play-test-data", "");
const command_line::arg_descriptor<bool> arg_generate_and_play_test_data ("generate-and-play-test-data", "");
const command_line::arg_descriptor<bool> arg_test_transactions ("test-transactions", "");
const command_line::arg_descriptor<std::string> arg_run_single_test ("run-single-test", "" );
const command_line::arg_descriptor<std::string> arg_run_single_test ("run-single-test", "<TEST_NAME[@HF]> TEST_NAME -- name of a single test to run, HF -- specific hardfork id to run the test for" );
const command_line::arg_descriptor<bool> arg_enable_debug_asserts ("enable-debug-asserts", "" );
const command_line::arg_descriptor<bool> arg_stop_on_fail ("stop-on-fail", "");
@ -428,6 +428,8 @@ bool gen_and_play_intermitted_by_blockchain_saveload(const char* const genclass_
CHECK_AND_ASSERT_MES(!hardforks.empty(), false, "invalid hardforks mask: " << hardfork_str_mask); \
for(size_t i = 0; i < hardforks.size() && !skip_all_till_the_end; ++i) \
{ \
if (run_single_test_hardfork != SIZE_MAX && hardforks[i] != run_single_test_hardfork) \
continue; \
std::string tns = std::string(#genclass) + " @ HF " + epee::string_tools::num_to_string_fast(hardforks[i]); \
const char* testname = tns.c_str(); \
TIME_MEASURE_START_MS(t); \
@ -916,9 +918,20 @@ int main(int argc, char* argv[])
epee::debug::get_set_enable_assert(true, command_line::get_arg(g_vm, arg_enable_debug_asserts)); // don't comment out this: many tests have normal-negative checks (i.e. tx with invalid amount shouldn't be created), so be ready for MANY assertion breaks
std::string run_single_test;
size_t run_single_test_hardfork = SIZE_MAX; // SIZE_MAX means all hard forks, other values mean hardfork id
if (command_line::has_arg(g_vm, arg_run_single_test))
{
run_single_test = command_line::get_arg(g_vm, arg_run_single_test);
std::string arg = command_line::get_arg(g_vm, arg_run_single_test);
std::vector<std::string> items;
boost::split(items, arg, boost::is_any_of("@"));
CHECK_AND_ASSERT_MES(items.size() > 0, 2, "unable to parse arg_run_single_test");
run_single_test = items[0];
if (items.size() > 1)
{
int64_t val = 0;
epee::string_tools::string_to_num_fast(items[1], val);
run_single_test_hardfork = val;
}
}
if (run_single_test.empty())
@ -1087,6 +1100,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(wallet_rpc_integrated_address);
GENERATE_AND_PLAY(wallet_rpc_integrated_address_transfer);
GENERATE_AND_PLAY(wallet_rpc_transfer);
GENERATE_AND_PLAY(wallet_rpc_alias_tests);
GENERATE_AND_PLAY_HF(wallet_rpc_exchange_suite, "3,4");
GENERATE_AND_PLAY(wallet_chain_switch_with_spending_the_same_ki);
GENERATE_AND_PLAY(wallet_sending_to_integrated_address);
@ -1109,7 +1123,7 @@ int main(int argc, char* argv[])
//GENERATE_AND_PLAY(pos_emission_test); // Long test! by demand only
GENERATE_AND_PLAY(pos_wallet_big_block_test);
//GENERATE_AND_PLAY(block_template_against_txs_size); // Long test! by demand only
GENERATE_AND_PLAY(pos_altblocks_validation);
GENERATE_AND_PLAY_HF(pos_altblocks_validation, "3-*");
GENERATE_AND_PLAY_HF(pos_mining_with_decoys, "3");
// alternative blocks and generic chain-switching tests
@ -1118,13 +1132,13 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_chain_switch_1);
GENERATE_AND_PLAY(bad_chain_switching_with_rollback);
GENERATE_AND_PLAY(chain_switching_and_tx_with_attachment_blobsize);
GENERATE_AND_PLAY(chain_switching_when_gindex_spent_in_both_chains);
GENERATE_AND_PLAY_HF(chain_switching_when_gindex_spent_in_both_chains, "3-*");
GENERATE_AND_PLAY(alt_chain_coins_pow_mined_then_spent);
GENERATE_AND_PLAY(gen_simple_chain_split_1);
GENERATE_AND_PLAY(alt_blocks_validation_and_same_new_amount_in_two_txs);
GENERATE_AND_PLAY(alt_blocks_with_the_same_txs);
GENERATE_AND_PLAY(chain_switching_when_out_spent_in_alt_chain_mixin);
GENERATE_AND_PLAY(chain_switching_when_out_spent_in_alt_chain_ref_id);
GENERATE_AND_PLAY_HF(alt_blocks_validation_and_same_new_amount_in_two_txs, "3-*");
GENERATE_AND_PLAY_HF(alt_blocks_with_the_same_txs, "3-*");
GENERATE_AND_PLAY_HF(chain_switching_when_out_spent_in_alt_chain_mixin, "3-*");
GENERATE_AND_PLAY_HF(chain_switching_when_out_spent_in_alt_chain_ref_id, "3-*");
// miscellaneous tests

View file

@ -518,7 +518,7 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev
r = false;
try
{
alice_wlt->request_alias_update(ai_alice_update, res_tx, TESTS_DEFAULT_FEE, 0);
alice_wlt->request_alias_update(ai_alice_update, res_tx, TESTS_DEFAULT_FEE);
}
catch (...)
{
@ -540,7 +540,7 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev
// update alias, change comment and address
ai.m_text_comment = "Update to normal";
ai.m_address = m_accounts[MINER_ACC_IDX].get_public_address();
alice_wlt->request_alias_update(ai, res_tx, TESTS_DEFAULT_FEE, 0);
alice_wlt->request_alias_update(ai, res_tx, TESTS_DEFAULT_FEE);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
@ -586,7 +586,7 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev
// update alias once again, change comment and address to auditable
// alias updated by miner, as he's the owner now
miner_wlt->request_alias_update(ai_alice_update, res_tx, TESTS_DEFAULT_FEE, 0);
miner_wlt->request_alias_update(ai_alice_update, res_tx, TESTS_DEFAULT_FEE);
// after HF2: extra_alias_entry should be here, not extra_alias_entry_old
r = have_type_in_variant_container<extra_alias_entry>(res_tx.extra);
@ -1221,7 +1221,7 @@ bool hard_fork_2_alias_update_using_old_tx<before_hf_2>::c1(currency::core& c, s
//
{
transaction tx_upd = AUTO_VAL_INIT(tx_upd);
alice_wlt->request_alias_update(ai_upd, tx_upd, TESTS_DEFAULT_FEE, 0);
alice_wlt->request_alias_update(ai_upd, tx_upd, TESTS_DEFAULT_FEE);
std::string tx_upd_hex = epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(tx_upd));
LOG_PRINT_L0("tx upd: " << ENDL << tx_upd_hex);
}
@ -1334,9 +1334,9 @@ bool hard_fork_2_incorrect_alias_update<before_hf_2>::c1(currency::core& c, size
r = false;
try
{
alice_wlt->request_alias_update(ai_upd, tx_upd, TESTS_DEFAULT_FEE, 0);
alice_wlt->request_alias_update(ai_upd, tx_upd, TESTS_DEFAULT_FEE);
}
catch (tools::error::tx_rejected&)
catch(std::runtime_error&)
{
// this should cause an exception with certain type
r = true;

View file

@ -167,10 +167,10 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
// generate miner tx using incorrect current_block_size only for size estimation
uint64_t block_reward_without_fee = 0;
uint64_t block_reward = 0;
m_block_reward = 0;
size_t estimated_block_size = m_txs_total_size;
bool r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee,
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
CHECK_AND_ASSERT_THROW_MES(r, "construct_miner_tx failed");
estimated_block_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx);
@ -178,7 +178,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
for (size_t try_count = 0; try_count != 10; ++try_count)
{
r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee,
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed");
cumulative_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx);
@ -230,13 +230,71 @@ void pos_block_builder::step5_sign(const currency::tx_source_entry& se, const cu
ring.emplace_back(el.stealth_address, el.amount_commitment, el.blinded_asset_id, el.concealing_point);
}
crypto::hash tx_hash_for_sig = get_block_hash(m_block);
crypto::point_t stake_out_blinded_asset_id_pt = currency::native_coin_asset_id_pt + se.real_out_asset_id_blinding_mask * crypto::c_point_X;
crypto::hash hash_for_zarcanum_sig = get_block_hash(m_block);
#ifndef NDEBUG
{
crypto::point_t source_amount_commitment = crypto::c_scalar_1div8 * se.amount * stake_out_blinded_asset_id_pt + crypto::c_scalar_1div8 * se.real_out_amount_blinding_mask * crypto::c_point_G;
CHECK_AND_ASSERT_THROW_MES(se.outputs[se.real_output].amount_commitment == source_amount_commitment.to_public_key(), "real output amount commitment check failed");
CHECK_AND_ASSERT_THROW_MES(ring[prepared_real_out_index].amount_commitment == se.outputs[se.real_output].amount_commitment, "ring secret member doesn't match with the stake output");
CHECK_AND_ASSERT_THROW_MES(m_context.stake_amount == se.amount, "stake_amount missmatch");
}
#endif
CHECK_AND_ASSERT_THROW_MES(m_miner_tx_tgc.pseudo_out_amount_blinding_masks_sum.is_zero(), "pseudo_out_amount_blinding_masks_sum is nonzero"); // it should be zero because there's only one input (stake), and thus one pseudo out
crypto::scalar_t pseudo_out_amount_blinding_mask = m_miner_tx_tgc.amount_blinding_masks_sum; // sum of outputs' amount blinding masks
//LOG_PRINT_YELLOW(std::setw(42) << std::left << "pseudo_out_amount_blinding_mask : " << pseudo_out_amount_blinding_mask, LOG_LEVEL_0);
//LOG_PRINT_YELLOW(std::setw(42) << std::left << "m_miner_tx_tgc.amount_blinding_masks[0] : " << m_miner_tx_tgc.amount_blinding_masks[0], LOG_LEVEL_0);
m_miner_tx_tgc.pseudo_outs_blinded_asset_ids.emplace_back(currency::native_coin_asset_id_pt); // for Zarcanum stake inputs pseudo outputs commitments has explicit native asset id
m_miner_tx_tgc.pseudo_outs_plus_real_out_blinding_masks.emplace_back(0);
m_miner_tx_tgc.real_zc_ins_asset_ids.emplace_back(se.asset_id);
// TODO @#@# [architecture] the same value is calculated in zarcanum_generate_proof(), consider an impovement
m_miner_tx_tgc.pseudo_out_amount_commitments_sum += m_context.stake_amount * stake_out_blinded_asset_id_pt + pseudo_out_amount_blinding_mask * crypto::c_point_G;
m_miner_tx_tgc.real_in_asset_id_blinding_mask_x_amount_sum += se.real_out_asset_id_blinding_mask * m_context.stake_amount;
//LOG_PRINT_YELLOW(std::setw(42) << std::left << "pseudo_out_amount_commitments_sum : " << m_miner_tx_tgc.pseudo_out_amount_commitments_sum, LOG_LEVEL_0);
uint8_t err = 0;
r = crypto::zarcanum_generate_proof(tx_hash_for_sig, m_context.kernel_hash, ring, m_context.last_pow_block_id_hashed, m_context.sk.kimage,
secret_x, m_context.secret_q, prepared_real_out_index,m_context.stake_amount, se.real_out_asset_id_blinding_mask, m_context.stake_out_amount_blinding_mask, -m_miner_tx_tgc.amount_blinding_masks_sum,
r = crypto::zarcanum_generate_proof(hash_for_zarcanum_sig, m_context.kernel_hash, ring, m_context.last_pow_block_id_hashed, m_context.sk.kimage,
secret_x, m_context.secret_q, prepared_real_out_index, m_context.stake_amount, se.real_out_asset_id_blinding_mask, m_context.stake_out_amount_blinding_mask, pseudo_out_amount_blinding_mask,
static_cast<crypto::zarcanum_proof&>(sig), &err);
CHECK_AND_ASSERT_THROW_MES(r, "zarcanum_generate_proof failed, err: " << (int)err);
//
// The miner tx prefix should be sealed by now, and the tx hash should be defined.
// Any changes made below should only affect the signatures/proofs and should not impact the prefix hash calculation.
//
crypto::hash miner_tx_id = get_transaction_hash(m_block.miner_tx);
// proofs for miner_tx
// asset surjection proof
currency::zc_asset_surjection_proof asp{};
r = generate_asset_surjection_proof(miner_tx_id, false, m_miner_tx_tgc, asp); // has_non_zc_inputs == false because after the HF4 PoS mining is only allowed for ZC stakes inputs
CHECK_AND_ASSERT_THROW_MES(r, "generete_asset_surjection_proof failed");
m_block.miner_tx.proofs.emplace_back(std::move(asp));
// range proofs
currency::zc_outs_range_proof range_proofs{};
r = generate_zc_outs_range_proof(miner_tx_id, 0, m_miner_tx_tgc, m_block.miner_tx.vout, range_proofs);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate zc_outs_range_proof()");
m_block.miner_tx.proofs.emplace_back(std::move(range_proofs));
// balance proof
currency::zc_balance_proof balance_proof{};
r = generate_tx_balance_proof(m_block.miner_tx, miner_tx_id, m_miner_tx_tgc, m_block_reward, balance_proof);
CHECK_AND_ASSERT_THROW_MES(r, "generate_tx_balance_proof failed");
m_block.miner_tx.proofs.emplace_back(std::move(balance_proof));
//err = 0;
//r = crypto::zarcanum_verify_proof(hash_for_zarcanum_sig, m_context.kernel_hash, ring, m_context.last_pow_block_id_hashed, m_context.sk.kimage, m_context.basic_diff, sig, &err);
//CHECK_AND_ASSERT_THROW_MES(r, "zarcanum_verify_proof failed, err: " << (int)err);
//r = check_tx_balance(m_block.miner_tx, miner_tx_id, m_block_reward);
//CHECK_AND_ASSERT_THROW_MES(r, "check_tx_balance failed");
}
else
{

View file

@ -77,7 +77,7 @@ struct pos_block_builder
//currency::stake_kernel m_stake_kernel {};
size_t m_height = 0;
size_t m_pos_stake_output_gindex = 0;
//uint64_t m_pos_stake_amount = 0;
uint64_t m_block_reward = 0;
currency::tx_generation_context m_miner_tx_tgc {};
currency::pos_mining_context m_context {};

View file

@ -849,7 +849,7 @@ bool pos_wallet_big_block_test::c1(currency::core& c, size_t ev_index, const std
pos_altblocks_validation::pos_altblocks_validation()
{
test_chain_unit_base::set_hardforks_for_old_tests();
//test_chain_unit_base::set_hardforks_for_old_tests();
}
bool pos_altblocks_validation::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
@ -871,23 +871,26 @@ bool pos_altblocks_validation::generate(std::vector<test_event_entry>& events) c
std::list<account_base> miner_acc_lst(1, miner_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core");
MAKE_NEXT_BLOCK(events, blk_1, blk_0, alice_acc);
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, alice_acc);
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
bool HF4_active = m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, get_block_height(blk_1r) + 1);
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc);
const transaction& stake_tx = blk_1.miner_tx;
uint64_t alice_money = get_outs_money_amount(stake_tx);
uint64_t stake_tx_out_id = 0;
// select stake_tx_out_id as an output with the biggest amount
for (size_t i = 1; i < stake_tx.vout.size(); ++i)
{
if (boost::get<currency::tx_out_bare>(stake_tx.vout[i]).amount >boost::get<currency::tx_out_bare>( stake_tx.vout[stake_tx_out_id]).amount)
stake_tx_out_id = i;
}
uint64_t alice_money = decode_native_output_amount_or_throw(alice_acc, blk_1.miner_tx, stake_tx_out_id);
//// select stake_tx_out_id as an output with the biggest amount
//for (size_t i = 1; i < stake_tx.vout.size(); ++i)
//{
// if (boost::get<currency::tx_out_bare>(stake_tx.vout[i]).amount > boost::get<currency::tx_out_bare>( stake_tx.vout[stake_tx_out_id]).amount)
// stake_tx_out_id = i;
//}
MAKE_TX_FEE(events, tx_0, alice_acc, alice_acc, alice_money - TESTS_DEFAULT_FEE * 17, TESTS_DEFAULT_FEE * 17, blk_2);
// tx_0 transfers all Alice's money, so it effectevily spends all outputs in stake_ts, make sure it does
CHECK_AND_ASSERT_MES(tx_0.vin.size() == stake_tx.vout.size(), false, "probably, tx_0 doesn't spend all Alice's money as expected, tx_0.vin.size()=" << tx_0.vin.size() << ", stake_tx.vout.size()=" << stake_tx.vout.size());
//CHECK_AND_ASSERT_MES(tx_0.vin.size() == stake_tx.vout.size(), false, "probably, tx_0 doesn't spend all Alice's money as expected, tx_0.vin.size()=" << tx_0.vin.size() << ", stake_tx.vout.size()=" << stake_tx.vout.size());
MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_0);
@ -900,12 +903,13 @@ bool pos_altblocks_validation::generate(std::vector<test_event_entry>& events) c
REWIND_BLOCKS_N_WITH_TIME(events, blk_3r, blk_3, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_NEXT_POS_BLOCK(events, blk_4, blk_3r, miner_acc, miner_acc_lst);
MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc);
MAKE_NEXT_POS_BLOCK(events, blk_6, blk_5, miner_acc, miner_acc_lst);
// 0 1 11 12 13 23 24 25 <- height
// 0 11 21 22 23 33 34 35 36 <- height
//
// +------- blk_1 mined by Alice
// |
// (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- <- main chain
// (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- (6 )- <- main chain
// | tx_0
// +---<<---uses-blk_1-out--+
@ -915,38 +919,60 @@ bool pos_altblocks_validation::generate(std::vector<test_event_entry>& events) c
block blk_2a = AUTO_VAL_INIT(blk_2a);
r = generate_pos_block_with_given_coinstake(generator, events, alice_acc, blk_1r, stake_tx, stake_tx_out_id, blk_2a);
CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed");
events.push_back(blk_2a);
ADD_CUSTOM_EVENT(events, blk_2a);
CHECK_AND_ASSERT_MES(generator.add_block_info(blk_2a, std::list<transaction>()), false, "add_block_info failed");
// 0 1 11 12 13 23 24 25 <- height
// 0 11 21 22 23 33 34 35 36 <- height
//
// +-----------------------+
// | tx_0 tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- <- main chain
// | tx_0 tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- (6 )- <- main chain
// | \
// | \- (2a)- <- alt chain
// +--------------+ PoS block 2a uses stake already spent in main chain
// | \- (2a)- <- alt chain
// +--------------+ PoS block 2a uses stake already spent in main chain
// Case 2 (should fail)
// Case 2a (should fail)
// alt PoS block (blk_3a) refers in its coinstake to an output (stake_tx_out_id) already spent in this alt chain (in blk_2a)
block blk_3a = AUTO_VAL_INIT(blk_3a);
r = generate_pos_block_with_given_coinstake(generator, events, alice_acc, blk_2a, stake_tx, stake_tx_out_id, blk_3a);
CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed");
DO_CALLBACK(events, "mark_invalid_block");
events.push_back(blk_3a);
ADD_CUSTOM_EVENT(events, blk_3a);
// 0 1 11 12 13 23 24 25 <- height
// 0 11 21 22 23 33 34 35 36 <- height
//
// +-----------------------+
// | tx_0 tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- <- main chain
// | tx_0 tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- (6 )- <- main chain
// || \
// || \- (2a)- #3a#- <- alt chain
// |+--------------+ | PoS block 2a uses stake already spent in main chain (okay)
// +-----------------------+ PoS block 3a uses stake already spent in current alt chain (fail)
// || \- (2a)- #3a#- <- alt chain
// |+--------------+ | PoS block 2a uses stake already spent in main chain (okay)
// +-----------------------+ PoS block 3a uses stake already spent in current alt chain (fail)
// Case 2b (should fail)
// alt PoS block (blk_3aa) has invalid signature
block blk_3aa{};
r = generate_pos_block_with_given_coinstake(generator, events, miner_acc, blk_2a, blk_0r.miner_tx, 0, blk_3aa);
CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed");
if (HF4_active)
boost::get<zarcanum_sig>(blk_3aa.miner_tx.signatures[0]).y0.m_u64[1] = 5; // invalidate signature
else
boost::get<NLSAG_sig>(blk_3aa.miner_tx.signatures[0]).s[0].c.data[5] = 7; // invalidate signature
DO_CALLBACK(events, "mark_invalid_block");
ADD_CUSTOM_EVENT(events, blk_3aa);
// 0 11 21 22 23 33 34 35 36 <- height
//
// +-----------------------+
// | tx_0 tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- (6 )- <- main chain
// || \
// || \- (2a)- #3aa#- <- alt chain
// |+--------------+ | PoS block 2a uses stake already spent in main chain (okay)
// +-----------------------+ PoS block 3aa has incorrect signature (fail)
REWIND_BLOCKS_N_WITH_TIME(events, blk_2br, blk_2a, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// Case 3 (should pass)
@ -954,55 +980,63 @@ bool pos_altblocks_validation::generate(std::vector<test_event_entry>& events) c
block blk_3b = AUTO_VAL_INIT(blk_3b);
r = generate_pos_block_with_given_coinstake(generator, events, alice_acc, blk_2br, blk_2a.miner_tx, 0, blk_3b);
CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed");
events.push_back(blk_3b);
ADD_CUSTOM_EVENT(events, blk_3b);
CHECK_AND_ASSERT_MES(generator.add_block_info(blk_3b, std::list<transaction>()), false, "add_block_info failed");
// 0 1 11 12 13 22 23 24 25 <- height
// 0 11 21 22 23 33 34 35 36 <- height
//
// +-----------------------+
// | tx_0 tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )- ........ (3r)- (4 )- (5 )- <- main chain
// | tx_0 tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )- ........ (3r)- (4 )- (5 )- (6 )- <- main chain
// || \
// || \- (2a)- #3a#- <- alt chain
// |+--------------+ \ | PoS block 2a uses stake already spent in main chain (okay)
// +---------------|-------+ PoS block 3a uses stake already spent in current alt chain (fail)
// || \- (2a)- #3a#- <- alt chain
// |+--------------+ \ | PoS block 2a uses stake already spent in main chain (okay)
// +---------------|-------+ PoS block 3a uses stake already spent in current alt chain (fail)
// | \
// | \ ...... (2br)- (3b)- <- alt chain
// | \ ...... (2br)- (3b)- <- alt chain
// | |
// +-----------------------+ PoS block 3b uses as stake an output, created in current alt chain (2a)
// +-----------------------+ PoS block 3b uses as stake an output, created in current alt chain (2a)
// Case 4 (should fail)
// alt PoS block (blk_4b) in its coinstake refers to an output (tx_0) that appeared in the main chain (blk_3) above split height
block blk_4b = AUTO_VAL_INIT(blk_4b);
r = generate_pos_block_with_given_coinstake(generator, events, alice_acc, blk_3b, tx_0, tx_0_some_output_idx, blk_4b, tx_0_some_output_gindex);
CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed");
DO_CALLBACK(events, "mark_invalid_block");
events.push_back(blk_4b);
if (HF4_active)
{
CHECK_AND_ASSERT_MES(!r, false, "generate_pos_block_with_given_coinstake not failed as expected");
}
else
{
CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed");
DO_CALLBACK(events, "mark_invalid_block");
ADD_CUSTOM_EVENT(events, blk_4b);
}
// 0 1 11 12 13 22 23 24 25 <- height
// 0 11 21 22 23 33 34 35 36 <- height
// +------------------+
// +-----------------------+ | |
// | tx_0 | tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )- ........ (3r)- (4 )- (5 )- <- main chain
// | tx_0 | tx_0 spends all outputs in blk_1 (main chain)
// (0 )- (1 )-...(1r)- (2 )- (3 )- ........ (3r)- (4 )- (5 )- (6 )- <- main chain
// || \ |
// || \- (2a)- #3a#- | <- alt chain
// |+--------------+ \ | \ PoS block 2a uses stake already spent in main chain (okay)
// +---------------|-------+ \ PoS block 3a uses stake already spent in current alt chain (fail)
// || \- (2a)- #3a#- | <- alt chain
// |+--------------+ \ | \ PoS block 2a uses stake already spent in main chain (okay)
// +---------------|-------+ \ PoS block 3a uses stake already spent in current alt chain (fail)
// | \ \
// | \ ...... (2br)- (3b)- #4b# <- alt chain
// | \ ...... (2br)- (3b)- #4b# <- alt chain
// | |
// +-----------------------+ PoS block 3b uses as stake an output, created in current alt chain (2a)
// +-----------------------+ PoS block 3b uses as stake an output, created in current alt chain (2a)
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_5), get_block_hash(blk_5)));
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_6), get_block_hash(blk_6)));
// Final check: switch the chains
MAKE_NEXT_BLOCK(events, blk_4c, blk_3b, miner_acc);
MAKE_NEXT_BLOCK(events, blk_5c, blk_4c, miner_acc);
MAKE_NEXT_BLOCK(events, blk_6c, blk_5c, miner_acc);
MAKE_NEXT_BLOCK(events, blk_7c, blk_6c, miner_acc);
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_6c), get_block_hash(blk_6c)));
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_7c), get_block_hash(blk_7c)));
size_t txs_count = 1;
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", txs_count); // tx_0 should left in the pool

View file

@ -6,12 +6,76 @@
#include "chaingen.h"
#include "wallet_rpc_tests.h"
#include "wallet_test_core_proxy.h"
#include "currency_core/currency_core.h"
#include "currency_core/bc_offers_service.h"
#include "rpc/core_rpc_server.h"
#include "currency_protocol/currency_protocol_handler.h"
#include "../../src/wallet/wallet_rpc_server.h"
#include "offers_helper.h"
#include "random_helper.h"
using namespace currency;
template<typename server_t>
struct transport
{
server_t& m_rpc_srv;
transport(server_t& rpc_srv) :m_rpc_srv(rpc_srv)
{}
epee::net_utils::http::http_response_info m_response;
bool is_connected() { return true; }
template<typename t_a, typename t_b, typename t_c>
bool connect(t_a ta, t_b tb, t_c tc) { return true; }
template<typename dummy_t>
bool invoke(const std::string uri, const std::string method_, const std::string& body, const epee::net_utils::http::http_response_info** ppresponse_info, const dummy_t& d)
{
epee::net_utils::http::http_request_info query_info;
query_info.m_URI = uri;
query_info.m_body = body;
tools::wallet_rpc_server::connection_context ctx;
bool r = m_rpc_srv.handle_http_request(query_info, m_response, ctx);
if (ppresponse_info)
*ppresponse_info = &m_response;
return r;
}
};
template<typename request_t, typename response_t, typename t_rpc_server>
bool invoke_text_json_for_rpc(t_rpc_server& srv, const std::string& method_name, const request_t& req, response_t& resp)
{
transport<t_rpc_server> tr(srv);
bool r = epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, resp, tr);
return r;
}
template<typename request_t, typename response_t>
bool invoke_text_json_for_wallet(std::shared_ptr<tools::wallet2> wlt, const std::string& method_name, const request_t& req, response_t& resp)
{
tools::wallet_rpc_server wlt_rpc_wrapper(wlt);
return invoke_text_json_for_rpc(wlt_rpc_wrapper, method_name, req, resp);
}
template<typename request_t, typename response_t>
bool invoke_text_json_for_core(currency::core& c, const std::string& method_name, const request_t& req, response_t& resp)
{
currency::t_currency_protocol_handler<currency::core> m_cprotocol(c, nullptr);
nodetool::node_server<currency::t_currency_protocol_handler<currency::core> > p2p(m_cprotocol);
bc_services::bc_offers_service of(nullptr);
currency::core_rpc_server core_rpc_wrapper(c, p2p, of);
core_rpc_wrapper.set_ignore_connectivity_status(true);
return invoke_text_json_for_rpc(core_rpc_wrapper, method_name, req, resp);
}
wallet_rpc_integrated_address::wallet_rpc_integrated_address()
{
//REGISTER_CALLBACK_METHOD(wallet_rpc_integrated_address, c1);
@ -189,7 +253,6 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind
}
//------------------------------------------------------------------------------
wallet_rpc_transfer::wallet_rpc_transfer()
{
REGISTER_CALLBACK_METHOD(wallet_rpc_transfer, configure_core);
@ -300,7 +363,100 @@ bool wallet_rpc_transfer::c1(currency::core& c, size_t ev_index, const std::vect
return true;
}
//------------------------------------------------------------------------------
wallet_rpc_alias_tests::wallet_rpc_alias_tests()
{
REGISTER_CALLBACK_METHOD(wallet_rpc_alias_tests, configure_core);
REGISTER_CALLBACK_METHOD(wallet_rpc_alias_tests, c1);
m_hardforks.set_hardfork_height(1, 1);
m_hardforks.set_hardfork_height(2, 1);
m_hardforks.set_hardfork_height(3, 1);
m_hardforks.set_hardfork_height(4, 1);
}
bool wallet_rpc_alias_tests::generate(std::vector<test_event_entry>& events) const
{
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // default callback will initialize core runtime config with m_hardforks
set_hard_fork_heights_to_generator(generator);
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 6);
DO_CALLBACK(events, "c1");
return true;
}
bool wallet_rpc_alias_tests::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
miner_wlt->refresh();
{
tools::wallet_public::COMMAND_RPC_REGISTER_ALIAS::request req = AUTO_VAL_INIT(req);
tools::wallet_public::COMMAND_RPC_REGISTER_ALIAS::response rsp = AUTO_VAL_INIT(rsp);
#define ALIAS_FOR_TEST "monero"
req.al.alias = ALIAS_FOR_TEST;
req.al.details.address = miner_wlt->get_account().get_public_address_str();
req.al.details.comment = "XMR";
r = invoke_text_json_for_wallet(miner_wlt, "register_alias", req, rsp);
CHECK_AND_ASSERT_MES(r, false, "failed to invoke_text_json_for_wallet");
}
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 3);
CHECK_AND_ASSERT_MES(r, false, "failed to mine_next_pow_blocks_in_playtime");
{
currency::COMMAND_RPC_GET_ALIAS_DETAILS::request req = AUTO_VAL_INIT(req);
currency::COMMAND_RPC_GET_ALIAS_DETAILS::response rsp = AUTO_VAL_INIT(rsp);
req.alias = ALIAS_FOR_TEST;
r = invoke_text_json_for_core(c, "get_alias_details", req, rsp);
CHECK_AND_ASSERT_MES(r, false, "failed to invoke_text_json_for_wallet");
CHECK_AND_ASSERT_MES(rsp.status == API_RETURN_CODE_OK, false, "failed to invoke_text_json_for_wallet");
CHECK_AND_ASSERT_MES(rsp.alias_details.address == miner_wlt->get_account().get_public_address_str(), false, "failed to invoke_text_json_for_wallet");
}
miner_wlt->refresh();
{
tools::wallet_public::COMMAND_RPC_UPDATE_ALIAS::request req = AUTO_VAL_INIT(req);
tools::wallet_public::COMMAND_RPC_UPDATE_ALIAS::response rsp = AUTO_VAL_INIT(rsp);
req.al.alias = ALIAS_FOR_TEST;
req.al.details.address = alice_wlt->get_account().get_public_address_str();
req.al.details.comment = "XMR of Alice";
r = invoke_text_json_for_wallet(miner_wlt, "update_alias", req, rsp);
CHECK_AND_ASSERT_MES(r, false, "failed to invoke_text_json_for_wallet");
}
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 3);
CHECK_AND_ASSERT_MES(r, false, "failed to mine_next_pow_blocks_in_playtime");
{
currency::COMMAND_RPC_GET_ALIAS_DETAILS::request req = AUTO_VAL_INIT(req);
currency::COMMAND_RPC_GET_ALIAS_DETAILS::response rsp = AUTO_VAL_INIT(rsp);
req.alias = ALIAS_FOR_TEST;
r = invoke_text_json_for_core(c, "get_alias_details", req, rsp);
CHECK_AND_ASSERT_MES(r, false, "failed to invoke_text_json_for_wallet");
CHECK_AND_ASSERT_MES(rsp.status == API_RETURN_CODE_OK, false, "failed to invoke_text_json_for_wallet");
CHECK_AND_ASSERT_MES(rsp.alias_details.address == alice_wlt->get_account().get_public_address_str(), false, "failed to invoke_text_json_for_wallet");
}
return true;
}
//------------------------------------------------------------------------------
wallet_rpc_exchange_suite::wallet_rpc_exchange_suite()
@ -322,40 +478,6 @@ bool wallet_rpc_exchange_suite::generate(std::vector<test_event_entry>& events)
}
struct transport
{
tools::wallet_rpc_server& m_rpc_srv;
transport(tools::wallet_rpc_server& rpc_srv):m_rpc_srv(rpc_srv)
{}
epee::net_utils::http::http_response_info m_response;
bool is_connected() { return true; }
template<typename t_a, typename t_b, typename t_c>
bool connect(t_a ta, t_b tb, t_c tc) { return true; }
template<typename dummy_t>
bool invoke(const std::string uri, const std::string method_, const std::string& body, const epee::net_utils::http::http_response_info** ppresponse_info, const dummy_t& d)
{
epee::net_utils::http::http_request_info query_info;
query_info.m_URI = uri;
query_info.m_body = body;
tools::wallet_rpc_server::connection_context ctx;
bool r = m_rpc_srv.handle_http_request(query_info, m_response, ctx);
if (ppresponse_info)
*ppresponse_info = &m_response;
return r;
}
};
template<typename request_t, typename response_t>
bool invoke_text_json_for_rpc(tools::wallet_rpc_server& srv, const std::string& method_name, const request_t& req, response_t& resp)
{
transport tr(srv);
bool r = epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, resp, tr);
return r;
}
#include "wallet_rpc_tests_legacy_defs.h"

View file

@ -29,6 +29,14 @@ struct wallet_rpc_transfer : public wallet_test
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
struct wallet_rpc_alias_tests : public wallet_test
{
wallet_rpc_alias_tests();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
/*
Tests to make sure api for exchanges didn't change after HF4(Zarcanum)
testing api: get_recent_txs_and_info, make_integrated_address,

View file

@ -1868,7 +1868,7 @@ bool gen_wallet_alias_via_special_wallet_funcs::c1(currency::core& c, size_t ev_
ai.m_text_comment = "Update!";
ai.m_address = m_accounts[MINER_ACC_IDX].get_public_address();
alice_wlt->request_alias_update(ai, res_tx, TESTS_DEFAULT_FEE, 0);
alice_wlt->request_alias_update(ai, res_tx, TESTS_DEFAULT_FEE);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool");
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);

View file

@ -1,5 +1,5 @@
// Copyright (c) 2020-2023 Zano Project
// Copyright (c) 2020-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2020-2024 Zano Project
// Copyright (c) 2020-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -975,7 +975,7 @@ TEST(crypto, scalar_basics)
return true;
}
TEST(crypto, sc_mul_performance)
TEST(perf, sc_mul)
{
std::vector<scalar_t> scalars(100000);
for (auto& s : scalars)
@ -1070,7 +1070,7 @@ TEST(crypto, hp)
return true;
}
TEST(crypto, cn_fast_hash_perf)
TEST(perf, cn_fast_hash)
{
//return true;
const crypto::hash h_initial = *(crypto::hash*)(&scalar_t::random());
@ -1157,7 +1157,7 @@ TEST(crypto, cn_fast_hash_perf)
TEST(crypto, sc_invert_performance)
TEST(perf, sc_invert)
{
std::vector<scalar_t> scalars(10000);
LOG_PRINT_L0("Running " << scalars.size() << " sc_invert tests...");

View file

@ -34,8 +34,8 @@ POP_VS_WARNINGS
void test_plain_wallet()
{
//std::string res = plain_wallet::init("195.201.107.230", "33336", "E:\\tmp\\", 0);
std::string res = plain_wallet::init("127.0.0.1", "12111", "C:\\Users\\roky\\home22\\", 0);
std::string res = plain_wallet::init("195.201.107.230", "33340", "C:\\Users\\roky\\home\\", 0);
//std::string res = plain_wallet::init("127.0.0.1", "12111", "C:\\Users\\roky\\home22\\", 0);
std::string res___ = plain_wallet::get_wallet_files();
@ -60,21 +60,45 @@ void test_plain_wallet()
std::string invoke_body = "{\"method\":\"store\",\"params\":{}}";
std::string res1 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "{\"method\":\"get_recent_txs_and_info\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}";
std::string res2 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
{
invoke_body = "{\"method\":\"getbalance\",\"params\":{}}";
std::string res3 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "";
}
invoke_body = "{\"method\":\"get_recent_txs_and_info2\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}";
res2 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
{
invoke_body = "{\"method\":\"assets_whitelist_get\",\"params\":{}}";
std::string res3 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "";
}
{
//invoke_body = "{\"method\":\"assets_whitelist_get\",\"params\":{}}";
//std::string json_request;
bool r = epee::file_io_utils::load_file_to_string("C:\\Users\\roky\\home\\wallets\\deploy_asset_request.json", invoke_body);
CHECK_AND_ASSERT_MES(r, void(), "wrong bla bla bla");
std::string res3 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "";
}
//invoke_body = "{\"method\":\"get_recent_txs_and_info\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}";
//std::string res2 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
//invoke_body = "{\"method\":\"get_recent_txs_and_info2\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}";
//res2 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "{\"method\":\"getbalance\",\"params\":{}}";
std::string res3 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "{\r\n \"method\": \"transfer\",\r\n \"params\": {\r\n \"destinations\": [\r\n {\r\n \"amount\": \"1000000000000\",\r\n \"address\": \"ZxD9oVwGwW6ULix9Pqttnr7JDpaoLvDVA1KJ9eA9KRxPMRZT5X7WwtU94XH1Z6q6XTMxNbHmbV2xfZ429XxV6fST2DxEg4BQV\",\r\n \"asset_id\": \"cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6\"\r\n }\r\n ],\r\n \"fee\": 10000000000,\r\n \"mixin\": 10,\r\n \"payment_id\": \"\",\r\n \"comment\": \"\",\r\n \"push_payer\": false,\r\n \"hide_receiver\": true\r\n }\r\n}";
std::string res4 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
//invoke_body = "{\r\n \"method\": \"transfer\",\r\n \"params\": {\r\n \"destinations\": [\r\n {\r\n \"amount\": \"1000000000000\",\r\n \"address\": \"ZxD9oVwGwW6ULix9Pqttnr7JDpaoLvDVA1KJ9eA9KRxPMRZT5X7WwtU94XH1Z6q6XTMxNbHmbV2xfZ429XxV6fST2DxEg4BQV\",\r\n \"asset_id\": \"cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6\"\r\n }\r\n ],\r\n \"fee\": 10000000000,\r\n \"mixin\": 10,\r\n \"payment_id\": \"\",\r\n \"comment\": \"\",\r\n \"push_payer\": false,\r\n \"hide_receiver\": true\r\n }\r\n}";
//std::string res4 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
LOG_PRINT_L0(res);
//LOG_PRINT_L0(res);
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2022 Zano Project
// Copyright (c) 2022-2024 Zano Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -10,23 +10,23 @@ using namespace currency;
namespace
{
void do_pos_test(uint64_t expected, const std::string& str)
void do_pos_test(uint64_t expected, const std::string& str, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT)
{
uint64_t val;
std::string number_str = str;
std::replace(number_str.begin(), number_str.end(), '_', '.');
number_str.erase(std::remove(number_str.begin(), number_str.end(), '~'), number_str.end());
ASSERT_TRUE(parse_amount(val, number_str));
ASSERT_TRUE(parse_amount(number_str, val, decimal_point));
ASSERT_EQ(expected, val);
}
void do_neg_test(const std::string& str)
void do_neg_test(const std::string& str, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT)
{
uint64_t val;
std::string number_str = str;
std::replace(number_str.begin(), number_str.end(), '_', '.');
number_str.erase(std::remove(number_str.begin(), number_str.end(), '~'), number_str.end());
ASSERT_FALSE(parse_amount(val, number_str));
ASSERT_FALSE(parse_amount(number_str, val, decimal_point));
}
}
@ -48,6 +48,23 @@ namespace
do_neg_test(#str); \
}
#define TEST_pos_dp(expected, str, decimal_point) \
TEST(parse_amount, handles_pos_ ## str ## _dp ## decimal_point) \
{ \
do_pos_test(UINT64_C(expected), #str, decimal_point); \
}
#define TEST_neg_dp(str, decimal_point) \
TEST(parse_amount, handles_neg_ ## str ## _dp ## decimal_point) \
{ \
do_neg_test(#str, decimal_point); \
}
#define TEST_neg_n_dp(str, name, decimal_point) \
TEST(parse_amount, handles_neg_ ## name ## _dp ## decimal_point) \
{ \
do_neg_test(#str, decimal_point); \
}
TEST_pos(0, 0);
TEST_pos(0, 00);
@ -96,6 +113,44 @@ TEST_pos(18446744073700000000, 18446744_0737000000000);
TEST_pos(18446744073700000000, 18446744_07370000000000000000000);
TEST_pos(18446744073709551615, 18446744_073709551615);
// non-standard decimal point
TEST_pos_dp(0, 0_0, 3);
TEST_pos_dp(0, 00_0, 3);
TEST_pos_dp(0, 00_00, 3);
TEST_pos_dp(0, 00000000_00, 3);
TEST_pos_dp(0, 00_000000000, 3);
TEST_pos_dp(0, 00_00000000000000000000000000000000, 3);
TEST_pos_dp( 65535, 65535, 0);
TEST_pos_dp( 6553500, 65535, 2);
TEST_pos_dp( 65535000000, 65535, 6);
TEST_pos_dp( 18000000000000000000, 18, 18);
TEST_pos_dp( 1, 0_1, 1);
TEST_pos_dp( 10, 0_1, 2);
TEST_pos_dp( 100, 0_1, 3);
TEST_pos_dp( 10000000000000000000, 0_1, 20);
TEST_pos_dp( 1, 0_001, 3);
TEST_pos_dp( 123, 0_123, 3);
TEST_pos_dp( 1230, 0_123, 4);
TEST_pos_dp( 12300, 0_123, 5);
TEST_pos_dp( 123000, 0_123, 6);
TEST_pos_dp(18446744073709551615, 18446744073709551615, 0);
TEST_pos_dp(18446744073709551615, 18446744073709551615_0, 0);
TEST_pos_dp(18446744073709551615, 1844674407370955161_5, 1);
TEST_pos_dp(18446744073709551615, 1844674407370955161_50, 1);
TEST_pos_dp(18446744073709551615, 18446744073709551_615, 3);
TEST_pos_dp(18446744073709551615, 18446744073709551_615000, 3);
TEST_pos_dp(18446744073709551615, 1_8446744073709551615, 19);
TEST_pos_dp(18446744073709551615, 1_844674407370955161500, 19);
TEST_pos_dp(18446744073709551615, 0_18446744073709551615, 20);
TEST_pos_dp(18446744073709551615, 0_1844674407370955161500, 20);
// Invalid numbers
TEST_neg_n(~, empty_string);
TEST_neg_n(-0, minus_0);
@ -109,10 +164,17 @@ TEST_neg(0_0000000000001);
TEST_neg(0_0000000000009);
TEST_neg(18446744_0737000000001);
TEST_neg_dp(00_184467440737095516150001, 20);
TEST_neg_dp(00_184467440737095516151, 20);
TEST_neg_dp(1_2, 0);
// Overflow
TEST_neg(184467440737_09551616);
TEST_neg(184467440738);
TEST_neg(18446744073709551616);
TEST_neg_dp(18446744073709551616, 0);
TEST_neg_dp(1844674407370955161_60, 1);
TEST_neg_dp(0_18446744073709551616, 20);
// Two or more points
TEST_neg(__);
@ -123,6 +185,51 @@ TEST_neg(0_0_);
TEST_neg(_0_0);
TEST_neg(0_0_0);
// moved from test_format_utils.cpp
TEST(validate_parse_amount_case, validate_parse_amount)
{
uint64_t res = 0;
bool r = currency::parse_amount("0.0001", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000000);
r = currency::parse_amount("100.0001", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000100000000);
r = currency::parse_amount("000.0000", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 0);
r = currency::parse_amount("0", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 0);
r = currency::parse_amount(" 100.0001 ", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000100000000);
r = currency::parse_amount(" 100.0000 ", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000000000000);
r = currency::parse_amount(" 100. 0000 ", res);
ASSERT_FALSE(r);
r = currency::parse_amount("100. 0000", res);
ASSERT_FALSE(r);
r = currency::parse_amount("100 . 0000", res);
ASSERT_FALSE(r);
r = currency::parse_amount("100.00 00", res);
ASSERT_FALSE(r);
r = currency::parse_amount("1 00.00 00", res);
ASSERT_FALSE(r);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

View file

@ -1,4 +1,4 @@
// Copyright (c) 2022 Zano Project
// Copyright (c) 2022-2024 Zano Project
// Copyright (c) 2012-2014 The Boolberry developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -80,7 +80,10 @@ TEST(tx_signatures_packing, 1)
sigs.clear();
ASSERT_EQ(1, get_object_blobsize(sigs));
//
// Notation:
// v(x) = tools::get_varint_packed_size(x)
//
{
// empty NLSAG
@ -105,7 +108,7 @@ TEST(tx_signatures_packing, 1)
// 128 10-ring NLSAGs
// v(128) + 128 * (1 + v(10) + 10 * 2 * 32) = 82178
sigs.clear();
NLSAG_sig nlsag = AUTO_VAL_INIT(nlsag);
NLSAG_sig nlsag{};
nlsag.s.resize(10);
for(size_t i = 0; i < 128; ++i)
sigs.push_back(nlsag);
@ -113,37 +116,38 @@ TEST(tx_signatures_packing, 1)
ASSERT_EQ(82178, get_object_blobsize(sigs));
}
// the following tests cases should be redone
// the following tests cases should be redone, do we really need them? -- sowle
// TODO @#@#
{
// empty ZC_sig
// v(1) + (1 + 32 + 32 + (1 + 10*32) + 32) = 99
// v(1) + 1 * (1 + 32 + 32 + (1 + 32 + v(0)+0*2*32 + 32 + 32)) = 164
sigs.clear();
sigs.emplace_back(std::move(ZC_sig()));
ASSERT_EQ(99, t_serializable_object_to_blob(sigs).size());
ASSERT_EQ(99, get_object_blobsize(sigs));
ASSERT_EQ(164, t_serializable_object_to_blob(sigs).size());
ASSERT_EQ(164, get_object_blobsize(sigs));
}
{
// 128 empty ZC_sigs
// v(128) + 128 * (1 + 32 + 32 + (v(0) + 0*32) + 32) = 12546
// v(128) + 128 * (1 + 32 + 32 + (1 + 32 + v(0)+0*2*32 + 32 + 32)) = 20866
sigs.clear();
for(size_t i = 0; i < 128; ++i)
sigs.emplace_back(std::move(ZC_sig()));
ASSERT_EQ(12546, t_serializable_object_to_blob(sigs).size());
ASSERT_EQ(12546, get_object_blobsize(sigs));
ASSERT_EQ(20866, t_serializable_object_to_blob(sigs).size());
ASSERT_EQ(20866, get_object_blobsize(sigs));
}
{
// 128 10-ring ZC_sigs
// v(128) + 128 * (1 + 32 + 32 + (v(10) + 10*32) + 32) = 53506 (97 + (v(10) + 10*32))
ZC_sig zc = AUTO_VAL_INIT(zc);
//zc.clsags_gg.r.resize(10);
// v(128) + 128 * (1 + 32 + 32 + (1 + 32 + v(10)+10*2*32 + 32 + 32)) = 102786
ZC_sig zc{};
zc.clsags_ggx.r_x.resize(10);
zc.clsags_ggx.r_g.resize(10);
sigs.clear();
for(size_t i = 0; i < 128; ++i)
sigs.emplace_back(zc);
ASSERT_EQ(53506, t_serializable_object_to_blob(sigs).size());
ASSERT_EQ(53506, get_object_blobsize(sigs));
ASSERT_EQ(102786, t_serializable_object_to_blob(sigs).size());
ASSERT_EQ(102786, get_object_blobsize(sigs));
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2019 Zano Project
// Copyright (c) 2019-2024 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -9,35 +9,27 @@ TEST(p2p_client_version, test_1)
{
using namespace tools;
// good
// good (>= 2.x since HF4)
ASSERT_TRUE(check_remote_client_version("10.101.999.28391[deadbeef31337-dirty]"));
ASSERT_TRUE(check_remote_client_version("1.1.9.237[aabcd]"));
ASSERT_TRUE(check_remote_client_version("3.0.2.7[aa00bcd]"));
ASSERT_TRUE(check_remote_client_version("1.4.2.7[aabcd]"));
ASSERT_TRUE(check_remote_client_version("1.1.2.67[88f868c]"));
ASSERT_TRUE(check_remote_client_version("1.1.2.67[88f868c]"));
ASSERT_TRUE(check_remote_client_version("1.1.2.67[26c00a8]"));
ASSERT_TRUE(check_remote_client_version("1.1.2.67[26c00a8-dirty]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.65[40ba8cd]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.63[b0f376b]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.58[14bd668]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.58[9920eb7]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.58[e0d4ad8]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.57[b77b915]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.57[7dd61ae]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.57[7dd61ae-dirty]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.57"));
ASSERT_TRUE(check_remote_client_version("2.0.0.000[a]"));
ASSERT_TRUE(check_remote_client_version("2.4.2.7[aabcd]"));
ASSERT_TRUE(check_remote_client_version("2.99.0.67[26c00a8-dirty]"));
ASSERT_TRUE(check_remote_client_version("4.0.0.0[7dd61ae-dirty]"));
ASSERT_TRUE(check_remote_client_version("5.0.0.0[7dd61ae-dirty]"));
// bad
ASSERT_FALSE(check_remote_client_version(""));
ASSERT_FALSE(check_remote_client_version(" "));
ASSERT_FALSE(check_remote_client_version(" "));
ASSERT_FALSE(check_remote_client_version(" "));
ASSERT_FALSE(check_remote_client_version("."));
ASSERT_FALSE(check_remote_client_version(".."));
ASSERT_FALSE(check_remote_client_version("..."));
ASSERT_FALSE(check_remote_client_version("1.0.999"));
@ -48,6 +40,9 @@ TEST(p2p_client_version, test_1)
ASSERT_FALSE(check_remote_client_version("1.0.40[469]"));
ASSERT_FALSE(check_remote_client_version("1.0.39[f77f0d7]"));
ASSERT_FALSE(check_remote_client_version("1.0.38[f77f0d7-dirty]"));
ASSERT_FALSE(check_remote_client_version("1.0.37[7dd61ae-dirty]"));
ASSERT_FALSE(check_remote_client_version("1.99.37[7dd61ae-dirty]"));
ASSERT_FALSE(check_remote_client_version("0.0.500[000]"));
ASSERT_FALSE(check_remote_client_version("a.1.9.237[aabcd]"));
ASSERT_FALSE(check_remote_client_version("x.0.57"));
}

View file

@ -125,48 +125,3 @@ void force_random(forced_to_pod_t& o)
// }
//
// }
TEST(validate_parse_amount_case, validate_parse_amount)
{
uint64_t res = 0;
bool r = currency::parse_amount(res, "0.0001");
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000000);
r = currency::parse_amount(res, "100.0001");
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000100000000);
r = currency::parse_amount(res, "000.0000");
ASSERT_TRUE(r);
ASSERT_EQ(res, 0);
r = currency::parse_amount(res, "0");
ASSERT_TRUE(r);
ASSERT_EQ(res, 0);
r = currency::parse_amount(res, " 100.0001 ");
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000100000000);
r = currency::parse_amount(res, " 100.0000 ");
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000000000000);
r = currency::parse_amount(res, " 100. 0000 ");
ASSERT_FALSE(r);
r = currency::parse_amount(res, "100. 0000");
ASSERT_FALSE(r);
r = currency::parse_amount(res, "100 . 0000");
ASSERT_FALSE(r);
r = currency::parse_amount(res, "100.00 00");
ASSERT_FALSE(r);
r = currency::parse_amount(res, "1 00.00 00");
ASSERT_FALSE(r);
}

View file

@ -31,26 +31,32 @@
FROM ubuntu:18.04 as build-prep
ENV DEBIAN_FRONTEND noninteractive
RUN apt update && \
apt install -y build-essential \
libicu-dev \
libz-dev \
curl \
g++ \
gcc-8 \
g++-8 \
git
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 700 --slave /usr/bin/g++ g++ /usr/bin/g++-7 && \
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
WORKDIR /root
# Lib Settings
ARG CMAKE_VERSION_DOT=3.15.5
ARG CMAKE_HASH=62e3e7d134a257e13521e306a9d3d1181ab99af8fcae66699c8f98754fc02dda
ARG CMAKE_VERSION_DOT=3.16.9
ARG CMAKE_HASH=d71eda07d6ecf3964de65a0e36d0b171565e1aced56ba9f53ca3783406b5cacf
ARG BOOST_VERSION=1_70_0
ARG BOOST_VERSION_DOT=1.70.0
ARG BOOST_HASH=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778
ARG OPENSSL_VERSION_DOT=1.1.1n
ARG OPENSSL_HASH=40dceb51a4f6a5275bde0e6bf20ef4b91bfc32ed57c0552e2e8e15463372b17a
ARG OPENSSL_VERSION_DOT=1.1.1w
ARG OPENSSL_HASH=cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8
# Environment Variables
ENV BOOST_ROOT /root/boost_${BOOST_VERSION}
@ -68,7 +74,7 @@ RUN set -ex \
# Download Boost
RUN set -ex \
&& curl -L -o boost_${BOOST_VERSION}.tar.bz2 https://downloads.sourceforge.net/project/boost/boost/${BOOST_VERSION_DOT}/boost_${BOOST_VERSION}.tar.bz2 \
&& sha256sum boost_${BOOST_VERSION}.tar.bz2 \
&& sha256sum boost_${BOOST_VERSION}.tar.bz2 \
&& echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c\
&& tar -xvf boost_${BOOST_VERSION}.tar.bz2
@ -82,10 +88,10 @@ RUN curl https://www.openssl.org/source/openssl-${OPENSSL_VERSION_DOT}.tar.gz -O
# Compile CMake
RUN set -ex \
&& mkdir /opt/cmake \
&& sh cmake-3.15.5-Linux-x86_64.sh --prefix=/opt/cmake --skip-license\
&& sh cmake-3.16.9-Linux-x86_64.sh --prefix=/opt/cmake --skip-license\
&& ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake\
&& cmake --version\
&& rm cmake-3.15.5-Linux-x86_64.sh
&& rm cmake-3.16.9-Linux-x86_64.sh
# Compile Boost
RUN set -ex \