diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..fdb74465 --- /dev/null +++ b/LICENSE @@ -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. \ No newline at end of file diff --git a/contrib/db/CMakeLists.txt b/contrib/db/CMakeLists.txt index 6f2213b4..c558ad63 100644 --- a/contrib/db/CMakeLists.txt +++ b/contrib/db/CMakeLists.txt @@ -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() diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 318237c9..376af660 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -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 diff --git a/contrib/epee/include/print_fixed_point_helper.h b/contrib/epee/include/print_fixed_point_helper.h index c652f601..91de1dd4 100644 --- a/contrib/epee/include/print_fixed_point_helper.h +++ b/contrib/epee/include/print_fixed_point_helper.h @@ -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; } } diff --git a/contrib/epee/include/serialization/keyvalue_helpers.h b/contrib/epee/include/serialization/keyvalue_helpers.h index 7dc812ad..9b5f0dcf 100644 --- a/contrib/epee/include/serialization/keyvalue_helpers.h +++ b/contrib/epee/include/serialization/keyvalue_helpers.h @@ -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(); diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h index 91f1aeda..134c477b 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization.h +++ b/contrib/epee/include/serialization/keyvalue_serialization.h @@ -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(__VA_ARGS__) +#define DOC_EXMP_AGGR(...) , epee::create_t_object(KV_MAKE_ALIAS_NAME(){__VA_ARGS__}) // Function template to create an object with forwarded constructor arguments diff --git a/contrib/epee/include/storages/portable_storage_to_json.h b/contrib/epee/include/storages/portable_storage_to_json.h index 3292c952..7230a14b 100644 --- a/contrib/epee/include/storages/portable_storage_to_json.h +++ b/contrib/epee/include/storages/portable_storage_to_json.h @@ -116,7 +116,7 @@ namespace epee template static void handle_obj_end(t_stream& strm, size_t indent) { - strm << "}"; + strm << make_indent(indent) << "}"; } template diff --git a/src/common/variant_helper.h b/src/common/variant_helper.h index 9f98cbaa..4eb12546 100644 --- a/src/common/variant_helper.h +++ b/src/common/variant_helper.h @@ -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(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() } } diff --git a/src/crypto/clsag.h b/src/crypto/clsag.h index da969d8a..924af50d 100644 --- a/src/crypto/clsag.h +++ b/src/crypto/clsag.h @@ -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 // diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index a16302f1..419cdd1c 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -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 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(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& alt_chain_block_ids, + uint64_t split_height, + const alt_chain_type& alt_chain, + const std::unordered_set& 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 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 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 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 pub_keys(abs_key_offsets.size(), null_pkey); // old bare outputs + std::vector pub_key_pointers; // old bare outputs (pointers) + vector zc_input_ring; // ZC outputs + vector 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(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(out_in_alt); - } - else - { - const txout_htlc& out_htlc = boost::get(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(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(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(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(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(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(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(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(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(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(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(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(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(o.target).key); - } - else - { - abei.outputs_pub_keys[o.amount].push_back(boost::get(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; } diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 489f4635..2c6e0bb5 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -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 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 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 > 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 > 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& 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& 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(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(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(); diff --git a/src/currency_core/blockchain_storage_basic.h b/src/currency_core/blockchain_storage_basic.h index 65c6862b..0013dc51 100644 --- a/src/currency_core/blockchain_storage_basic.h +++ b/src/currency_core/blockchain_storage_basic.h @@ -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() }; diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 80ddef17..0d3e5891 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -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() }; diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 5f4fa38f..c28a212d 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -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(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() { diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index fd33a6b8..17d6711e 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -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 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 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); diff --git a/src/currency_core/currency_format_utils_transactions.cpp b/src/currency_core/currency_format_utils_transactions.cpp index 291010a6..6c4a5a2e 100644 --- a/src/currency_core/currency_format_utils_transactions.cpp +++ b/src/currency_core/currency_format_utils_transactions.cpp @@ -398,14 +398,112 @@ namespace currency CATCH_ENTRY2(std::vector{}); } //--------------------------------------------------------------- - 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.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(tx.vin); + size_t tx_bare_inputs_count = count_type_in_variant_container(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(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 } -} \ No newline at end of file +} diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index aeaa551a..0ce53e85 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -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); diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 6cb817e0..40758a4a 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -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); diff --git a/src/gui/qt-daemon/application/mainwindow.h b/src/gui/qt-daemon/application/mainwindow.h index 074fb9f5..0f575b6b 100644 --- a/src/gui/qt-daemon/application/mainwindow.h +++ b/src/gui/qt-daemon/application/mainwindow.h @@ -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); diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 9be6a53f..0710887a 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 9be6a53f757a17403ea5798d08b577d450eb620a +Subproject commit 0710887ae3231d329092691f326d91d90662149e diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index ad4786f2..02e7b478 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -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); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index f088ccc6..9a89d043 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -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 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 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 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 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; 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 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 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 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 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 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 global_indexes; std::vector 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 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 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() }; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index c953138f..14f74dec 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 &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::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::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 &args) return true; } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::call_rpc(const std::vector& 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 &args) { CONFIRM_WITH_PASSWORD(); @@ -2240,6 +2303,55 @@ bool simple_wallet::update_asset(const std::vector &args) return true; } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::transfer_asset_ownership(const std::vector& 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 &args) { CONFIRM_WITH_PASSWORD(); @@ -2492,7 +2604,7 @@ bool simple_wallet::sweep_below(const std::vector &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); } } diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 0b0843d0..5f260433 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -91,12 +91,13 @@ namespace currency bool tor_enable(const std::vector &args); bool tor_disable(const std::vector &args); bool deploy_new_asset(const std::vector &args); + bool call_rpc(const std::vector& args); bool add_custom_asset_id(const std::vector &args); bool remove_custom_asset_id(const std::vector &args); bool emit_asset(const std::vector &args); bool burn_asset(const std::vector &args); bool update_asset(const std::vector &args); - + bool transfer_asset_ownership(const std::vector& args); //---------------------------------------------------------------------------------------------------- bool generate_ionic_swap_proposal(const std::vector &args); bool get_ionic_swap_proposal_info(const std::vector &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); diff --git a/src/version.h.in b/src/version.h.in index 6819f5d7..26d965ed 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -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 "]" diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index d5720fe3..e9a8a8f1 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3813,40 +3813,76 @@ bool wallet2::balance(std::list& 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 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(tx.vin[i]).key_offsets.size() - 1; + //mx = boost::get(tx.vin[i]).key_offsets.size() - 1; } else if (tx.vin[i].type() == typeid(txin_to_key)) { amount = boost::get(tx.vin[i]).amount; - mx = boost::get(tx.vin[i]).key_offsets.size() - 1; + //mx = boost::get(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& 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& 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& 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& 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(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 (...) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 725c2c42..2fa7601b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -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& amounts); void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector& 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& 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& 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& selected_indexes); //PoS diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index bfab00d5..90dbf48c 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -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 diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 663fb080..b9a5ddb9 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -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 { diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 10d2a399..9efaf197 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -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; diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 86a0039a..9ea31394 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -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); diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 02287be5..7f3ee253 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -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; } diff --git a/src/wallet/wallets_manager.h b/src/wallet/wallets_manager.h index 014ea3ef..01c62062 100644 --- a/src/wallet/wallets_manager.h +++ b/src/wallet/wallets_manager.h @@ -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); diff --git a/tests/core_tests/chain_switch_1.cpp b/tests/core_tests/chain_switch_1.cpp index a579515f..2c830dd6 100644 --- a/tests/core_tests/chain_switch_1.cpp +++ b/tests/core_tests/chain_switch_1.cpp @@ -422,6 +422,15 @@ bool chain_switching_when_gindex_spent_in_both_chains::generate(std::vector 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 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({ 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& 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& 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 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& events, c std::map 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.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 &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 &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( 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(boost::get(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()); - 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 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(boost::get(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; diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 087e0c3a..d8d49100 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -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 &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& events, const crypto::hash& last_block_id, const currency::txin_to_key& in_t_k, const crypto::hash& hash_for_sig, const std::vector &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(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; diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index aad760ea..010c2230 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -26,7 +26,7 @@ namespace const command_line::arg_descriptor arg_play_test_data ("play-test-data", ""); const command_line::arg_descriptor arg_generate_and_play_test_data ("generate-and-play-test-data", ""); const command_line::arg_descriptor arg_test_transactions ("test-transactions", ""); - const command_line::arg_descriptor arg_run_single_test ("run-single-test", "" ); + const command_line::arg_descriptor arg_run_single_test ("run-single-test", " TEST_NAME -- name of a single test to run, HF -- specific hardfork id to run the test for" ); const command_line::arg_descriptor arg_enable_debug_asserts ("enable-debug-asserts", "" ); const command_line::arg_descriptor 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 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 diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 173bb2b9..7ce86a5b 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -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(res_tx.extra); @@ -1221,7 +1221,7 @@ bool hard_fork_2_alias_update_using_old_tx::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::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; diff --git a/tests/core_tests/pos_block_builder.cpp b/tests/core_tests/pos_block_builder.cpp index c96575b1..8d394d0e 100644 --- a/tests/core_tests/pos_block_builder.cpp +++ b/tests/core_tests/pos_block_builder.cpp @@ -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(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 { diff --git a/tests/core_tests/pos_block_builder.h b/tests/core_tests/pos_block_builder.h index 46c49900..fdf7a297 100644 --- a/tests/core_tests/pos_block_builder.h +++ b/tests/core_tests/pos_block_builder.h @@ -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 {}; diff --git a/tests/core_tests/pos_validation.cpp b/tests/core_tests/pos_validation.cpp index 4f444e69..28f66b6a 100644 --- a/tests/core_tests/pos_validation.cpp +++ b/tests/core_tests/pos_validation.cpp @@ -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& events) @@ -871,23 +871,26 @@ bool pos_altblocks_validation::generate(std::vector& events) c std::list 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(stake_tx.vout[i]).amount >boost::get( 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(stake_tx.vout[i]).amount > boost::get( 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& 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& 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()), 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(blk_3aa.miner_tx.signatures[0]).y0.m_u64[1] = 5; // invalidate signature + else + boost::get(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& 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()), 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 diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index e704855f..3fa4b2d7 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -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 +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 + bool connect(t_a ta, t_b tb, t_c tc) { return true; } + + template + 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 +bool invoke_text_json_for_rpc(t_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; +} + +template +bool invoke_text_json_for_wallet(std::shared_ptr 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 +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 m_cprotocol(c, nullptr); + nodetool::node_server > 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& 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& events) +{ + bool r = false; + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX); + std::shared_ptr 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& 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 - bool connect(t_a ta, t_b tb, t_c tc) { return true; } - - template - 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 -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" diff --git a/tests/core_tests/wallet_rpc_tests.h b/tests/core_tests/wallet_rpc_tests.h index aa6e9b5e..0d939778 100644 --- a/tests/core_tests/wallet_rpc_tests.h +++ b/tests/core_tests/wallet_rpc_tests.h @@ -29,6 +29,14 @@ struct wallet_rpc_transfer : public wallet_test bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; +struct wallet_rpc_alias_tests : public wallet_test +{ + wallet_rpc_alias_tests(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; + + /* Tests to make sure api for exchanges didn't change after HF4(Zarcanum) testing api: get_recent_txs_and_info, make_integrated_address, diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index bfadc1fb..ef10bf61 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -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); diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 9515df91..546fff99 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -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 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 scalars(10000); LOG_PRINT_L0("Running " << scalars.size() << " sc_invert tests..."); diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 58fbd85f..1055bfca 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -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); } diff --git a/tests/unit_tests/amounts_tests.cpp b/tests/unit_tests/amounts_tests.cpp index 300b92a7..24aa5b84 100644 --- a/tests/unit_tests/amounts_tests.cpp +++ b/tests/unit_tests/amounts_tests.cpp @@ -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); +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unit_tests/basic_struct_packing.cpp b/tests/unit_tests/basic_struct_packing.cpp index 41b16705..86896933 100644 --- a/tests/unit_tests/basic_struct_packing.cpp +++ b/tests/unit_tests/basic_struct_packing.cpp @@ -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)); } } diff --git a/tests/unit_tests/p2p_client_version.cpp b/tests/unit_tests/p2p_client_version.cpp index 3761e36a..183f6d36 100644 --- a/tests/unit_tests/p2p_client_version.cpp +++ b/tests/unit_tests/p2p_client_version.cpp @@ -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")); } diff --git a/tests/unit_tests/test_format_utils.cpp b/tests/unit_tests/test_format_utils.cpp index 0e277222..f12c149f 100644 --- a/tests/unit_tests/test_format_utils.cpp +++ b/tests/unit_tests/test_format_utils.cpp @@ -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); -} diff --git a/utils/docker/Dockerfile b/utils/docker/Dockerfile index 580c2a31..4394a6db 100644 --- a/utils/docker/Dockerfile +++ b/utils/docker/Dockerfile @@ -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 \