From 7606c6996158e65b4eb2cc75f68be9076933fb86 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 18 Apr 2025 06:18:57 +0300 Subject: [PATCH 01/65] p2p: COMMAND_REQUEST_ANONYMIZED_PEERS (WIP) --- src/connectivity_tool/conn_tool.cpp | 150 +--------------------------- src/p2p/net_node.h | 8 +- src/p2p/net_node.inl | 35 ++----- src/p2p/p2p_protocol_defs.h | 61 +++-------- 4 files changed, 30 insertions(+), 224 deletions(-) diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp index 2e813674..d33d65ce 100644 --- a/src/connectivity_tool/conn_tool.cpp +++ b/src/connectivity_tool/conn_tool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2024 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -57,8 +57,6 @@ namespace const command_line::arg_descriptor arg_generate_genesis ("generate-genesis", "Generate genesis coinbase based on config file"); const command_line::arg_descriptor arg_genesis_split_amount ( "genesis-split-amount", "Set split amount for generating genesis block"); const command_line::arg_descriptor arg_get_info_flags ( "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", ""); - const command_line::arg_descriptor arg_set_peer_log_level ( "set-peer-log-level", "Set log level for remote peer"); - const command_line::arg_descriptor arg_download_peer_log ( "download-peer-log", "Download log from remote peer [,]"); const command_line::arg_descriptor arg_do_consloe_log ( "do-console-log", "Tool generates debug console output(debug purposes)"); const command_line::arg_descriptor arg_generate_integrated_address ( "generate-integrated-address", "Tool create integrated address from simple address and payment_id"); const command_line::arg_descriptor arg_pack_file ("pack-file", "perform gzip-packing and calculate hash for a given file"); @@ -923,152 +921,6 @@ bool invoke_debug_command(po::variables_map& vm, const crypto::secret_key& sk, n return net_utils::invoke_remote_command2(command_t::ID, req, rsp, transport); } //--------------------------------------------------------------------------------------------------------------- -bool handle_set_peer_log_level(po::variables_map& vm) -{ - crypto::secret_key sk = AUTO_VAL_INIT(sk); - if (!get_private_key(sk, vm)) - { - std::cout << "ERROR: secret key error" << ENDL; - return false; - } - - int64_t log_level = command_line::get_arg(vm, arg_set_peer_log_level); - if (log_level < LOG_LEVEL_0 || log_level > LOG_LEVEL_MAX) - { - std::cout << "Error: invalid log level value: " << log_level << ENDL; - return false; - } - - net_utils::levin_client2 transport; - peerid_type peer_id = 0; - - COMMAND_SET_LOG_LEVEL::request req = AUTO_VAL_INIT(req); - req.new_log_level = log_level; - - COMMAND_SET_LOG_LEVEL::response rsp = AUTO_VAL_INIT(rsp); - if (!invoke_debug_command(vm, sk, transport, peer_id, req, rsp)) - { - std::cout << "ERROR: invoking COMMAND_SET_LOG_LEVEL failed" << ENDL; - return false; - } - - std::cout << "OK! Log level changed: " << rsp.old_log_level << " -> " << rsp.current_log_level << ENDL; - - return true; -} -//--------------------------------------------------------------------------------------------------------------- -bool handle_download_peer_log(po::variables_map& vm) -{ - crypto::secret_key sk = AUTO_VAL_INIT(sk); - if (!get_private_key(sk, vm)) - { - std::cout << "ERROR: secret key error" << ENDL; - return false; - } - - int64_t start_offset_signed = 0; - int64_t count = -1; - - std::string arg_str = command_line::get_arg(vm, arg_download_peer_log); - size_t comma_pos = arg_str.find(','); - if (comma_pos != std::string::npos) - { - // count is specified - if (!epee::string_tools::string_to_num_fast(arg_str.substr(comma_pos + 1), count) || count < 0) - { - std::cout << "ERROR: invalid argument: " << arg_str << ENDL; - return false; - } - arg_str.erase(comma_pos); - } - if (!epee::string_tools::string_to_num_fast(arg_str, start_offset_signed) || start_offset_signed < 0) - { - std::cout << "ERROR: couldn't parse start_offset: " << arg_str << ENDL; - return false; - } - uint64_t start_offset = static_cast(start_offset_signed); - - net_utils::levin_client2 transport; - peerid_type peer_id = 0; - - COMMAND_REQUEST_LOG::request req = AUTO_VAL_INIT(req); - COMMAND_REQUEST_LOG::response rsp = AUTO_VAL_INIT(rsp); - if (!invoke_debug_command(vm, sk, transport, peer_id, req, rsp) || !rsp.error.empty()) - { - std::cout << "ERROR: invoking COMMAND_REQUEST_LOG failed: " << rsp.error << ENDL; - return false; - } - - std::cout << "Current log level: " << rsp.current_log_level << ENDL; - std::cout << "Current log size: " << rsp.current_log_size << ENDL; - - if (start_offset == 0 && count == 0) - return true; // a caller wanted to just get the info, end of story - - if (start_offset >= rsp.current_log_size) - { - std::cout << "ERROR: invalid start offset: " << start_offset << ", log size: " << rsp.current_log_size << ENDL; - return false; - } - - std::cout << "Downloading..." << ENDL; - - std::string local_filename = tools::get_default_data_dir() + "/log_" + epee::string_tools::num_to_string_fast(peer_id) + ".log"; - std::ofstream log{ local_filename, std::ifstream::binary }; - if (!log) - { - std::cout << "Couldn't open " << local_filename << " for writing." << ENDL; - return false; - } - - const uint64_t chunk_size = 1024 * 1024 * 5; - uint64_t end_offset = start_offset; - while (true) - { - req.log_chunk_offset = end_offset; - req.log_chunk_size = std::min(chunk_size, rsp.current_log_size - req.log_chunk_offset); - - if (count > 0) - { - uint64_t bytes_left = count + start_offset - end_offset; - req.log_chunk_size = std::min(req.log_chunk_size, bytes_left); - } - - if (req.log_chunk_size == 0) - break; - - std::this_thread::sleep_for(std::chrono::seconds(1)); - - if (!invoke_debug_command(vm, sk, transport, peer_id, req, rsp) || !rsp.error.empty()) - { - std::cout << "ERROR: invoking COMMAND_REQUEST_LOG failed: " << rsp.error << ENDL; - return false; - } - - if (!epee::zlib_helper::unpack(rsp.log_chunk)) - { - std::cout << "ERROR: zip unpack failed" << ENDL; - return false; - } - - if (rsp.log_chunk.size() != req.log_chunk_size) - { - std::cout << "ERROR: unpacked size: " << rsp.log_chunk.size() << ", requested: " << req.log_chunk_size << ENDL; - return false; - } - - log.write(rsp.log_chunk.c_str(), rsp.log_chunk.size()); - - end_offset += req.log_chunk_size; - - std::cout << end_offset - start_offset << " bytes downloaded" << ENDL; - } - - std::cout << "Remote log from offset " << start_offset << " to offset " << end_offset << " (" << end_offset - start_offset << " bytes) " << - "was successfully downloaded to " << local_filename << ENDL; - - return true; -} bool handle_generate_integrated_address(po::variables_map& vm) diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 6cb58abb..5f009059 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -142,8 +142,7 @@ namespace nodetool HANDLE_INVOKE_T2(COMMAND_REQUEST_STAT_INFO, &node_server::handle_get_stat_info) HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state) HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id) - HANDLE_INVOKE_T2(COMMAND_REQUEST_LOG, &node_server::handle_request_log) - HANDLE_INVOKE_T2(COMMAND_SET_LOG_LEVEL, &node_server::handle_set_log_level) + HANDLE_INVOKE_T2(COMMAND_REQUEST_ANONYMIZED_PEERS, &node_server::handle_request_anonymized_peers) } #endif CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&) @@ -158,8 +157,7 @@ namespace nodetool int handle_get_stat_info(int command, typename COMMAND_REQUEST_STAT_INFO::request& arg, typename COMMAND_REQUEST_STAT_INFO::response& rsp, p2p_connection_context& context); int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context); int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context); - int handle_request_log(int command, COMMAND_REQUEST_LOG::request& arg, COMMAND_REQUEST_LOG::response& rsp, p2p_connection_context& context); - int handle_set_log_level(int command, COMMAND_SET_LOG_LEVEL::request& arg, COMMAND_SET_LOG_LEVEL::response& rsp, p2p_connection_context& context); + int handle_request_anonymized_peers(int command, COMMAND_REQUEST_ANONYMIZED_PEERS::request& req, COMMAND_REQUEST_ANONYMIZED_PEERS::response& rsp, p2p_connection_context& context); private: #endif bool init_config(); diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 1bb27fbb..1b398d71 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -1196,7 +1196,7 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - int node_server::handle_request_log(int command, COMMAND_REQUEST_LOG::request& req, COMMAND_REQUEST_LOG::response& rsp, p2p_connection_context& context) + int node_server::handle_request_anonymized_peers(int command, COMMAND_REQUEST_ANONYMIZED_PEERS::request& req, COMMAND_REQUEST_ANONYMIZED_PEERS::response& rsp, p2p_connection_context& context) { if (!check_trust(req.tr)) { @@ -1204,30 +1204,15 @@ namespace nodetool return 1; } - rsp.current_log_level = static_cast(log_space::get_set_log_detalisation_level()); - tools::get_log_chunk_gzipped(req.log_chunk_offset, req.log_chunk_size, rsp.log_chunk, rsp.error); - rsp.current_log_size = tools::get_log_file_size(); + m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cn_context) + { + auto& el = rsp.peers.emplace_back(); + el.inbound = cn_context.m_is_income; + el.time_started = cn_context.m_started; + return true; + }); - return 1; - } - //----------------------------------------------------------------------------------- - template - int node_server::handle_set_log_level(int command, COMMAND_SET_LOG_LEVEL::request& req, COMMAND_SET_LOG_LEVEL::response& rsp, p2p_connection_context& context) - { - if (!check_trust(req.tr)) - { - drop_connection(context); - return 1; - } - - rsp.old_log_level = static_cast(log_space::get_set_log_detalisation_level()); - log_space::get_set_log_detalisation_level(true, static_cast(req.new_log_level)); - rsp.current_log_level = static_cast(log_space::get_set_log_detalisation_level()); - - if (rsp.old_log_level != rsp.current_log_level) - { - LOG_PRINT_CC(context, "log level changed by debug command: " << rsp.old_log_level << " -> " << rsp.current_log_level, LOG_LEVEL_0); - } + std::shuffle(rsp.peers.begin(), rsp.peers.end(), crypto::uniform_random_bit_generator()); return 1; } diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index fe1225f4..f31d5329 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -402,65 +402,36 @@ namespace nodetool /************************************************************************/ /* */ /************************************************************************/ - struct COMMAND_REQUEST_LOG + struct COMMAND_REQUEST_ANONYMIZED_PEERS { - const static int ID = P2P_COMMANDS_POOL_BASE + 7; + const static int ID = P2P_COMMANDS_POOL_BASE + 100; struct request { proof_of_trust tr; - uint64_t log_chunk_offset; - uint64_t log_chunk_size; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tr) - KV_SERIALIZE(log_chunk_offset) - KV_SERIALIZE(log_chunk_size) END_KV_SERIALIZE_MAP() }; + struct anonymized_peer_info + { + uint64_t time_started; + bool inbound; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(time_started) + KV_SERIALIZE(inbound) + END_KV_SERIALIZE_MAP() + }; + struct response { - int64_t current_log_level; - uint64_t current_log_size; - std::string error; - std::string log_chunk; + std::vector peers; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(current_log_level) - KV_SERIALIZE(current_log_size) - KV_SERIALIZE(error) - KV_SERIALIZE(log_chunk) - END_KV_SERIALIZE_MAP() - }; - }; - - /************************************************************************/ - /* */ - /************************************************************************/ - struct COMMAND_SET_LOG_LEVEL - { - const static int ID = P2P_COMMANDS_POOL_BASE + 8; - - struct request - { - proof_of_trust tr; - int64_t new_log_level; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(tr) - KV_SERIALIZE(new_log_level) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - int64_t old_log_level; - int64_t current_log_level; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(old_log_level) - KV_SERIALIZE(current_log_level) + KV_SERIALIZE(peers) END_KV_SERIALIZE_MAP() }; }; From 36d14dbc99d2b3da0a59623c6df7ce65a42f5de4 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 18 Apr 2025 15:09:16 +0300 Subject: [PATCH 02/65] conn_tool: get-anonymized-peers command-line option implemented --- src/connectivity_tool/conn_tool.cpp | 46 +++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp index d33d65ce..bb026c90 100644 --- a/src/connectivity_tool/conn_tool.cpp +++ b/src/connectivity_tool/conn_tool.cpp @@ -57,6 +57,7 @@ namespace const command_line::arg_descriptor arg_generate_genesis ("generate-genesis", "Generate genesis coinbase based on config file"); const command_line::arg_descriptor arg_genesis_split_amount ( "genesis-split-amount", "Set split amount for generating genesis block"); const command_line::arg_descriptor arg_get_info_flags ( "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", ""); + const command_line::arg_descriptor arg_get_anonymized_peers( "get-anonymized-peers", "Retrieves anonymized peers connected to the specified peer."); const command_line::arg_descriptor arg_do_consloe_log ( "do-console-log", "Tool generates debug console output(debug purposes)"); const command_line::arg_descriptor arg_generate_integrated_address ( "generate-integrated-address", "Tool create integrated address from simple address and payment_id"); const command_line::arg_descriptor arg_pack_file ("pack-file", "perform gzip-packing and calculate hash for a given file"); @@ -744,23 +745,23 @@ bool get_private_key(crypto::secret_key& pk, po::variables_map& vm) } else { - key_str = get_password("Enter maintain private key:"); + key_str = get_password("Enter maintenance private key:"); } if(!string_tools::hex_to_pod(key_str, pk)) { - std::cout << "ERROR: wrong secret key set" << ENDL; + std::cout << "ERROR: incorrect private key entered" << ENDL; return false; } crypto::public_key pubkey = AUTO_VAL_INIT(pubkey); if(!crypto::secret_key_to_public_key(pk, pubkey)) { - std::cout << "ERROR: wrong secret key set(secret_key_to_public_key failed)" << ENDL; + std::cout << "ERROR: wrong private key (secret_key_to_public_key failed)" << ENDL; return false; } if( pubkey != tools::get_public_key_from_string(P2P_MAINTAINERS_PUB_KEY)) { - std::cout << "ERROR: wrong secret key set(public keys not match)" << ENDL; + std::cout << "ERROR: wrong pritvate key (public key missmatch)" << ENDL; return false; } return true; @@ -921,8 +922,34 @@ bool invoke_debug_command(po::variables_map& vm, const crypto::secret_key& sk, n return net_utils::invoke_remote_command2(command_t::ID, req, rsp, transport); } //--------------------------------------------------------------------------------------------------------------- +bool handle_get_anonymized_peers(po::variables_map& vm) +{ + crypto::secret_key sk{}; + if (!get_private_key(sk, vm)) + { + std::cout << "ERROR: secret key error" << ENDL; + return false; + } + net_utils::levin_client2 transport; + peerid_type peer_id = 0; + COMMAND_REQUEST_ANONYMIZED_PEERS::request req{}; + + COMMAND_REQUEST_ANONYMIZED_PEERS::response rsp{}; + if (!invoke_debug_command(vm, sk, transport, peer_id, req, rsp)) + { + std::cout << "ERROR: invoking COMMAND_REQUEST_ANONYMIZED_PEERS failed" << ENDL; + return false; + } + + std::cout << "Success." << ENDL << ENDL; + + std::cout << epee::serialization::store_t_to_json(rsp); + + return true; +} +//--------------------------------------------------------------------------------------------------------------- bool handle_generate_integrated_address(po::variables_map& vm) { std::string add_and_payment_id = command_line::get_arg(vm, arg_generate_integrated_address); @@ -1175,8 +1202,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_genesis_split_amount); command_line::add_arg(desc_params, arg_get_info_flags); command_line::add_arg(desc_params, arg_log_journal_len); - command_line::add_arg(desc_params, arg_set_peer_log_level); - command_line::add_arg(desc_params, arg_download_peer_log); + command_line::add_arg(desc_params, arg_get_anonymized_peers); command_line::add_arg(desc_params, arg_do_consloe_log); command_line::add_arg(desc_params, arg_generate_integrated_address); command_line::add_arg(desc_params, arg_pack_file); @@ -1244,13 +1270,9 @@ int main(int argc, char* argv[]) { return generate_genesis(command_line::get_arg(vm, arg_generate_genesis), 10000000000000000) ? EXIT_SUCCESS : EXIT_FAILURE; } - else if (command_line::has_arg(vm, arg_set_peer_log_level)) + else if (command_line::has_arg(vm, arg_get_anonymized_peers) && command_line::get_arg(vm, arg_get_anonymized_peers)) { - return handle_set_peer_log_level(vm) ? EXIT_SUCCESS : EXIT_FAILURE; - } - else if (command_line::has_arg(vm, arg_download_peer_log)) - { - return handle_download_peer_log(vm) ? EXIT_SUCCESS : EXIT_FAILURE; + return handle_get_anonymized_peers(vm) ? EXIT_SUCCESS : EXIT_FAILURE; } else if (command_line::has_arg(vm, arg_generate_integrated_address)) { From 166b683295604905f034554f4dde8eafd97eca7e Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 17 Jun 2025 17:06:16 +0400 Subject: [PATCH 03/65] tiny format tweak --- src/currency_core/currency_basic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 63f94212..c73660f6 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -1091,7 +1091,7 @@ namespace currency BOOST_SERIALIZE(attachment) BOOST_END_VERSION_UNDER(1) BOOST_SERIALIZE(proofs) - END_BOOST_SERIALIZATION() + END_BOOST_SERIALIZATION() }; From 90a4a68eb58115266d2ae69f96b5f3b120e67922 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 18 Jun 2025 22:45:28 +0400 Subject: [PATCH 04/65] added sanitize_utf8 to invoke() in plain_wallet --- src/wallet/plain_wallet_api.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index d242c760..943cd133 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -605,6 +605,7 @@ namespace plain_wallet PLAIN_WALLET_BEGIN_TRY_ENTRY(); GET_INSTANCE_PTR(inst_ptr); return inst_ptr->gwm.invoke(h, params); + tools::sanitize_utf8(params); PLAIN_WALLET_CATCH(); } From 2bab9177003576a9c25b7788880d8157e8053a83 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 19 Jun 2025 14:35:11 +0400 Subject: [PATCH 05/65] fixed typo --- src/wallet/plain_wallet_api.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 943cd133..eceb536e 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -604,8 +604,9 @@ namespace plain_wallet { PLAIN_WALLET_BEGIN_TRY_ENTRY(); GET_INSTANCE_PTR(inst_ptr); - return inst_ptr->gwm.invoke(h, params); - tools::sanitize_utf8(params); + std::string res = inst_ptr->gwm.invoke(h, params); + tools::sanitize_utf8(res); + return res; PLAIN_WALLET_CATCH(); } From ab01ce4fd6ae4b1933f833bcaaff7b694e3db556 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 19 Jun 2025 12:55:44 +0200 Subject: [PATCH 06/65] ui update (PR 150) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 5bb46f99..9531b14e 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 5bb46f99d5554d0c80752833a6bfd7ef4458174b +Subproject commit 9531b14e8443dd78411f84ed82fe0496dd9a3895 From 430cbffd25e487e9f83e89b2612a2c71297d0acb Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 19 Jun 2025 17:40:47 +0200 Subject: [PATCH 07/65] wallet rpc: WALLET_RPC_ERROR_CODE_GENERIC_ERROR (-9) added --- src/wallet/wallet_rpc_server.cpp | 10 +++++----- src/wallet/wallet_rpc_server_error_codes.h | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index f49a5d3d..26d9a81a 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -38,25 +38,25 @@ POP_VS_WARNINGS catch (const tools::error::daemon_busy& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY; \ - er.message = std::string("WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY") + e.what(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY: ") + e.what(); \ return false; \ } \ catch (const tools::error::not_enough_money& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY; \ - er.message = std::string("WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY") + e.error_code(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY: ") + e.what(); \ return false; \ } \ catch (const tools::error::wallet_error& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ - er.message = e.error_code(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR: ") + e.what(); \ return false; \ } \ catch (const std::exception& e) \ { \ - er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ - er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR: ") + e.what(); \ + er.code = WALLET_RPC_ERROR_CODE_GENERIC_ERROR; \ + er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_ERROR: ") + e.what(); \ return false; \ } \ catch (...) \ diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h index 676b64ea..8ef2af3f 100644 --- a/src/wallet/wallet_rpc_server_error_codes.h +++ b/src/wallet/wallet_rpc_server_error_codes.h @@ -15,3 +15,4 @@ #define WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT -6 #define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -7 #define WALLET_RPC_ERROR_CODE_WRONG_MIXINS_FOR_AUDITABLE_WALLET -8 +#define WALLET_RPC_ERROR_CODE_GENERIC_ERROR -9 From 1b0f64176d1660994674c50bb0299eb325d58c0d Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 19 Jun 2025 17:42:00 +0200 Subject: [PATCH 08/65] wallet rpc: tx_comment is now put into tx's extra for consistency with wallet_manager's approach --- src/wallet/wallet_rpc_server.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 26d9a81a..f9ba3b1e 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -73,11 +73,11 @@ void exception_handler() namespace tools { //----------------------------------------------------------------------------------- - const command_line::arg_descriptor wallet_rpc_server::arg_rpc_bind_port ("rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server"); - const command_line::arg_descriptor wallet_rpc_server::arg_rpc_bind_ip ("rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1"); - const command_line::arg_descriptor wallet_rpc_server::arg_miner_text_info ( "miner-text-info", "Wallet password"); - const command_line::arg_descriptor wallet_rpc_server::arg_deaf_mode ( "deaf", "Put wallet into 'deaf' mode make it ignore any rpc commands(usable for safe PoS mining)"); - const command_line::arg_descriptor wallet_rpc_server::arg_jwt_secret("jwt-secret", "Enables JWT auth over secret string provided"); + const command_line::arg_descriptor wallet_rpc_server::arg_rpc_bind_port ("rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server"); + const command_line::arg_descriptor wallet_rpc_server::arg_rpc_bind_ip ("rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1"); + const command_line::arg_descriptor wallet_rpc_server::arg_miner_text_info ("miner-text-info", "Wallet password"); + const command_line::arg_descriptor wallet_rpc_server::arg_deaf_mode ("deaf", "Put wallet into 'deaf' mode make it ignore any rpc commands(usable for safe PoS mining)"); + const command_line::arg_descriptor wallet_rpc_server::arg_jwt_secret ("jwt-secret", "Enables JWT auth over secret string provided"); void wallet_rpc_server::init_options(boost::program_options::options_description& desc) { @@ -428,7 +428,7 @@ namespace tools return true; WALLET_RPC_CATCH_TRY_ENTRY(); } - + //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx) { WALLET_RPC_BEGIN_TRY_ENTRY(); @@ -525,7 +525,7 @@ namespace tools { currency::tx_comment comment = AUTO_VAL_INIT(comment); comment.comment = req.comment; - attachments.push_back(comment); + extra.push_back(comment); } if (req.push_payer && !wrap) From 46eab648341ea968b2a4d01806ba6e0e98cfd2cb Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 20 Jun 2025 01:30:00 +0200 Subject: [PATCH 09/65] rename: encrypt_attachments() -> encrypt_payload_items() + test gen_wallet_decrypted_attachments -> gen_wallet_decrypted_payload_items improved (tx_comment put in extra) --- src/currency_core/currency_format_utils.cpp | 8 +++--- src/currency_core/currency_format_utils.h | 4 +-- tests/core_tests/chaingen.h | 29 +++++++++------------ tests/core_tests/chaingen_main.cpp | 2 +- tests/core_tests/wallet_tests.cpp | 24 +++++++++-------- tests/core_tests/wallet_tests.h | 4 +-- 6 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index c8ad89d7..8eb0412d 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -1784,7 +1784,7 @@ namespace currency } //--------------------------------------------------------------- - void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation) + void encrypt_payload_items(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation) { bool r = crypto::generate_key_derivation(destination_addr.view_public_key, tx_random_key.sec, derivation); CHECK_AND_ASSERT_MES(r, void(), "failed to generate_key_derivation"); @@ -1816,10 +1816,10 @@ namespace currency } } //--------------------------------------------------------------- - void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key) + void encrypt_payload_items(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key) { crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); - return encrypt_attachments(tx, sender_keys, destination_addr, tx_random_key, derivation); + return encrypt_payload_items(tx, sender_keys, destination_addr, tx_random_key, derivation); } //--------------------------------------------------------------- void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x) @@ -2582,7 +2582,7 @@ namespace currency //include offers if need tx.attachment = attachments; - encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, gen_context.tx_key, result.derivation); + encrypt_payload_items(tx, sender_account_keys, crypt_destination_addr, gen_context.tx_key, result.derivation); } else { diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index b3cfbeed..62cece1e 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -396,8 +396,8 @@ namespace currency bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time); crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys); bool decrypt_payload_items(bool is_income, const transaction& tx, const account_keys& acc_keys, std::vector& decrypted_items); - void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation); - void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key); + void encrypt_payload_items(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation); + void encrypt_payload_items(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key); bool is_derivation_used_to_encrypt(const transaction& tx, const crypto::key_derivation& derivation); bool is_address_like_wrapped(const std::string& addr); void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x); diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index e4286057..6ea4cc90 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -1356,12 +1356,14 @@ void append_vector_by_another_vector(U& dst, const V& src) #define MAKE_TX_LIST_START_WITH_ATTACHS(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD, ATTACHS) MAKE_TX_LIST_START_MIX_ATTR(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD, CURRENCY_TO_KEY_OUT_RELAXED, ATTACHS) -#define MAKE_TX_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, FEE, HEAD, ATTACH) \ - PRINT_EVENT_N(EVENTS); \ - currency::transaction TX_VAR = AUTO_VAL_INIT(TX_VAR); \ - CHECK_AND_ASSERT_MES(construct_tx_to_key(generator.get_hardforks(), EVENTS, TX_VAR, HEAD, FROM, TO, AMOUNT, FEE, 0, generator.last_tx_generated_secret_key, CURRENCY_TO_KEY_OUT_RELAXED, empty_extra, ATTACH), false, "construct_tx_to_key failed"); \ +#define MAKE_TX_EXTRA_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, FEE, HEAD, EXTRA, ATTACH) \ + PRINT_EVENT_N(EVENTS); \ + currency::transaction TX_VAR{}; \ + CHECK_AND_ASSERT_MES(construct_tx_to_key(generator.get_hardforks(), EVENTS, TX_VAR, HEAD, FROM, TO, AMOUNT, FEE, 0, generator.last_tx_generated_secret_key, CURRENCY_TO_KEY_OUT_RELAXED, EXTRA, ATTACH), false, "construct_tx_to_key failed"); \ EVENTS.push_back(TX_VAR) +#define MAKE_TX_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, FEE, HEAD, ATTACH) MAKE_TX_EXTRA_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, FEE, HEAD, empty_extra, ATTACH) + #define MAKE_TX_ATTACH(EVENTS, TX_VAR, FROM, TO, AMOUNT, HEAD, ATTACH) MAKE_TX_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, HEAD, ATTACH) #define MAKE_MINER_TX_AND_KEY_MANUALLY(TX, PREV_BLOCK, P_KEYPAIR) \ @@ -1417,30 +1419,25 @@ void append_vector_by_another_vector(U& dst, const V& src) #define MAKE_TEST_WALLET_TX(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC) \ PRINT_EVENT_N(EVENTS_VEC); \ - transaction TX_VAR = AUTO_VAL_INIT(TX_VAR); \ + transaction TX_VAR{}; \ { \ std::vector destinations(1, tx_destination_entry(MONEY, DEST_ACC.get_public_address())); \ WLT_WAR->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, std::vector(), std::vector(), TX_VAR); \ } \ EVENTS_VEC.push_back(TX_VAR) -#define MAKE_TEST_WALLET_TX_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, ATTACH) \ +#define MAKE_TEST_WALLET_TX_EXTRA_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, EXTRA, ATTACH) \ PRINT_EVENT_N(EVENTS_VEC); \ - transaction TX_VAR = AUTO_VAL_INIT(TX_VAR); \ + transaction TX_VAR{}; \ { \ std::vector destinations(1, tx_destination_entry(MONEY, DEST_ACC.get_public_address())); \ - WLT_WAR->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, std::vector(), ATTACH, TX_VAR); \ + WLT_WAR->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, EXTRA, ATTACH, TX_VAR); \ } \ EVENTS_VEC.push_back(TX_VAR) -#define MAKE_TEST_WALLET_TX_EXTRA(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, EXTRA) \ - PRINT_EVENT_N(EVENTS_VEC); \ - transaction TX_VAR = AUTO_VAL_INIT(TX_VAR); \ - { \ - std::vector destinations(1, tx_destination_entry(MONEY, DEST_ACC.get_public_address())); \ - WLT_WAR->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, EXTRA, std::vector(), TX_VAR); \ - } \ - EVENTS_VEC.push_back(TX_VAR) +#define MAKE_TEST_WALLET_TX_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, ATTACH) MAKE_TEST_WALLET_TX_EXTRA_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, empty_extra, ATTACH) + +#define MAKE_TEST_WALLET_TX_EXTRA(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, EXTRA) MAKE_TEST_WALLET_TX_EXTRA_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, EXTRA, empty_attachment) #define CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(WLT_WAR, TOTAL_BALANCE) \ if (!check_balance_via_wallet(*WLT_WAR.get(), #WLT_WAR, TOTAL_BALANCE)) \ diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 38952ed1..cd886555 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1077,7 +1077,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_wallet_oversized_payment_id); GENERATE_AND_PLAY(gen_wallet_transfers_and_outdated_unconfirmed_txs); GENERATE_AND_PLAY(gen_wallet_transfers_and_chain_switch); - GENERATE_AND_PLAY(gen_wallet_decrypted_attachments); + GENERATE_AND_PLAY(gen_wallet_decrypted_payload_items); GENERATE_AND_PLAY_HF(gen_wallet_alias_and_unconfirmed_txs, "3-*"); GENERATE_AND_PLAY_HF(gen_wallet_alias_via_special_wallet_funcs, "3-*"); GENERATE_AND_PLAY(gen_wallet_fake_outputs_randomness); diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index e3039a06..f7d10647 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1443,14 +1443,14 @@ bool gen_wallet_transfers_and_chain_switch::generate(std::vector& events) const +bool gen_wallet_decrypted_payload_items::generate(std::vector& events) const { // Test outline // NOTE: All transactions are sending with same attachments: tx_payer, tx_comment and tx_message @@ -1508,16 +1508,18 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e // that feeling when you are a bit paranoid std::vector decrypted_attachments; currency::keypair k = currency::keypair::generate(); - transaction t = AUTO_VAL_INIT(t); - t.attachment = std::vector({ a_tx_payer, a_tx_comment, a_tx_message }); + transaction t{}; + t.attachment.push_back(a_tx_payer); + t.attachment.push_back(a_tx_message); + t.extra.push_back(a_tx_comment); add_tx_pub_key_to_extra(t, k.pub); add_attachments_info_to_extra(t.extra, t.attachment); - currency::encrypt_attachments(t, miner_acc.get_keys(), alice_acc.get_public_address(), k); + currency::encrypt_payload_items(t, miner_acc.get_keys(), alice_acc.get_public_address(), k); bool r = currency::decrypt_payload_items(true, t, alice_acc.get_keys(), decrypted_attachments); - CHECK_AND_ASSERT_MES(r, false, "encrypt_attachments + decrypt_attachments failed to work together"); + CHECK_AND_ASSERT_MES(r, false, "encrypt_payload_items + decrypt_attachments failed to work together"); } - MAKE_TX_ATTACH(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(10000), blk_0r, std::vector({ a_tx_payer, a_tx_comment, a_tx_message })); + MAKE_TX_EXTRA_ATTACH_FEE(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(10000), TESTS_DEFAULT_FEE, blk_0r, std::vector({ a_tx_comment }), std::vector({ a_tx_payer, a_tx_message })); MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc); // don't put tx_0 into this block, the block is only necessary to trigger tx_pool scan on in wallet2::refresh() // wallet callback must be passed as shared_ptr, so to avoid deleting "this" construct shared_ptr with custom null-deleter @@ -1540,7 +1542,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e // Do the same in opposite direction: alice -> miner. Unlock money, received by Alice first. REWIND_BLOCKS_N(events, blk_2r, blk_2, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); - MAKE_TX_ATTACH(events, tx_1, alice_acc, miner_acc, MK_TEST_COINS(100), blk_2r, std::vector({ a_tx_payer, a_tx_comment, a_tx_message })); + MAKE_TX_EXTRA_ATTACH_FEE(events, tx_1, alice_acc, miner_acc, MK_TEST_COINS(100), TESTS_DEFAULT_FEE, blk_2r, std::vector({ a_tx_comment }), std::vector({ a_tx_payer, a_tx_message })); MAKE_NEXT_BLOCK(events, blk_3, blk_2r, miner_acc); // don't put tx_1 into this block, the block is only necessary to trigger tx_pool scan on in wallet2::refresh() // Spend tx was not sent via Alice wallet instance, so wallet can't obtain destination address and pass it to callback (although, it decrypts attachments & extra) @@ -1573,7 +1575,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e m_comment_to_be_checked = a_tx_comment.comment; m_address_to_be_checked = get_account_address_as_str(bob_acc.get_public_address()); // note, that a_tx_payer is NOT refering to Bob's account, but in the callback we should get correct sender addr m_on_transfer2_called = false; - MAKE_TEST_WALLET_TX_ATTACH(events, tx_2, alice_wlt, MK_TEST_COINS(2000), bob_acc, std::vector({ a_tx_payer, a_tx_comment, a_tx_message })); + MAKE_TEST_WALLET_TX_EXTRA_ATTACH(events, tx_2, alice_wlt, MK_TEST_COINS(2000), bob_acc, std::vector({ a_tx_comment }), std::vector({ a_tx_payer, a_tx_message })); CHECK_AND_ASSERT_MES(m_on_transfer2_called, false, "on_transfer2() was not called (5)"); MAKE_NEXT_BLOCK(events, blk_5, blk_4r, miner_acc); // don't put tx_2 into this block, the block is only necessary to trigger tx_pool scan on in wallet2::refresh() @@ -1595,7 +1597,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_6r, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 2 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 2 + WALLET_DEFAULT_TX_SPENDABLE_AGE); a_tx_payer.acc_addr = bob_acc.get_public_address(); // here we specify correct payer address, as it will not be masked by wallet - MAKE_TEST_WALLET_TX_ATTACH(events, tx_3, bob_wlt, MK_TEST_COINS(200), alice_acc, std::vector({ a_tx_payer, a_tx_comment, a_tx_message })); + MAKE_TEST_WALLET_TX_EXTRA_ATTACH(events, tx_3, bob_wlt, MK_TEST_COINS(200), alice_acc, std::vector({ a_tx_comment }), std::vector({ a_tx_payer, a_tx_message })); MAKE_NEXT_BLOCK(events, blk_7, blk_6r, miner_acc); // don't put tx_3 into this block, the block is only necessary to trigger tx_pool scan on in wallet2::refresh() @@ -1612,7 +1614,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e return true; } -void gen_wallet_decrypted_attachments::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) +void gen_wallet_decrypted_payload_items::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { m_on_transfer2_called = true; //try { diff --git a/tests/core_tests/wallet_tests.h b/tests/core_tests/wallet_tests.h index ab7a109c..5c105b7b 100644 --- a/tests/core_tests/wallet_tests.h +++ b/tests/core_tests/wallet_tests.h @@ -104,9 +104,9 @@ struct gen_wallet_transfers_and_chain_switch : public wallet_test bool generate(std::vector& events) const; }; -struct gen_wallet_decrypted_attachments : public wallet_test, virtual public tools::i_wallet2_callback +struct gen_wallet_decrypted_payload_items : public wallet_test, virtual public tools::i_wallet2_callback { - gen_wallet_decrypted_attachments(); + gen_wallet_decrypted_payload_items(); bool generate(std::vector& events) const; // intrface tools::i_wallet2_callback From c6614912b112b0c7615f61799923935498412a7f Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 20 Jun 2025 01:31:42 +0200 Subject: [PATCH 10/65] wallet: 1) tx_comment is only allowed in extra; 2) tx_comment temporary allowed only if destinations addresses are the same; 3) integrated address can be only the first if there are many --- src/wallet/wallet2.cpp | 15 +++++++++++++++ src/wallet/wallet2.h | 1 + src/wallet/wallet_rpc_server.cpp | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 8d1630ca..f777d86d 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -8234,6 +8234,20 @@ void wallet2::check_and_throw_if_self_directed_tx_with_payment_id_requested(cons WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!has_payment_id, "sending funds to yourself with payment id is not allowed"); } //---------------------------------------------------------------------------------------------------- +void wallet2::check_and_throw_if_smth_not_good_with_comment_or_payment_id(const construct_tx_param& ctp) +{ + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!have_type_in_variant_container(ctp.attachments), "tx_comment is not allowed to be in attachments"); + + if (ctp.dsts.size() > 1 && have_type_in_variant_container(ctp.extra)) + { + const auto& first_destination = ctp.dsts.front(); + for(size_t i = 1; i < ctp.dsts.size(); ++i) + { + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ctp.dsts[i].addr == first_destination.addr, "currently tx_comment cannot be used with multi-destination transfer"); + } + } +} +//---------------------------------------------------------------------------------------------------- void wallet2::transfer(construct_tx_param& ctp, currency::transaction& tx, bool send_to_network, @@ -8252,6 +8266,7 @@ void wallet2::transfer(construct_tx_param& ctp, WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!is_auditable() || !is_watch_only(), "You can't initiate coins transfer using an auditable watch-only wallet."); // btw, watch-only wallets can call transfer() within cold-signing process check_and_throw_if_self_directed_tx_with_payment_id_requested(ctp); + check_and_throw_if_smth_not_good_with_comment_or_payment_id(ctp); bool asset_operation_requested = count_type_in_variant_container(ctp.extra) != 0; bool dont_have_zero_asset_ids_in_destinations = std::count_if(ctp.dsts.begin(), ctp.dsts.end(), [](const tx_destination_entry& de) { return de.asset_id == null_pkey; }) == 0; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index dd412494..9f440c8a 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -913,6 +913,7 @@ private: bool generate_utxo_defragmentation_transaction_if_needed(currency::transaction& tx); bool store_unsigned_tx_to_file_and_reserve_transfers(const currency::finalize_tx_param& ftp, const std::string& filename, std::string* p_unsigned_tx_blob_str = nullptr); void check_and_throw_if_self_directed_tx_with_payment_id_requested(const construct_tx_param& ctp); + void check_and_throw_if_smth_not_good_with_comment_or_payment_id(const construct_tx_param& ctp); void push_new_block_id(const crypto::hash& id, uint64_t height); bool lookup_item_around(uint64_t i, std::pair& result); //void get_short_chain_history(std::list& ids); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index f9ba3b1e..15a4d276 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -505,6 +505,12 @@ namespace tools er.message = std::string("embedded payment id: ") + embedded_payment_id + " conflicts with previously set payment id: " + payment_id; return false; } + if (it != req.destinations.begin()) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; + er.message = std::string("payment id: ") + embedded_payment_id + " currently can only be set for the first destination (an so you can use integrated address only for the fist destination)"; + return false; + } payment_id = embedded_payment_id; } de.amount = it->amount; From a3905348f1c2f08133b91fc818431102c3cffe2c Mon Sep 17 00:00:00 2001 From: zano build machine Date: Fri, 20 Jun 2025 02:32:11 +0300 Subject: [PATCH 11/65] === build number: 411 -> 412 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index 69d040b4..30764cfd 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "7" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 411 +#define PROJECT_VERSION_BUILD_NO 412 #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 "]" From 0c77467c7bdab446dad1ef59334ce535e547cb3a Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 20 Jun 2025 01:36:09 +0200 Subject: [PATCH 12/65] === version bump: 2.1.7 -> 2.1.8 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index 30764cfd..76b72bd0 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -5,7 +5,7 @@ #define PROJECT_MAJOR_VERSION "2" #define PROJECT_MINOR_VERSION "1" -#define PROJECT_REVISION "7" +#define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION #define PROJECT_VERSION_BUILD_NO 412 From aaf878419dfb3c22bbf842d5dff7f4786c8286b5 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 23 Jun 2025 13:03:26 +0200 Subject: [PATCH 13/65] ui update (PR 151) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 9531b14e..317979cd 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 9531b14e8443dd78411f84ed82fe0496dd9a3895 +Subproject commit 317979cdf88fc2ca785a3f1a0e0578b7a0f42ff5 From afd479fa62ca7bfe48776479341cf3c1499bb4f7 Mon Sep 17 00:00:00 2001 From: zano build machine Date: Mon, 23 Jun 2025 14:10:04 +0300 Subject: [PATCH 14/65] === build number: 412 -> 413 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index 76b72bd0..51f7e11f 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 412 +#define PROJECT_VERSION_BUILD_NO 413 #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 "]" From f8600d9fe446c6fb3f1a336e613bc7ed692d1d25 Mon Sep 17 00:00:00 2001 From: Dmitry Matsiukhov <46869283+dimmarvel@users.noreply.github.com> Date: Mon, 23 Jun 2025 17:38:55 +0300 Subject: [PATCH 15/65] fix cmake for linux build (#531) --- CMakeLists.txt | 6 +++--- tests/CMakeLists.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f01fff7..5897025d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,7 +248,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS") #set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}") elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") if(CAKEWALLET) - find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale) + find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem locale thread timer date_time chrono regex serialization atomic program_options) else() set(Boost_LIBRARY_DIRS "${Boost_LIBRARY_DIRS}/${CMAKE_ANDROID_ARCH_ABI}/") set(Boost_LIBRARIES "${Boost_LIBRARY_DIRS}libboost_system.a;${Boost_LIBRARY_DIRS}libboost_filesystem.a;${Boost_LIBRARY_DIRS}libboost_thread.a;${Boost_LIBRARY_DIRS}libboost_timer.a;${Boost_LIBRARY_DIRS}libboost_date_time.a;${Boost_LIBRARY_DIRS}libboost_chrono.a;${Boost_LIBRARY_DIRS}libboost_regex.a;${Boost_LIBRARY_DIRS}libboost_serialization.a;${Boost_LIBRARY_DIRS}libboost_atomic.a;${Boost_LIBRARY_DIRS}libboost_program_options.a") @@ -256,9 +256,9 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC") elseif(APPLE) - find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale) + find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem locale thread timer date_time chrono regex serialization atomic program_options) else() - find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale log) + find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem locale thread timer date_time chrono regex serialization atomic program_options log) endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 323dbbd8..fb38a979 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,7 +32,7 @@ target_link_libraries(coretests rpc wallet currency_core common crypto zlibstati target_link_libraries(functional_tests rpc wallet currency_core crypto common zlibstatic ethash libminiupnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(hash-tests crypto ethash) target_link_libraries(hash-target-tests crypto currency_core ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(performance_tests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) +target_link_libraries(performance_tests wallet rpc currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(unit_tests wallet currency_core common crypto gtest_main zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(net_load_tests_clt currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(net_load_tests_srv currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) From ffa94febc6d4af113a280604dd3a13ee6c6c251f Mon Sep 17 00:00:00 2001 From: Dmitry Matsiukhov <46869283+dimmarvel@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:54:52 +0300 Subject: [PATCH 16/65] coretests: block_choice_rule_bigger_fee test added (#530) * add bigger fee block choice test * fix block_validation * remove c1, add check_top_block callback * added more checks * update test case * delete: cmake fix for linux * part of fixs * add new check * delete unused declareted * add comments * fix comment * fix comments --- tests/core_tests/block_validation.cpp | 148 ++++++++++++++++++++++++++ tests/core_tests/block_validation.h | 10 ++ tests/core_tests/chaingen_main.cpp | 3 +- 3 files changed, 160 insertions(+), 1 deletion(-) diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index ed290387..2d35c703 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -1202,3 +1202,151 @@ bool block_reward_in_alt_chain_basic::assert_reward(currency::core& core, size_t return true; } + +//----------------------------------------------------------------------------------------------------- +block_choice_rule_bigger_fee::block_choice_rule_bigger_fee() +{ + REGISTER_CALLBACK("c1", block_choice_rule_bigger_fee::c1); +} + +struct block_choice_rule_bigger_fee::argument_assert +{ + std::list transactions{}; + + argument_assert() = default; + + argument_assert(const std::list& txs) + : transactions(txs) + {} + + BEGIN_SERIALIZE() + FIELD(transactions) + END_SERIALIZE() +}; + +// Test idea: fork-choice rule based on transactions’ median fees +/* Sets up three competing chains: + * - Main(blk_1a): 4 transactions with fee 6 (fees = [6, 6, 6, 6], median = (6 + 6) / 2 = 6, score = 6 * 4 = 24) + * - Alt1(blk_1b): 2 transactions with fee 11 (fees = [11, 11], median = (11 + 11) / 2 = 11, score = 11 * 2 = 22) + * - Alt2(blk_1): 2 transactions with fee 10 (fees = [10, 10], median = (10 + 10) / 2 = 10, score = 10 * 2 = 20) + * + * Fork-choice rule: + * - Even count: median = average of the two middle fees, then multiply by the number of transactions. + * - Odd count: median = fee of the central transaction, then multiply by the number of transactions. + * + * The chain with the highest resulting value wins. In this test, Main(blk_1a) wins (24 > 22 and 24 > 20) + * and remains the preferred chain even after Alt2Alt2(blk_1) appears. + */ +bool block_choice_rule_bigger_fee::generate(std::vector& events) const +{ + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + DO_CALLBACK(events, "configure_core"); + + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + // Main chain + MAKE_TX_FEE(events, tx_1, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE * 10, blk_0r); + MAKE_TX_FEE(events, tx_2, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE * 10, blk_0r); + + std::list txs_1{tx_1, tx_2}; + MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner, txs_1); + + DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_1)); + DO_CALLBACK(events, "check_tx_pool_empty"); + + /* 0 10 11 + (blk_0) - ... - (blk_0r) - (blk_1) + {tx0} {tx1, tx2} + */ + + // Alt chain + MAKE_TX_FEE(events, tx_3, miner, miner, MK_TEST_COINS(8), TESTS_DEFAULT_FEE * 6, blk_0r); + MAKE_TX_FEE(events, tx_4, miner, miner, MK_TEST_COINS(8), TESTS_DEFAULT_FEE * 6, blk_0r); + MAKE_TX_FEE(events, tx_5, miner, miner, MK_TEST_COINS(8), TESTS_DEFAULT_FEE * 6, blk_0r); + MAKE_TX_FEE(events, tx_6, miner, miner, MK_TEST_COINS(8), TESTS_DEFAULT_FEE * 6, blk_0r); + + std::list txs_1a{tx_3, tx_4, tx_5, tx_6}; + MAKE_NEXT_BLOCK_TX_LIST(events, blk_1a, blk_0r, miner, txs_1a); + + // tx_1,tx_2 should be in pool + DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_1a)); + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(2)); + + // Fees are pre-sorted: + // - If count is even: sum the two middle fees -> e.g., 6 + 6 / 2 * 4 = 24 (blk_1a) + // - If the number is odd: take the central transaction, for example tx1 tx2 tx3 - the fee of tx2 will be median + /* 0 10 11 + (blk_0) - ... - (blk_0r) - (blk_1a) - win because 1 + {tx0} {tx_3, tx_4, tx_5, tx_6} + | + | 11 + \ - (blk_1) + */ + + std::list transactions; + for (const auto& tx : txs_1) + { + transactions.push_back(get_transaction_hash(tx)); + } + argument_assert argument_1a{transactions}; + + DO_CALLBACK_PARAMS_STR(events, "c1", t_serializable_object_to_blob(argument_1a)); + + MAKE_TX_FEE(events, tx_7, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE * 11, blk_0r); + MAKE_TX_FEE(events, tx_8, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE * 11, blk_0r); + + std::list txs_1b{tx_7, tx_8}; + MAKE_NEXT_BLOCK_TX_LIST(events, blk_1b, blk_0r, miner, txs_1b); + + /* 0 10 11 + (blk_0) - ... - (blk_0r) - (blk_1a) - won because (6 + 6) / 2 * 4 = 24 > 22(blk_1b) + {tx0} {tx_3, tx_4, tx_5, tx_6} + | + | 11 + \ - (blk_1b) - lost because after sorting the central element has the value (11 + 11) / 2 * 2 = 22 < 24 + | + | 11 + \ - (blk_1) - lost (10 + 10) / 2 * 2 = 20 < 24 + */ + + // tx_1, tx_2, tx_7, tx_8 should be in pool + DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_1a)); + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(4)); + + for (const auto& tx : txs_1b) + { + transactions.push_back(get_transaction_hash(tx)); + } + argument_assert argument_1b{transactions}; + DO_CALLBACK_PARAMS_STR(events, "c1", t_serializable_object_to_blob(argument_1b)); + + return true; +} + +bool block_choice_rule_bigger_fee::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + argument_assert argument{}; + { + const auto serialized_argument{boost::get(events.at(ev_index)).callback_params}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(argument, serialized_argument), true); + } + + std::list txs; + c.get_pool_transactions(txs); + + CHECK_AND_ASSERT_MES(txs.size() == argument.transactions.size(), false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + + std::list hash_txs; + for (const auto& tx : txs) + { + hash_txs.push_back(get_transaction_hash(tx)); + } + + hash_txs.sort(); + argument.transactions.sort(); + CHECK_AND_ASSERT_MES(hash_txs == argument.transactions, false, "Unexpected transactions in the mempool"); + + return true; +} diff --git a/tests/core_tests/block_validation.h b/tests/core_tests/block_validation.h index 59e4c149..1eac64bd 100644 --- a/tests/core_tests/block_validation.h +++ b/tests/core_tests/block_validation.h @@ -217,3 +217,13 @@ private: bool assert_reward(currency::core& core, size_t event_index, const std::vector& events) const; struct argument_assert; }; + +struct block_choice_rule_bigger_fee : public wallet_test +{ + block_choice_rule_bigger_fee(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); + +private: + struct argument_assert; +}; \ No newline at end of file diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index cd886555..fb722a87 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1191,7 +1191,8 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(gen_block_miner_tx_has_out_to_initiator, "0,3"); GENERATE_AND_PLAY_HF(gen_block_has_invalid_tx, "0,3"); GENERATE_AND_PLAY_HF(gen_block_is_too_big, "0,3"); - GENERATE_AND_PLAY_HF(gen_block_wrong_version_agains_hardfork, "0,3"); + GENERATE_AND_PLAY_HF(gen_block_wrong_version_agains_hardfork, "0,3"); + GENERATE_AND_PLAY_HF(block_choice_rule_bigger_fee, "4-*"); //GENERATE_AND_PLAY(gen_block_invalid_binary_format); // Takes up to 3 hours, if CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 500, up to 30 minutes, if CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10 From 2b3360f66aca3f7ae08b438365d29955601b2730 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 25 Jun 2025 16:41:26 +0400 Subject: [PATCH 17/65] added more logs --- src/rpc/core_rpc_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index a498ec18..7b9aa012 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -919,7 +919,7 @@ namespace currency if(!tvc.m_should_be_relayed) { - LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed"); + LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed, tx blob: " << << req.tx_as_hex); res.status = "Not relayed"; return true; } From a0c1c8b4dff9b4ed1c9750b5d7fc7a777aac7a85 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 25 Jun 2025 16:46:37 +0400 Subject: [PATCH 18/65] fixed typo --- src/rpc/core_rpc_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 7b9aa012..a1d1d7cd 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -919,7 +919,7 @@ namespace currency if(!tvc.m_should_be_relayed) { - LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed, tx blob: " << << req.tx_as_hex); + LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed, tx blob: " << req.tx_as_hex); res.status = "Not relayed"; return true; } From 5340c6db323bcdb28e18567d8bd2cc6ca4ebd9fd Mon Sep 17 00:00:00 2001 From: Dmitry Matsiukhov <46869283+dimmarvel@users.noreply.github.com> Date: Fri, 27 Jun 2025 21:16:24 +0300 Subject: [PATCH 19/65] coretests: test for miner tx with non-empty extra_nonce before and after HF4 (#532) * try check extra nonce in miner_tx * update c1 * write extra nonces, create pow pos block, checkers for exnonce, bug with HF4 * success check pos block * correct pos/pos extra nonce validation for hf3+ * clean code, separate to methods, add template test, pos/pow extra nonce check in block * delete logs * back normal naming * fix review comments --- tests/core_tests/chaingen.cpp | 100 ++++++++++++++++++- tests/core_tests/chaingen.h | 4 +- tests/core_tests/chaingen_main.cpp | 2 +- tests/core_tests/pos_validation.cpp | 146 +++++++++++++++++++--------- tests/core_tests/pos_validation.h | 14 +++ 5 files changed, 216 insertions(+), 50 deletions(-) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index a70104fc..cf9c1af1 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -940,7 +940,7 @@ bool test_generator::construct_block(int64_t manual_timestamp_adjustment, const crypto::hash& prev_id/* = crypto::hash()*/, const wide_difficulty_type& diffic/* = 1*/, const transaction& miner_tx/* = transaction()*/, const std::vector& tx_hashes/* = std::vector()*/, - size_t txs_sizes/* = 0*/) + size_t txs_sizes/* = 0*/, currency::blobdata extra_nonce/* = blobdata()*/) { size_t height = get_block_height(prev_block) + 1; blk.major_version = actual_params & bf_major_ver ? major_ver : m_hardforks.get_block_major_version_by_height(height); @@ -966,7 +966,7 @@ bool test_generator::construct_block(int64_t manual_timestamp_adjustment, size_t current_block_size = txs_sizes + get_object_blobsize(blk.miner_tx); // TODO: This will work, until size of constructed block is less then CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, - miner_acc.get_public_address(), miner_acc.get_public_address(), blk.miner_tx, base_block_reward, block_reward, tx_version, tx_hardfork_id, blobdata(), 1)) + miner_acc.get_public_address(), miner_acc.get_public_address(), blk.miner_tx, base_block_reward, block_reward, tx_version, tx_hardfork_id, extra_nonce, 1)) return false; } @@ -2498,6 +2498,102 @@ uint64_t decode_native_output_amount_or_throw(const account_base& acc, const tra return amount; } +bool generate_pos_block_with_extra_nonce(test_generator& generator, const std::vector& events, const currency::account_base& miner, const currency::account_base& recipient, const currency::block& prev_block, const currency::transaction& stake_tx, const currency::blobdata& pos_nonce, currency::block& result) +{ + // get params for PoS + crypto::hash prev_id = get_block_hash(prev_block); + wide_difficulty_type pos_diff{}; + crypto::hash last_pow_block_hash{}, last_pos_block_kernel_hash{}; + bool 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"); + + // tx key and key image for stake out + crypto::public_key stake_pk = get_tx_pub_key_from_extra(stake_tx); + keypair kp; + crypto::key_image ki; + size_t stake_output_idx = 0; + generate_key_image_helper(miner.get_keys(), stake_pk, stake_output_idx, kp, ki); + + // glob index for stake out + uint64_t stake_output_gidx = UINT64_MAX; + 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"); + + pos_block_builder pb; + uint64_t height = get_block_height(prev_block) + 1; + pb.step1_init_header(generator.get_hardforks(), height, prev_id); + pb.step2_set_txs({}); + + if (generator.get_hardforks().is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, height)) + { + std::vector sources; + bool ok = fill_tx_sources( + sources, events, prev_block, miner.get_keys(), + UINT64_MAX, 0, false, false, true + ); + + auto it = std::find_if(sources.begin(), sources.end(), + [&](const tx_source_entry &e){ + return e.real_out_tx_key == stake_pk + && e.real_output_in_tx_index == stake_output_idx; + }); + CHECK_AND_ASSERT_MES(it != sources.end(), false, "source entry not found"); + const tx_source_entry& se = *it; + + pb.step3a(pos_diff, last_pow_block_hash, last_pos_block_kernel_hash); + pb.step3b( + se.amount, ki, + 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 + ); + + // insert extra_nonce + pb.step4_generate_coinbase_tx( + generator.get_timestamps_median(prev_id), + generator.get_already_generated_coins(prev_block), + recipient.get_public_address(), + pos_nonce, + CURRENCY_MINER_TX_MAX_OUTS + ); + + pb.step5_sign(se, miner.get_keys()); + } + else // HF3: SLSAG + { + uint64_t amount = boost::get(stake_tx.vout[stake_output_idx]).amount; + pb.step3_build_stake_kernel( + amount, + stake_output_gidx, + ki, + pos_diff, + last_pow_block_hash, + last_pos_block_kernel_hash, + prev_block.timestamp + ); + + // insert extra_nonce + pb.step4_generate_coinbase_tx( + generator.get_timestamps_median(prev_id), + generator.get_already_generated_coins(prev_block), + recipient.get_public_address(), + pos_nonce, + CURRENCY_MINER_TX_MAX_OUTS + ); + + crypto::public_key out_pk = boost::get(boost::get(stake_tx.vout[stake_output_idx]).target).key; + pb.step5_sign(stake_pk, stake_output_idx, out_pk, miner); + } + + result = pb.m_block; + 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 */) { diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 6ea4cc90..e9bf05a3 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -570,7 +570,8 @@ public: const currency::account_base& miner_acc, int actual_params = bf_none, uint8_t major_ver = 0, uint8_t minor_ver = 0, uint64_t timestamp = 0, const crypto::hash& prev_id = crypto::hash(), const currency::wide_difficulty_type& diffic = 1, const currency::transaction& miner_tx = currency::transaction(), - const std::vector& tx_hashes = std::vector(), size_t txs_sizes = 0); + const std::vector& tx_hashes = std::vector(), size_t txs_sizes = 0, + currency::blobdata extra_nonce = currency::blobdata()); bool construct_block_manually_tx(currency::block& blk, const currency::block& prev_block, const currency::account_base& miner_acc, const std::vector& tx_hashes, size_t txs_size); bool find_nounce(currency::block& blk, std::vector& blocks, currency::wide_difficulty_type dif, uint64_t height) const; @@ -828,6 +829,7 @@ uint64_t get_last_block_of_type(bool looking_for_pos, const test_generator::bloc 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_extra_nonce(test_generator& generator, const std::vector& events, const currency::account_base& miner, const currency::account_base& recipient, const currency::block& prev_block, const currency::transaction& stake_tx, const currency::blobdata& pos_nonce, currency::block& result); 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); diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index fb722a87..978da46a 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1118,7 +1118,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_pos_coinstake_already_spent); GENERATE_AND_PLAY(gen_pos_incorrect_timestamp); GENERATE_AND_PLAY(gen_pos_too_early_pos_block); - GENERATE_AND_PLAY(gen_pos_extra_nonce); + GENERATE_AND_PLAY_HF(gen_pos_extra_nonce, "3-*"); GENERATE_AND_PLAY(gen_pos_min_allowed_height); GENERATE_AND_PLAY(gen_pos_invalid_coinbase); // GENERATE_AND_PLAY(pos_wallet_minting_same_amount_diff_outs); // Long test! Takes ~10 hours to simulate 6000 blocks on 2015 middle-end computer diff --git a/tests/core_tests/pos_validation.cpp b/tests/core_tests/pos_validation.cpp index 28f66b6a..539b9259 100644 --- a/tests/core_tests/pos_validation.cpp +++ b/tests/core_tests/pos_validation.cpp @@ -217,56 +217,110 @@ bool gen_pos_too_early_pos_block::configure_core(currency::core& c, size_t ev_in //------------------------------------------------------------------ -bool gen_pos_extra_nonce::generate(std::vector& events) const +bool gen_pos_extra_nonce::configure_core(currency::core& c, size_t ev_index, const std::vector&) { - uint64_t ts = time(NULL); - - GENERATE_ACCOUNT(miner); - GENERATE_ACCOUNT(alice); - MAKE_GENESIS_BLOCK(events, blk_0, miner, ts); - DO_CALLBACK(events, "configure_core"); - REWIND_BLOCKS(events, blk_0r, blk_0, miner); - - // Legend: (n) - PoW block, [m] - PoS block - // 0 10 11 <-- blockchain height (assuming CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10) - // (0 )--(0r)--[1 ] main chain - - // make a PoS block manually with incorrect timestamp - crypto::hash prev_id = get_block_hash(blk_0r); - size_t height = CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1; - currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false); - - const transaction& stake = blk_0.miner_tx; - crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake); - size_t stake_output_idx = 0; - size_t stake_output_gidx = 0; - uint64_t stake_output_amount =boost::get( stake.vout[stake_output_idx]).amount; - 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.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, blk_0r.timestamp); - - // use biggest possible extra nonce (255 bytes) + largest alias - currency::blobdata extra_nonce(255, 'x'); - //currency::extra_alias_entry alias = AUTO_VAL_INIT(alias); // TODO: this alias entry was ignored for a long time, now I commented it out, make sure it's okay -- sowle - //alias.m_alias = std::string(255, 'a'); - //alias.m_address = miner.get_keys().account_address; - //alias.m_text_comment = std::string(255, 'y'); - pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), alice.get_public_address(), extra_nonce, CURRENCY_MINER_TX_MAX_OUTS); - pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, miner); - block blk_1 = pb.m_block; - - // EXPECTED: blk_1 is accepted - events.push_back(blk_1); - + currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config(); + pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; + pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH; + pc.hf4_minimum_mixins = 0; + pc.hard_forks = m_hardforks; + c.get_blockchain_storage().set_core_runtime_config(pc); return true; } +gen_pos_extra_nonce::gen_pos_extra_nonce() +{ + REGISTER_CALLBACK_METHOD(gen_pos_extra_nonce, configure_core); + REGISTER_CALLBACK_METHOD(gen_pos_extra_nonce, request_pow_template_with_nonce); + REGISTER_CALLBACK_METHOD(gen_pos_extra_nonce, check_pow_nonce); + REGISTER_CALLBACK_METHOD(gen_pos_extra_nonce, check_pos_nonce); +} + +// Test: verify custom extra_nonce in blocks and templates +/* + * Scenarios: + * 1. PoW block contains m_pow_nonce + * 2. PoS block contains m_pos_nonce + * 3. PoW mining template contains m_pow_template_nonce + */ +bool gen_pos_extra_nonce::generate(std::vector& events) const +{ + GENERATE_ACCOUNT(miner); + GENERATE_ACCOUNT(alice); + m_accounts.push_back(miner); + m_accounts.push_back(alice); + m_pow_nonce = currency::blobdata(254, 'w'); + m_pos_nonce = currency::blobdata(255, 's'); + m_pow_template_nonce = "POW_TEMPLATE123"; + + uint64_t ts = test_core_time::get_time(); + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts); + DO_CALLBACK(events, "configure_core"); + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + + block blk_2 = AUTO_VAL_INIT(blk_2); + ts = blk_2.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN / 2; // to increase main chain difficulty + bool r = generator.construct_block_manually(blk_2, blk_1, miner, test_generator::bf_timestamp, 0, 0, + ts, crypto::hash(), 1, transaction(), std::vector(), 0, m_pow_nonce); + CHECK_AND_ASSERT_MES(r, false, "construct_block_manually failed"); + events.push_back(blk_2); + + DO_CALLBACK(events, "check_pow_nonce"); + REWIND_BLOCKS(events, blk_0r, blk_2, miner); + + // setup params for PoS + const currency::transaction& stake = blk_2.miner_tx; + + currency::block new_pos_block; + bool ok = generate_pos_block_with_extra_nonce(generator, events, miner, alice, blk_0r, stake, m_pos_nonce, new_pos_block); + CHECK_AND_ASSERT_MES(ok, false, "generate_pos_block_with_extra_nonce failed"); + + events.push_back(new_pos_block); + DO_CALLBACK(events, "check_pos_nonce"); + DO_CALLBACK(events, "request_pow_template_with_nonce"); + return true; +} + +bool gen_pos_extra_nonce::request_pow_template_with_nonce(currency::core& c, size_t ev_index, const std::vector& events) +{ + block bl; + wide_difficulty_type diff; + uint64_t height; + bool ok = c.get_block_template(bl, m_accounts[0].get_public_address(), m_accounts[0].get_public_address(), diff, height, m_pow_template_nonce); + CHECK_AND_ASSERT_MES(ok, false, "get_block_template failed"); + CHECK_AND_ASSERT_MES(has_extra_nonce(bl, m_pow_template_nonce), false, "PoW extra_nonce not found"); + return true; +} + +bool gen_pos_extra_nonce::check_pow_nonce(currency::core& c, size_t ev_index, const std::vector& events) +{ + block top; + bool ok = c.get_blockchain_storage().get_top_block(top); + CHECK_AND_ASSERT_MES(ok, false, "get_top_block failed"); + CHECK_AND_ASSERT_MES(has_extra_nonce(top, m_pow_nonce), false, "PoW extra_nonce not found"); + return true; +} + +bool gen_pos_extra_nonce::check_pos_nonce(currency::core& c, size_t ev_index, const std::vector& events) +{ + block top; + bool ok = c.get_blockchain_storage().get_top_block(top); + CHECK_AND_ASSERT_MES(ok, false, "get_top_block failed"); + CHECK_AND_ASSERT_MES(has_extra_nonce(top, m_pos_nonce), false, "PoS extra_nonce not found"); + return true; +} + +bool gen_pos_extra_nonce::has_extra_nonce(currency::block& blk, const std::string& expected_nonce) +{ + if (auto const* ud = get_type_in_variant_container(blk.miner_tx.extra)) { + LOG_PRINT_L0("Found extra nonce: '" << ud->buff << "' expected: '" << expected_nonce << "'"); + return ud->buff == expected_nonce; + } + return false; +} + +//------------------------------------------------------------------ + gen_pos_min_allowed_height::gen_pos_min_allowed_height() { REGISTER_CALLBACK_METHOD(gen_pos_min_allowed_height, configure_core); diff --git a/tests/core_tests/pos_validation.h b/tests/core_tests/pos_validation.h index 6b48deb3..a5363af9 100644 --- a/tests/core_tests/pos_validation.h +++ b/tests/core_tests/pos_validation.h @@ -71,7 +71,21 @@ struct gen_pos_too_early_pos_block : public pos_validation struct gen_pos_extra_nonce : public pos_validation { + gen_pos_extra_nonce(); + bool configure_core(currency::core& c, size_t, const std::vector& events); + bool request_pow_template_with_nonce(currency::core& c, size_t, const std::vector& events); + bool check_pos_nonce(currency::core& c, size_t, const std::vector& events); + bool check_pow_nonce(currency::core& c, size_t, const std::vector& events); bool generate(std::vector& events) const; + +private: + bool has_extra_nonce(currency::block& blk, const std::string& expected_nonce); + +private: + mutable currency::blobdata m_pow_nonce; + mutable currency::blobdata m_pos_nonce; + mutable currency::blobdata m_pow_template_nonce; + mutable std::vector m_accounts; }; struct gen_pos_min_allowed_height : public pos_validation From 05ea60a70cdbebda8914bba7ebe04d1fd87b8311 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Mon, 30 Jun 2025 15:39:47 +0400 Subject: [PATCH 20/65] made seed request non-synchronized --- src/wallet/wallets_manager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index e9866fef..ed1c5515 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -1922,10 +1922,11 @@ std::string wallets_manager::get_wallet_restore_info(uint64_t wallet_id, std::st { GET_WALLET_OPT_BY_ID(wallet_id, wo); - if (wo.wallet_state != view::wallet_status_info::wallet_state_ready || wo.long_refresh_in_progress) - return API_RETURN_CODE_CORE_BUSY; + seed_phrase = wo.w.unlocked_get()->get_account().get_seed_phrase(seed_password); - seed_phrase = wo.w->get()->get_account().get_seed_phrase(seed_password); + //if (wo.wallet_state != view::wallet_status_info::wallet_state_ready || wo.long_refresh_in_progress) + // return API_RETURN_CODE_CORE_BUSY; + //seed_phrase = wo.w->get()->get_account().get_seed_phrase(seed_password); return API_RETURN_CODE_OK; } From 430d31ba5e4a286d32e5d2ba05b6e45425f5a133 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 1 Jul 2025 20:37:30 +0400 Subject: [PATCH 21/65] added --no-white-list option for offline working --- src/simplewallet/simplewallet.cpp | 28 ++++++++++++++++++++++++---- src/simplewallet/simplewallet.h | 3 +++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 60ee03ae..656856cb 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -145,6 +145,7 @@ namespace const command_line::arg_descriptor arg_voting_config_file("voting-config-file", "Set voting config instead of getting if from daemon", ""); const command_line::arg_descriptor arg_no_password_confirmations("no-password-confirmation", "Enable/Disable password confirmation for transactions", false); const command_line::arg_descriptor arg_seed_doctor("seed-doctor", "Experimental: if your seed is not working for recovery this is likely because you've made a mistake whene you were doing back up(typo, wrong words order, missing word). This experimental code will attempt to recover seed phrase from with few approaches."); + const command_line::arg_descriptor arg_no_whitelist("no-white-list", "Do not load white list from interned."); const command_line::arg_descriptor< std::vector > arg_command ("command", ""); @@ -405,6 +406,16 @@ void process_wallet_command_line_params(const po::variables_map& vm, tools::wall wal.set_disable_tor_relay(true); } } + + if (command_line::has_arg(vm, arg_no_whitelist)) + { + wal.set_use_assets_whitelisting(!command_line::get_arg(vm, arg_no_whitelist)); + } + else + { + wal.set_use_assets_whitelisting(true); + } + if (command_line::has_arg(vm, arg_set_timeout)) { @@ -551,6 +562,7 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_ m_disable_tor = command_line::get_arg(vm, arg_disable_tor_relay); m_voting_config_file = command_line::get_arg(vm, arg_voting_config_file); m_no_password_confirmations = command_line::get_arg(vm, arg_no_password_confirmations); + m_no_whitelist = command_line::get_arg(vm, arg_no_whitelist); } //---------------------------------------------------------------------------------------------------- @@ -612,6 +624,7 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas m_wallet->generate(epee::string_encoding::utf8_to_wstring(m_wallet_file), password, create_auditable_wallet); message_writer(epee::log_space::console_color_white, true) << "Generated new " << (create_auditable_wallet ? "AUDITABLE" : "") << " wallet: " << m_wallet->get_account().get_public_address_str(); display_vote_info(*m_wallet); + preconfig_wallet_obj(); std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush; if (m_wallet->is_auditable()) std::cout << "tracking seed: " << std::endl << m_wallet->get_account().get_tracking_seed() << std::endl << std::flush; @@ -660,6 +673,7 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st std::cout << "tracking seed: " << std::endl << m_wallet->get_account().get_tracking_seed() << std::endl << std::flush; } display_vote_info(*m_wallet); + preconfig_wallet_obj(); if (m_do_not_set_date) m_wallet->reset_creation_time(0); } @@ -686,7 +700,12 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st return true; } //---------------------------------------------------------------------------------------------------- - +void simple_wallet::preconfig_wallet_obj() +{ + if (m_no_whitelist) + m_wallet->set_use_assets_whitelisting(false); +} +// bool simple_wallet::open_wallet(const string &wallet_file, const std::string& password) { m_wallet_file = wallet_file; @@ -702,8 +721,9 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa { m_wallet->load(epee::string_encoding::utf8_to_wstring(m_wallet_file), password); message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str(); + preconfig_wallet_obj(); display_vote_info(*m_wallet); - + break; } catch (const tools::error::wallet_load_notice_wallet_restored& /*e*/) @@ -3224,7 +3244,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, command_line::arg_generate_rpc_autodoc); command_line::add_arg(desc_params, arg_seed_doctor); command_line::add_arg(desc_params, arg_derive_custom_seed); - + command_line::add_arg(desc_params, arg_no_whitelist); tools::wallet_rpc_server::init_options(desc_params); @@ -3415,7 +3435,7 @@ int main(int argc, char* argv[]) if (command_line::get_arg(vm, arg_generate_new_wallet).size() || command_line::get_arg(vm, arg_generate_new_auditable_wallet).size()) return EXIT_FAILURE; - wal.set_use_assets_whitelisting(true); + wal.callback(callback); if (!offline_mode) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index d660e75c..afc07ec8 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -180,6 +180,8 @@ namespace currency }; private: + void preconfig_wallet_obj(); + std::string m_wallet_file; std::string m_generate_new; std::string m_generate_new_aw; @@ -196,6 +198,7 @@ namespace currency std::string m_restore_wallet; std::string m_voting_config_file; bool m_no_password_confirmations = false; + bool m_no_whitelist = false; crypto::hash m_password_hash; uint64_t m_password_salt; From 6a4d6e1fc6e1e52336158c5ef68d8cb53d17bdb5 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 1 Jul 2025 23:37:53 +0400 Subject: [PATCH 22/65] fixed #483, thanks to @gurglespuge for reporting it and proposing fix --- src/currency_core/blockchain_storage.cpp | 4 ++-- src/currency_core/blockchain_storage.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 88082943..f7d4e38a 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -74,8 +74,8 @@ using namespace currency; DISABLE_VS_WARNINGS(4267) -const command_line::arg_descriptor arg_db_cache_l1 ( "db-cache-l1", "Specify size of memory mapped db cache file"); -const command_line::arg_descriptor arg_db_cache_l2 ( "db-cache-l2", "Specify cached elements in db helpers"); +const command_line::arg_descriptor arg_db_cache_l1 ( "db-cache-l1", "Specify size of memory mapped db cache file"); +const command_line::arg_descriptor arg_db_cache_l2 ( "db-cache-l2", "Specify cached elements in db helpers"); //------------------------------------------------------------------ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(nullptr, m_rw_lock), diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 65dbc07a..cccc8d83 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -50,7 +50,7 @@ MARK_AS_POD_C11(macro_alias_1); #undef LOG_DEFAULT_CHANNEL #define LOG_DEFAULT_CHANNEL "core" -extern const command_line::arg_descriptor arg_db_cache_l2; +extern const command_line::arg_descriptor arg_db_cache_l2; namespace currency { From 187a830f58da97013aaf47802ac333a1f7b129ae Mon Sep 17 00:00:00 2001 From: Dmitry Matsiukhov <46869283+dimmarvel@users.noreply.github.com> Date: Thu, 3 Jul 2025 12:55:40 +0300 Subject: [PATCH 23/65] fixed input password bug (#536) --- src/simplewallet/password_container.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/simplewallet/password_container.cpp b/src/simplewallet/password_container.cpp index 6203eee9..ccba0c16 100644 --- a/src/simplewallet/password_container.cpp +++ b/src/simplewallet/password_container.cpp @@ -232,7 +232,10 @@ namespace tools else { m_password.push_back(ch); - std::cout << (char_to_replace_user_input != '\0' ? char_to_replace_user_input : ch); + std::cout.put(( + char_to_replace_user_input != '\0' ? + char_to_replace_user_input : static_cast(ch)) + ).flush(); } } From d5890e3c7f52fa82fcf8546755a166054bb2f385 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 3 Jul 2025 15:17:12 +0200 Subject: [PATCH 24/65] pod_array_file_container::clear() implemented --- src/common/pod_array_file_container.h | 32 ++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/common/pod_array_file_container.h b/src/common/pod_array_file_container.h index 7c168d79..8ac36270 100644 --- a/src/common/pod_array_file_container.h +++ b/src/common/pod_array_file_container.h @@ -67,6 +67,7 @@ namespace tools *p_reason = std::string("file was corrupted, truncated: ") + epee::string_tools::num_to_string_fast(file_size) + " -> " + epee::string_tools::num_to_string_fast(corrected_size); } + m_filename = filename; return true; } @@ -77,7 +78,7 @@ namespace tools bool push_back(const pod_t& item) { - if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit)) + if (!is_opened_and_in_good_state()) return false; m_stream.seekp(0, std::ios_base::end); @@ -93,7 +94,7 @@ namespace tools bool get_item(size_t index, pod_t& result) const { - if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit)) + if (!is_opened_and_in_good_state()) return false; size_t offset = index * sizeof result; @@ -108,20 +109,45 @@ namespace tools size_t size_bytes() const { - if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit)) + if (!is_opened_and_in_good_state()) return 0; m_stream.seekg(0, std::ios_base::end); return m_stream.tellg(); } + bool is_opened_and_in_good_state() const + { + if (!m_stream.is_open()) + return false; + if (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit) + return false; + return true; + } + size_t size() const { return size_bytes() / sizeof(pod_t); } + bool clear() + { + if (!is_opened_and_in_good_state()) + return false; + + // close and re-open stream with trunc bit + m_stream.close(); + m_stream.open(m_filename, std::ios::binary | std::ios::trunc | std::ios::in); + + if (m_stream.rdstate() != std::ios::eofbit) + return false; + + return true; + } + private: mutable boost::filesystem::fstream m_stream; + std::wstring m_filename; }; } // namespace tools From dfbda0a77f07b4934e348c37917a849fff7b4901 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 3 Jul 2025 16:13:44 +0200 Subject: [PATCH 25/65] minor improvements for wallet/simplewallet (logs, comments, error handling) --- src/crypto/crypto.cpp | 1 + src/currency_core/currency_format_utils.cpp | 9 ++- src/simplewallet/simplewallet.cpp | 41 +++++----- src/wallet/wallet2.cpp | 87 +++++++++++---------- src/wallet/wallet_errors.h | 4 +- 5 files changed, 76 insertions(+), 66 deletions(-) diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index 37701cd7..cfdfb866 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -294,6 +294,7 @@ namespace crypto { } void crypto_ops::generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) { + // image = sec * 8 * ge_fromfe_frombytes_vartime(cn_fast_hash(pub)) = sec * Hp( pub ) ge_p3 point; ge_p2 point2; crypto_assert(sc_check(&sec) == 0); diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 8eb0412d..dbe4d82a 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -736,14 +736,15 @@ namespace currency //------------------------------------------------------------------ bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral) { + // TODO: re-implement this to avoid double Hs calculation -- sowle crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); - bool r = crypto::generate_key_derivation(tx_public_key, ack.view_secret_key, recv_derivation); + bool r = crypto::generate_key_derivation(tx_public_key, ack.view_secret_key, recv_derivation); // recv_derivation = 8 * ack.view_secret_key * tx_public_key CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.view_secret_key << ")"); - r = crypto::derive_public_key(recv_derivation, real_output_index, ack.account_address.spend_public_key, in_ephemeral.pub); + r = crypto::derive_public_key(recv_derivation, real_output_index, ack.account_address.spend_public_key, in_ephemeral.pub); // = Hs(recv_derivation, real_output_index) * G + spend_public_key CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.account_address.spend_public_key << ")"); - crypto::derive_secret_key(recv_derivation, real_output_index, ack.spend_secret_key, in_ephemeral.sec); + crypto::derive_secret_key(recv_derivation, real_output_index, ack.spend_secret_key, in_ephemeral.sec); // = Hs(recv_derivation, real_output_index) + spend_secret_key return true; } //--------------------------------------------------------------- @@ -764,6 +765,8 @@ namespace currency //--------------------------------------------------------------- bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki) { + // h = Hs(8 * ack.view_secret_key * tx_public_key, real_output_index) + // ki = sec * Hp( pub ) = (h + spend_secret_key) * Hp( h * G + spend_public_key ) bool r = derive_ephemeral_key_helper(ack, tx_public_key, real_output_index, in_ephemeral); CHECK_AND_ASSERT_MES(r, false, "Failed to call derive_ephemeral_key_helper(...)"); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 656856cb..b1c6ec19 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2024 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -96,22 +96,18 @@ namespace ph = boost::placeholders; } \ catch (const tools::error::transfer_error& e) \ { \ - LOG_ERROR("unknown transfer error: " << e.to_string()); \ - fail_msg_writer() << "unknown transfer error: " << e.what(); \ + fail_msg_writer() << "(transfer) " << e.what(); \ } \ catch (const tools::error::wallet_internal_error& e) \ { \ - LOG_ERROR("internal error: " << e.to_string()); \ - fail_msg_writer() << "internal error: " << e.what(); \ + fail_msg_writer() << "(internal) " << e.what(); \ } \ catch (const std::exception& e) \ { \ - LOG_ERROR("unexpected error: " << e.what()); \ - fail_msg_writer() << "unexpected error: " << e.what(); \ + fail_msg_writer() << "(unexpected) " << e.what(); \ } \ catch (...) \ { \ - LOG_ERROR("Unknown error"); \ fail_msg_writer() << "unknown error"; \ } \ @@ -521,7 +517,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) else { bool r = open_wallet(m_wallet_file, pwd_container.password()); - CHECK_AND_ASSERT_MES(r, false, "could not open account"); + CHECK_AND_ASSERT_MES(r, false, "wallet could not be opened"); was_open = true; } process_wallet_command_line_params(vm, *m_wallet, false); @@ -714,6 +710,10 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa if (!m_voting_config_file.empty()) m_wallet->set_votes_config_path(m_voting_config_file); + auto print_wallet_opened_msg = [&](){ + message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str(); + }; + while (true) { @@ -728,7 +728,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa } catch (const tools::error::wallet_load_notice_wallet_restored& /*e*/) { - message_writer(epee::log_space::console_color_white, true) << "Opened wallet: " << m_wallet->get_account().get_public_address_str(); + print_wallet_opened_msg(); message_writer(epee::log_space::console_color_red, true) << "NOTICE: Wallet file was damaged and restored."; break; } @@ -1797,6 +1797,12 @@ bool simple_wallet::print_address(const std::vector &args/* = std:: //---------------------------------------------------------------------------------------------------- bool simple_wallet::show_seed(const std::vector &args) { + if (m_wallet->is_watch_only()) + { + fail_msg_writer() << "watch-only wallet doesn't have the full set of keys, hence no seed phrase can be generated"; + return false; + } + CONFIRM_WITH_PASSWORD(); success_msg_writer() << "Please enter a password to secure this seed. Securing your seed is HIGHLY recommended. Leave password blank to stay unsecured."; success_msg_writer(true) << "Remember, restoring a wallet from Secured Seed can only be done if you know its password."; @@ -1984,12 +1990,10 @@ bool simple_wallet::save_watch_only(const std::vector &args) } catch (const std::exception& e) { - LOG_ERROR("unexpected error: " << e.what()); - fail_msg_writer() << "unexpected error: " << e.what(); + fail_msg_writer() << e.what(); } catch (...) { - LOG_ERROR("Unknown error"); fail_msg_writer() << "unknown error"; } return true; @@ -2053,12 +2057,10 @@ bool simple_wallet::sign_transfer(const std::vector &args) } catch (const std::exception& e) { - LOG_ERROR("unexpected error: " << e.what()); - fail_msg_writer() << "unexpected error: " << e.what(); + fail_msg_writer() << e.what(); } catch (...) { - LOG_ERROR("Unknown error"); fail_msg_writer() << "unknown error"; } return true; @@ -2079,12 +2081,10 @@ bool simple_wallet::submit_transfer(const std::vector &args) } catch (const std::exception& e) { - LOG_ERROR("unexpected error: " << e.what()); - fail_msg_writer() << "unexpected error: " << e.what(); + fail_msg_writer() << e.what(); } catch (...) { - LOG_ERROR("Unknown error"); fail_msg_writer() << "unknown error"; } return true; @@ -3270,7 +3270,7 @@ int main(int argc, char* argv[]) } else if (command_line::get_arg(vm, command_line::arg_version)) { - success_msg_writer() << CURRENCY_NAME << " wallet v" << PROJECT_VERSION_LONG; + success_msg_writer() << CURRENCY_NAME << " simplewallet v" << PROJECT_VERSION_LONG; exit_requested = true; return true; } @@ -3296,6 +3296,7 @@ int main(int argc, char* argv[]) std::string log_dir; log_dir = log_file_path.has_parent_path() ? log_file_path.parent_path().string() : log_space::log_singletone::get_default_log_folder(); log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str(), LOG_LEVEL_4); + LOG_PRINT_L0(ENDL << ENDL); message_writer(epee::log_space::console_color_white, true, std::string(), LOG_LEVEL_0) << CURRENCY_NAME << " simplewallet v" << PROJECT_VERSION_LONG; if (command_line::has_arg(vm, command_line::arg_log_level)) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f777d86d..6e6b939f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -757,7 +757,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t { // normal wallet, calculate and store key images for own outs currency::keypair in_ephemeral = AUTO_VAL_INIT(in_ephemeral); - currency::generate_key_image_helper(m_account.get_keys(), ptc.tx_pub_key, o, in_ephemeral, ki); + currency::generate_key_image_helper(m_account.get_keys(), ptc.tx_pub_key, /* output index */ o, in_ephemeral, ki); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(in_ephemeral.pub == out_key, "key_image generated ephemeral public key that does not match with output_key"); } @@ -4322,29 +4322,25 @@ void wallet2::sign_transfer(const std::string& tx_sources_blob, std::string& sig // assumed to be called from normal, non-watch-only wallet THROW_IF_FALSE_WALLET_EX(!m_watch_only, error::wallet_common_error, "watch-only wallet is unable to sign transfers, you need to use normal wallet for that"); - // decrypt the blob - std::string decrypted_src_blob = crypto::chacha_crypt(tx_sources_blob, m_account.get_keys().view_secret_key); + // decrypt the blob + std::string decrypted_src_blob = crypto::chacha_crypt(tx_sources_blob, m_account.get_keys().view_secret_key); // deserialize args - currency::finalized_tx ft = AUTO_VAL_INIT(ft); + currency::finalized_tx ft{}; bool r = t_unserializable_object_from_blob(ft.ftp, decrypted_src_blob); THROW_IF_FALSE_WALLET_EX(r, error::wallet_common_error, "Failed to decrypt tx sources blob"); // make sure unsigned tx was created with the same keys THROW_IF_FALSE_WALLET_EX(ft.ftp.spend_pub_key == m_account.get_keys().account_address.spend_public_key, error::wallet_common_error, "The was created in a different wallet, keys missmatch"); - finalize_transaction(ft.ftp, ft.tx, ft.one_time_key, false); + finalize_transaction(ft.ftp, ft, false, true); + + WLT_LOG_L0("sign_transfer: tx " << ft.tx_id << " has been successfully signed"); // calculate key images for each change output - crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX( - crypto::generate_key_derivation( - m_account.get_keys().account_address.view_public_key, - ft.one_time_key, - derivation), - "internal error: sign_transfer: failed to generate key derivation(" - << m_account.get_keys().account_address.view_public_key - << ", view secret key: " << ft.one_time_key << ")"); + crypto::key_derivation derivation{}; + r = crypto::generate_key_derivation(m_account.get_keys().account_address.view_public_key, ft.one_time_key, derivation); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "sign_transfer: generate_key_derivation failed, tx: " << ft.tx_id); for (size_t i = 0; i < ft.tx.vout.size(); ++i) { @@ -4354,7 +4350,7 @@ void wallet2::sign_transfer(const std::string& tx_sources_blob, std::string& sig crypto::public_key ephemeral_pub{}; if (!crypto::derive_public_key(derivation, i, m_account.get_keys().account_address.spend_public_key, ephemeral_pub)) { - WLT_LOG_ERROR("derive_public_key failed for tx " << get_transaction_hash(ft.tx) << ", out # " << i); + WLT_LOG_ERROR("derive_public_key failed for tx " << ft.tx_id << ", out # " << i); } if (out_pk == ephemeral_pub) @@ -4367,6 +4363,7 @@ void wallet2::sign_transfer(const std::string& tx_sources_blob, std::string& sig crypto::generate_key_image(ephemeral_pub, ephemeral_sec, ki); ft.outs_key_images.push_back(make_serializable_pair(static_cast(i), ki)); + WLT_LOG_L1("sign_transfer: tx " << ft.tx_id << ", out index: " << i << ", ki: " << ki); } } @@ -4495,6 +4492,9 @@ bool wallet2::attach_asset_descriptor(const wallet_public::COMMAND_ATTACH_ASSET_ //---------------------------------------------------------------------------------------------------- void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx) { + // assumed to be called from watch-only wallet + THROW_IF_FALSE_WALLET_EX(m_watch_only, error::wallet_common_error, "submit_transfer should be called in watch-only wallet only"); + // decrypt sources std::string decrypted_src_blob = crypto::chacha_crypt(signed_tx_blob, m_account.get_keys().view_secret_key); @@ -4505,9 +4505,36 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans tx = ft.tx; crypto::hash tx_hash = get_transaction_hash(tx); - // foolproof + // foolproof check THROW_IF_FALSE_WALLET_CMN_ERR_EX(ft.ftp.spend_pub_key == m_account.get_keys().account_address.spend_public_key, "The given tx was created in a different wallet, keys missmatch, tx hash: " << tx_hash); + // prepare and check data for watch-only outkey2ki before sending the tx + std::vector> pk_ki_to_be_added; + std::vector> tri_ki_to_be_added; + if (m_watch_only) + { + for (auto& p : ft.outs_key_images) + { + THROW_IF_FALSE_WALLET_INT_ERR_EX(p.first < tx.vout.size(), "outs_key_images has invalid out index: " << p.first << ", tx.vout.size() = " << tx.vout.size()); + std::list stub{}; + const crypto::public_key& pk = out_get_pub_key(tx.vout[p.first], stub); + pk_ki_to_be_added.push_back(std::make_pair(pk, p.second)); + } + + THROW_IF_FALSE_WALLET_INT_ERR_EX(tx.vin.size() == ft.ftp.sources.size(), "tx.vin and ft.ftp.sources sizes missmatch"); + for (size_t i = 0; i < tx.vin.size(); ++i) + { + const crypto::key_image& ki = get_key_image_from_txin_v(tx.vin[i]); + const auto& src = ft.ftp.sources[i]; + THROW_IF_FALSE_WALLET_INT_ERR_EX(src.real_output < src.outputs.size(), "src.real_output is out of bounds: " << src.real_output); + const crypto::public_key& out_key = src.outputs[src.real_output].stealth_address; + tri_ki_to_be_added.push_back(std::make_pair(src.transfer_index, ki)); + pk_ki_to_be_added.push_back(std::make_pair(out_key, ki)); + } + } + + // SEND the transaction + try { send_transaction_to_network(tx); @@ -4523,38 +4550,16 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans add_sent_tx_detailed_info(tx, ft.ftp.attachments, ft.ftp.prepared_destinations, ft.ftp.selected_transfers); m_tx_keys.insert(std::make_pair(tx_hash, ft.one_time_key)); + // populate and store key images from own outputs, because otherwise a watch-only wallet cannot calculate it if (m_watch_only) { - std::vector> pk_ki_to_be_added; - std::vector> tri_ki_to_be_added; - - for (auto& p : ft.outs_key_images) - { - THROW_IF_FALSE_WALLET_INT_ERR_EX(p.first < tx.vout.size(), "outs_key_images has invalid out index: " << p.first << ", tx.vout.size() = " << tx.vout.size()); - std::list stub{}; - const crypto::public_key& pk = out_get_pub_key(tx.vout[p.first], stub); - pk_ki_to_be_added.push_back(std::make_pair(pk, p.second)); - } - - THROW_IF_FALSE_WALLET_INT_ERR_EX(tx.vin.size() == ft.ftp.sources.size(), "tx.vin and ft.ftp.sources sizes missmatch"); - for (size_t i = 0; i < tx.vin.size(); ++i) - { - const crypto::key_image& ki = get_key_image_from_txin_v(tx.vin[i]); - - const auto& src = ft.ftp.sources[i]; - THROW_IF_FALSE_WALLET_INT_ERR_EX(src.real_output < src.outputs.size(), "src.real_output is out of bounds: " << src.real_output); - const crypto::public_key& out_key = src.outputs[src.real_output].stealth_address; - - tri_ki_to_be_added.push_back(std::make_pair(src.transfer_index, ki)); - pk_ki_to_be_added.push_back(std::make_pair(out_key, ki)); - } - for (auto& p : pk_ki_to_be_added) { auto it = m_pending_key_images.find(p.first); if (it != m_pending_key_images.end()) { - LOG_PRINT_YELLOW("warning: for tx " << tx_hash << " out pub key " << p.first << " already exist in m_pending_key_images, ki: " << it->second << ", proposed new ki: " << p.second, LOG_LEVEL_0); + if (it->second != p.second) + LOG_PRINT_YELLOW("warning: for tx " << tx_hash << " out pub key " << p.first << " already exist in m_pending_key_images, ki: " << it->second << ", proposed new ki: " << p.second, LOG_LEVEL_0); } else { diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 7479159b..12581bc5 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -71,10 +71,10 @@ namespace tools std::string to_string() const { std::ostringstream ss; - ss << m_loc << '[' << boost::replace_all_copy(std::string(typeid(*this).name()), "struct ", ""); + ss << '[' << boost::replace_all_copy(std::string(typeid(*this).name()), "struct ", ""); if (!m_error_code.empty()) ss << "[" << m_error_code << "]"; - ss << "] " << Base::what(); + ss << "] " << m_loc << ENDL << " " << Base::what(); return ss.str(); } From c637e16848d4e32ae9817cf146d0107ab50964df Mon Sep 17 00:00:00 2001 From: Dmitry Matsiukhov <46869283+dimmarvel@users.noreply.github.com> Date: Fri, 4 Jul 2025 01:41:53 +0300 Subject: [PATCH 26/65] unit_tests: added a test for pod array file container, fixed clear() (#535) * add test for pod array file container * add tests for pod, clear and is open * header update --------- Co-authored-by: sowle --- src/common/pod_array_file_container.h | 7 +- tests/unit_tests/pod_array_file_container.cpp | 364 ++++++++++++++++++ 2 files changed, 366 insertions(+), 5 deletions(-) create mode 100644 tests/unit_tests/pod_array_file_container.cpp diff --git a/src/common/pod_array_file_container.h b/src/common/pod_array_file_container.h index 8ac36270..e165480c 100644 --- a/src/common/pod_array_file_container.h +++ b/src/common/pod_array_file_container.h @@ -137,12 +137,9 @@ namespace tools // close and re-open stream with trunc bit m_stream.close(); - m_stream.open(m_filename, std::ios::binary | std::ios::trunc | std::ios::in); + m_stream.open(m_filename, std::ios::binary | std::ios::trunc | std::ios::in | std::ios::out); - if (m_stream.rdstate() != std::ios::eofbit) - return false; - - return true; + return is_opened_and_in_good_state(); } private: diff --git a/tests/unit_tests/pod_array_file_container.cpp b/tests/unit_tests/pod_array_file_container.cpp new file mode 100644 index 00000000..ba4615aa --- /dev/null +++ b/tests/unit_tests/pod_array_file_container.cpp @@ -0,0 +1,364 @@ +// Copyright (c) 2025 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "epee/include/include_base_utils.h" +#include "crypto/crypto.h" +#include "crypto/crypto-sugar.h" +#include "gtest/gtest.h" +#include +#include +#include +#include + +#include "common/pod_array_file_container.h" + +// helper: returns a unique temp file path +static boost::filesystem::path make_temp_file() +{ + return boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("pod_test_%%%%-%%%%.bin"); +} + +//====================================================================== +// typed test fixture for pod_array_file_container +// container = alias for pod_array_file_container +// tmp_path = temp file for test +// SetUp() = generate temp path (SetUp from ::testing::Test) +// TearDown() = remove temp file (TearDown from ::testing::Test) +//====================================================================== + +template +class pod_array_file_typed_test : public ::testing::Test +{ +protected: + using container = tools::pod_array_file_container; + boost::filesystem::path tmp_path; + + void SetUp() override + { + tmp_path = make_temp_file(); + } + + void TearDown() override + { + if (boost::filesystem::exists(tmp_path)) + boost::filesystem::remove(tmp_path); + } +}; + +// list of integral types to test +using integral_types = ::testing::Types< + int8_t, uint8_t, + int16_t, uint16_t, + int32_t, uint32_t, + int64_t, uint64_t +>; +// register typed tests +TYPED_TEST_CASE(pod_array_file_typed_test, integral_types); + +// push back and get items: +// write values [-1,0,1] and verify they are read back correctly +TYPED_TEST(pod_array_file_typed_test, push_back_and_get_items) +{ + typename TestFixture::container c; + ASSERT_TRUE(c.open(this->tmp_path.wstring(), true)); + + std::vector values = + { + static_cast(-1), + 0, + static_cast(1) + }; + + for (auto v : values) + ASSERT_TRUE(c.push_back(v)); + + EXPECT_EQ(c.size(), values.size()); + + TypeParam read_value; + for (size_t i = 0; i < values.size(); ++i) + { + ASSERT_TRUE(c.get_item(i, read_value)); + EXPECT_EQ(read_value, values[i]); + } +} + +// ensure get_item returns false for index >= size +TYPED_TEST(pod_array_file_typed_test, get_item_out_of_range) +{ + typename TestFixture::container c; + ASSERT_TRUE(c.open(this->tmp_path.wstring(), true)); + + TypeParam dummy; + EXPECT_FALSE(c.get_item(0, dummy)); + EXPECT_FALSE(c.get_item(100, dummy)); +} + +// -------------------------------------------------------------------- + +typedef uint32_t pod_t; +typedef tools::pod_array_file_container pod_container; + +// open fails if not exist without create: +// open() false when file missing and create_if_not_exist=false +TEST(pod_array_file_container, open_fails_if_not_exist_without_create) +{ + auto path = make_temp_file(); + pod_container c; + std::string reason; + bool opened = c.open(path.wstring(), false, nullptr, &reason); + EXPECT_FALSE(opened); + EXPECT_TRUE(reason.find("not exist") != std::string::npos); +} + +// open creates file when not exist: +// open() with create flag creates empty file and size=0 +TEST(pod_array_file_container, open_creates_file_when_not_exist) +{ + auto path = make_temp_file(); + pod_container c; + bool corrupted = true; + ASSERT_TRUE(c.open(path.wstring(), true, &corrupted, nullptr)); + EXPECT_FALSE(corrupted); + EXPECT_EQ(c.size(), 0u); + c.close(); + EXPECT_TRUE(boost::filesystem::exists(path)); +} + +// -------------------------------------------------------------------- + +// POD struct with fixed-size fields +struct test_struct +{ + crypto::public_key pubkey; + crypto::key_image key; +}; + +typedef tools::pod_array_file_container struct_container; + +// push back and get items struct: +// write two test_struct and verify memory equality +TEST(pod_array_file_container_struct, push_back_and_get_items_struct) +{ + auto path = make_temp_file(); + struct_container c; + ASSERT_TRUE(c.open(path.wstring(), true)); + + test_struct a1{}, a2{}; + + // use random values for pubkey and key + a1.pubkey = (crypto::scalar_t::random() * crypto::c_point_G).to_public_key(); + a1.key = (crypto::scalar_t::random() * crypto::c_point_G).to_key_image(); + a2.pubkey = (crypto::scalar_t::random() * crypto::c_point_G).to_public_key(); + a2.key = (crypto::scalar_t::random() * crypto::c_point_G).to_key_image(); + + ASSERT_TRUE(c.push_back(a1)); + ASSERT_TRUE(c.push_back(a2)); + EXPECT_EQ(c.size(), 2u); + + test_struct got; + ASSERT_TRUE(c.get_item(0, got)); + EXPECT_EQ(got.pubkey, a1.pubkey); + EXPECT_EQ(got.key, a1.key); + ASSERT_TRUE(c.get_item(1, got)); + EXPECT_EQ(got.pubkey, a2.pubkey); + EXPECT_EQ(got.key, a2.key); +} + +// get item out of range struct: +// get_item false when no items written +TEST(pod_array_file_container_struct, get_item_out_of_range_struct) +{ + auto path = make_temp_file(); + struct_container c; + ASSERT_TRUE(c.open(path.wstring(), true)); + test_struct dummy; + EXPECT_FALSE(c.get_item(0, dummy)); +} + +// corrupted file truncation struct: +// simulate corrupted file tail and check truncation flag and size +TEST(pod_array_file_container_struct, corrupted_file_truncation_struct) +{ + auto path = make_temp_file(); + { + // write a valid test_struct followed by garbage data + boost::filesystem::ofstream out(path, std::ios::binary | std::ios::out); + test_struct tmp{}; + std::fill(std::begin(tmp.pubkey.data), std::end(tmp.pubkey.data), 'X'); + std::fill(std::begin(tmp.key.data), std::end(tmp.key.data), 'Y'); + out.write(reinterpret_cast(&tmp), sizeof(tmp)); + const char garbage[5] = {1,2,3,4,5}; + out.write(garbage, sizeof(garbage)); + } + + struct_container c; + bool corrupted = false; + std::string reason; + ASSERT_TRUE(c.open(path.wstring(), false, &corrupted, &reason)); + EXPECT_TRUE(corrupted); + EXPECT_EQ(c.size(), 1u); + + test_struct got; + ASSERT_TRUE(c.get_item(0, got)); + + for (size_t i = 0; i < sizeof(got.pubkey.data); ++i) + EXPECT_EQ(got.pubkey.data[i], 'X'); + for (size_t i = 0; i < sizeof(got.key.data); ++i) + EXPECT_EQ(got.key.data[i], 'Y'); + + EXPECT_TRUE(reason.find("truncated") != std::string::npos); +} + +// persistence between opens struct: +// write multiple structs, reopen file, verify data persists +TEST(pod_array_file_container_struct, persistence_between_opens_struct) +{ + auto path = make_temp_file(); + { + // write 3 test_struct with different pubkey and key values + struct_container c; + ASSERT_TRUE(c.open(path.wstring(), true)); + for (int i = 0; i < 3; ++i) + { + test_struct tmp{}; + tmp.pubkey.data[0] = '0' + i; + tmp.key.data[0] = 'A' + i; + ASSERT_TRUE(c.push_back(tmp)); + } + EXPECT_EQ(c.size(), 3u); + } + + // reopen and verify data + struct_container c2; + ASSERT_TRUE(c2.open(path.wstring(), false)); + EXPECT_EQ(c2.size(), 3u); + test_struct got; + for (int i = 0; i < 3; ++i) + { + ASSERT_TRUE(c2.get_item(i, got)); + EXPECT_EQ(got.pubkey.data[0], '0' + i); + EXPECT_EQ(got.key.data[0], 'A' + i); + } +} + +// size bytes and size: +// check size_bytes() matches raw byte count and size() element count +TEST(pod_array_file_container, size_bytes_and_size) +{ + auto path = make_temp_file(); + pod_container c; + ASSERT_TRUE(c.open(path.wstring(), true)); + EXPECT_EQ(c.size_bytes(), 0u); + EXPECT_EQ(c.size(), 0u); + // push one element + pod_t value = 42; + ASSERT_TRUE(c.push_back(value)); + EXPECT_EQ(c.size_bytes(), sizeof(pod_t)); + EXPECT_EQ(c.size(), 1u); +} + +// operations after close: +// ensure push_back and get_item fail after close() +TEST(pod_array_file_container, operations_after_close) +{ + auto path = make_temp_file(); + pod_container c; + ASSERT_TRUE(c.open(path.wstring(), true)); + ASSERT_TRUE(c.push_back(123u)); + c.close(); + // after close, operations should return false + EXPECT_FALSE(c.push_back(456u)); + pod_t dummy = 0; + EXPECT_FALSE(c.get_item(0, dummy)); +} + +// open fails if cannot open (directory): +// attempt to open a directory path should fail with "file could not be opened" +TEST(pod_array_file_container, open_fails_if_cannot_open) +{ + // create a directory instead of a file + auto dir_path = make_temp_file(); + boost::filesystem::create_directory(dir_path); + pod_container c; + std::string reason; + bool opened = c.open(dir_path.wstring(), true, nullptr, &reason); + EXPECT_FALSE(opened); + EXPECT_TRUE(reason.find("could not be opened") != std::string::npos); + boost::filesystem::remove(dir_path); +} + +// corrupted file truncation uint32: +// simulate corrupted file tail on uint32_t and check truncation +TEST(pod_array_file_container, corrupted_file_truncation_uint32) +{ + auto path = make_temp_file(); + { + boost::filesystem::ofstream out(path, std::ios::binary | std::ios::out); + pod_t v = 0x12345678u; + out.write(reinterpret_cast(&v), sizeof(v)); + const char junk[3] = {9,8,7}; + out.write(junk, sizeof(junk)); + } + pod_container c; + bool corrupted = false; + std::string reason; + ASSERT_TRUE(c.open(path.wstring(), false, &corrupted, &reason)); + EXPECT_TRUE(corrupted); + EXPECT_EQ(c.size(), 1u); + pod_t read_v; + ASSERT_TRUE(c.get_item(0, read_v)); + EXPECT_EQ(read_v, 0x12345678u); + EXPECT_TRUE(reason.find("truncated") != std::string::npos); +} + +// operations without open: +// ensure push_back/get_item/size_bytes/size behave when container never opened +TEST(pod_array_file_container, operations_without_open) +{ + pod_container c; + EXPECT_FALSE(c.push_back(1u)); + pod_t dummy; + EXPECT_FALSE(c.get_item(0, dummy)); + EXPECT_EQ(c.size_bytes(), 0u); + EXPECT_EQ(c.size(), 0u); +} + +// checks stream state transitions +TEST(pod_array_file_container, is_opened_and_in_good_state) +{ + auto path = make_temp_file(); + pod_container c; + + // not opened yet + EXPECT_FALSE(c.is_opened_and_in_good_state()); + + // open for create + ASSERT_TRUE(c.open(path.wstring(), true)); + EXPECT_TRUE(c.is_opened_and_in_good_state()); + + // after close + c.close(); + EXPECT_FALSE(c.is_opened_and_in_good_state()); +} + +// wipes file contents and resets size +TEST(pod_array_file_container, clear_resets_file) +{ + auto path = make_temp_file(); + pod_container c; + ASSERT_TRUE(c.open(path.wstring(), true)); + + // add some elements + ASSERT_TRUE(c.push_back(123u)); + ASSERT_TRUE(c.push_back(456u)); + EXPECT_EQ(c.size(), 2u); + + // clear the container + ASSERT_TRUE(c.clear()); + EXPECT_EQ(c.size(), 0u); + + // file should still be usable + ASSERT_TRUE(c.push_back(789u)); + EXPECT_EQ(c.size(), 1u); +} \ No newline at end of file From 035a441efeae3aaa530d75fe71112c63b1c189e3 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 8 Jul 2025 02:42:42 +0300 Subject: [PATCH 27/65] wallet2: dump_transfers now prints asset id instead of key images +typo fixed --- src/simplewallet/simplewallet.cpp | 6 ++-- src/simplewallet/simplewallet.h | 2 +- src/wallet/wallet2.cpp | 24 ++++++++++------ src/wallet/wallet2.h | 4 +-- tests/core_tests/chaingen.cpp | 6 ++-- .../escrow_wallet_altchain_test.cpp | 4 +-- tests/core_tests/escrow_wallet_tests.cpp | 28 +++++++++---------- tests/core_tests/multisig_wallet_tests.cpp | 4 +-- tests/core_tests/offers_test.cpp | 4 +-- tests/core_tests/pos_validation.cpp | 6 ++-- tests/core_tests/wallet_tests.cpp | 2 +- 11 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index b1c6ec19..4178ddee 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -298,7 +298,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("export_recent_transfers", boost::bind(&simple_wallet::export_recent_transfers, this, ph::_1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt"); m_cmd_binder.set_handler("list_outputs", boost::bind(&simple_wallet::list_outputs, this, ph::_1), "list_outputs [spent|unspent] [ticker=ZANO] [unknown] - Lists all the outputs. The result may be filtered by spent status, asset ticker or unknown asset ids."); m_cmd_binder.set_handler("lo", boost::bind(&simple_wallet::list_outputs, this, ph::_1), "alias for list_outputs"); - m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_trunsfers, this, ph::_1), "dump_transfers - Write transfers in json to dump_transfers.txt"); + m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_transfers, this, ph::_1), "dump_transfers - Write transfers in json to dump_transfers.txt"); m_cmd_binder.set_handler("dump_keyimages", boost::bind(&simple_wallet::dump_key_images, this, ph::_1), "dump_keyimages - Write key_images in json to dump_key_images.txt"); m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, ph::_1), "payments [ ... ] - Show payments , ... "); m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this,ph::_1), "Show blockchain height"); @@ -1184,12 +1184,12 @@ bool simple_wallet::export_recent_transfers(const std::vector& args return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::dump_trunsfers(const std::vector& args) +bool simple_wallet::dump_transfers(const std::vector& args) { stringstream ss; success_msg_writer() << "Generating text...."; - m_wallet->dump_trunsfers(ss); + m_wallet->dump_transfers(ss); success_msg_writer() << "Storing text to dump_transfers.txt...."; file_io_utils::save_string_to_file(log_space::log_singletone::get_default_log_folder() + "/dump_transfers.txt", ss.str()); success_msg_writer() << "Done...."; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index afc07ec8..6577b6a7 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -58,7 +58,7 @@ namespace currency bool show_balance(const std::vector &args = std::vector()); bool list_recent_transfers(const std::vector& args); bool export_recent_transfers(const std::vector& args); - bool dump_trunsfers(const std::vector& args); + bool dump_transfers(const std::vector& args); bool dump_key_images(const std::vector& args); bool show_incoming_transfers(const std::vector &args); bool show_staking_history(const std::vector& args); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6e6b939f..59107e5f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5921,9 +5921,9 @@ struct local_transfers_struct END_KV_SERIALIZE_MAP() }; -void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose, const crypto::public_key& asset_id) const +void wallet2::dump_transfers(std::stringstream& ss, bool verbose, const crypto::public_key& asset_id_to_filter) const { - bool filter_by_asset_id = asset_id != currency::null_pkey; + bool filter_by_asset_id = asset_id_to_filter != currency::null_pkey; if (verbose) { @@ -5933,7 +5933,7 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose, const crypto:: { uint64_t i = tr.first; const transfer_details& td = tr.second; - if (filter_by_asset_id && td.get_asset_id() != asset_id) + if (filter_by_asset_id && td.get_asset_id() != asset_id_to_filter) continue; ss << "{ \"i\": " << i << "," << ENDL; ss << "\"entry\": " << epee::serialization::store_t_to_json(td) << "}," << ENDL; @@ -5942,16 +5942,22 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose, const crypto:: else { boost::io::ios_flags_saver ifs(ss); - ss << "index amount spent_h g_index block block_ts flg tx out# key image" << ENDL; + ss << "index amount spent_h g_index block block_ts flg tx out# asset id" << ENDL; for (const auto& tr : m_transfers) { uint64_t i = tr.first; const transfer_details& td = tr.second; - if (filter_by_asset_id && td.get_asset_id() != asset_id) + const crypto::public_key asset_id = td.get_asset_id(); + if (filter_by_asset_id && asset_id != asset_id_to_filter) continue; + + uint32_t asset_flags = 0; + currency::asset_descriptor_base asset_info{}; + get_asset_info(asset_id, asset_info, asset_flags); + ss << std::right << std::setw(5) << i << " " << - std::setw(21) << print_money(td.amount()) << " " << + std::setw(21) << print_money(td.amount(), asset_info.decimal_point) << " " << std::setw(7) << td.m_spent_height << " " << std::setw(7) << td.m_global_output_index << " " << std::setw(6) << td.m_ptx_wallet_info->m_block_height << " " << @@ -5959,15 +5965,15 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose, const crypto:: std::setw(4) << td.m_flags << " " << get_transaction_hash(td.m_ptx_wallet_info->m_tx) << " " << std::setw(4) << td.m_internal_output_index << " " << - td.m_key_image << ENDL; + (asset_id == native_coin_asset_id ? std::string() : crypto::pod_to_hex(asset_id)) << ENDL; } } } //---------------------------------------------------------------------------------------------------- -std::string wallet2::dump_trunsfers(bool verbose, const crypto::public_key& asset_id) const +std::string wallet2::dump_transfers(bool verbose, const crypto::public_key& asset_id) const { std::stringstream ss; - dump_trunsfers(ss, verbose, asset_id); + dump_transfers(ss, verbose, asset_id); return ss.str(); } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 9f440c8a..4d3fa218 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -683,8 +683,8 @@ namespace tools void scan_tx_to_key_inputs(std::vector& found_transfers, const currency::transaction& tx); // asset_id = null_pkey means no filtering by asset id - void dump_trunsfers(std::stringstream& ss, bool verbose = true, const crypto::public_key& asset_id = currency::null_pkey) const; - std::string dump_trunsfers(bool verbose = false, const crypto::public_key& asset_id = currency::null_pkey) const; + void dump_transfers(std::stringstream& ss, bool verbose = true, const crypto::public_key& asset_id = currency::null_pkey) const; + std::string dump_transfers(bool verbose = false, const crypto::public_key& asset_id = currency::null_pkey) const; void dump_key_images(std::stringstream& ss); void get_multisig_transfers(multisig_transfer_container& ms_transfers); const multisig_transfer_container& get_multisig_transfers() const { return m_multisig_transfers; } diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index cf9c1af1..d6931f65 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -684,7 +684,7 @@ bool test_generator::find_kernel(const std::list& accs, for (size_t wallet_index = 0, size = wallets.size(); wallet_index < size; ++wallet_index) { std::shared_ptr w = wallets[wallet_index].wallet; - LOG_PRINT_L0("wallet #" << wallet_index << " @ block " << w->get_top_block_height() << ENDL << wallets[wallet_index].wallet->dump_trunsfers()); + LOG_PRINT_L0("wallet #" << wallet_index << " @ block " << w->get_top_block_height() << ENDL << wallets[wallet_index].wallet->dump_transfers()); } return false; @@ -2190,7 +2190,7 @@ bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name, if (!r) { - LOG_PRINT(account_name << "'s transfers for asset_id " << asset_id << ": " << ENDL << w.dump_trunsfers(false, asset_id), LOG_LEVEL_0); + LOG_PRINT(account_name << "'s transfers for asset_id " << asset_id << ": " << ENDL << w.dump_transfers(false, asset_id), LOG_LEVEL_0); } return r; @@ -2451,7 +2451,7 @@ bool refresh_wallet_and_check_balance(const char* intro_log_message, const char* if (print_transfers) { - LOG_PRINT_CYAN(wallet_name << "'s transfers: " << ENDL << wallet->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN(wallet_name << "'s transfers: " << ENDL << wallet->dump_transfers(), LOG_LEVEL_0); } CHECK_AND_ASSERT_MES(check_balance_via_wallet(*wallet.get(), wallet_name, expected_total, expected_mined, expected_unlocked, expected_awaiting_in, expected_awaiting_out), false, ""); diff --git a/tests/core_tests/escrow_wallet_altchain_test.cpp b/tests/core_tests/escrow_wallet_altchain_test.cpp index 514ebc82..69fd0ab4 100644 --- a/tests/core_tests/escrow_wallet_altchain_test.cpp +++ b/tests/core_tests/escrow_wallet_altchain_test.cpp @@ -319,7 +319,7 @@ bool escrow_altchain_meta_impl::c1(currency::core& c, size_t ev_index, const std alice_wlt->refresh(blocks_fetched); //fetched blocks disabled since resync might happened on different situation and number of blocks_fetched might be unexpected //CHECK_AND_ASSERT_MES(blocks_fetched == se.expected_blocks, false, "Alice got " << blocks_fetched << " after refresh, but " << se.expected_blocks << " is expected"); - LOG_PRINT_GREEN("Alice's transfers:" << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_1); + LOG_PRINT_GREEN("Alice's transfers:" << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_1); if (se.a_balance != UINT64_MAX) { uint64_t alice_balance = alice_wlt->balance(); @@ -338,7 +338,7 @@ bool escrow_altchain_meta_impl::c1(currency::core& c, size_t ev_index, const std bob_wlt->refresh(blocks_fetched); //fetched blocks disabled since resync might happened on different situation and number of blocks_fetched might be unexpected //CHECK_AND_ASSERT_MES(blocks_fetched == se.expected_blocks, false, "Bob got " << blocks_fetched << " after refresh, but " << se.expected_blocks << " is expected"); - LOG_PRINT_GREEN("Bob's transfers:" << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_1); + LOG_PRINT_GREEN("Bob's transfers:" << ENDL << bob_wlt->dump_transfers(), LOG_LEVEL_1); if (se.b_balance != UINT64_MAX) { uint64_t bob_balance = bob_wlt->balance(); diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index b5c71e29..0f0bbd6c 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -759,7 +759,7 @@ bool escrow_proposal_expiration::c1(currency::core& c, size_t ev_index, const st bob_wlt->refresh(); uint64_t alice_start_balance = alice_wlt->balance(); - LOG_PRINT_CYAN("Alice's wallet transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("Alice's wallet transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -777,7 +777,7 @@ bool escrow_proposal_expiration::c1(currency::core& c, size_t ev_index, const st transaction proposal_tx = AUTO_VAL_INIT(proposal_tx); transaction escrow_template_tx = AUTO_VAL_INIT(escrow_template_tx); alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_period, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, "", proposal_tx, escrow_template_tx); - LOG_PRINT_CYAN("alice transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("alice transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0); uint64_t alice_post_proposal_balance = alice_wlt->balance(); uint64_t alice_post_proposal_balance_expected = alice_start_balance - TESTS_DEFAULT_FEE; CHECK_AND_ASSERT_MES(alice_post_proposal_balance == alice_post_proposal_balance_expected, false, "Incorrect alice_post_proposal_balance: " << print_money(alice_post_proposal_balance) << ", expected: " << print_money(alice_post_proposal_balance_expected)); @@ -840,9 +840,9 @@ bool escrow_proposal_expiration::c2(currency::core& c, size_t ev_index, const st bob_wlt->refresh(); uint64_t alice_start_balance = alice_wlt->balance(); - LOG_PRINT_CYAN("Alice's wallet transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("Alice's wallet transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0); uint64_t bob_start_balance = bob_wlt->balance(); - LOG_PRINT_CYAN("Bob's wallet transfers: " << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("Bob's wallet transfers: " << ENDL << bob_wlt->dump_transfers(), LOG_LEVEL_0); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -860,7 +860,7 @@ bool escrow_proposal_expiration::c2(currency::core& c, size_t ev_index, const st transaction proposal_tx = AUTO_VAL_INIT(proposal_tx); transaction escrow_template_tx = AUTO_VAL_INIT(escrow_template_tx); alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_period, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, "", proposal_tx, escrow_template_tx); - LOG_PRINT_CYAN("%%%%% Escrow proposal sent, Alice's transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("%%%%% Escrow proposal sent, Alice's transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0); CHECK_AND_ASSERT_MES(check_wallet_balance_blocked_for_escrow(*alice_wlt.get(), "Alice", cpd.amount_a_pledge + cpd.amount_to_pay), false, ""); crypto::hash ms_id = get_multisig_out_id(escrow_template_tx, get_multisig_out_index(escrow_template_tx.vout)); CHECK_AND_ASSERT_MES(ms_id != null_hash, false, "Can't obtain multisig id from escrow template tx"); @@ -996,7 +996,7 @@ bool escrow_proposal_and_accept_expiration::c1(currency::core& c, size_t ev_inde transaction proposal_tx = AUTO_VAL_INIT(proposal_tx); transaction escrow_template_tx = AUTO_VAL_INIT(escrow_template_tx); alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_period, TESTS_DEFAULT_FEE, b_release_fee, "", proposal_tx, escrow_template_tx); - LOG_PRINT_CYAN("%%%%% Escrow proposal sent, Alice's transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("%%%%% Escrow proposal sent, Alice's transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0); CHECK_AND_ASSERT_MES(check_wallet_balance_blocked_for_escrow(*alice_wlt.get(), "Alice", cpd.amount_a_pledge + cpd.amount_to_pay), false, ""); crypto::hash ms_id = get_multisig_out_id(escrow_template_tx, get_multisig_out_index(escrow_template_tx.vout)); @@ -1021,8 +1021,8 @@ bool escrow_proposal_and_accept_expiration::c1(currency::core& c, size_t ev_inde CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Alice", alice_wlt, tools::wallet_public::escrow_contract_details::contract_accepted, ms_id, 0), false, ""); CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Bob", bob_wlt, tools::wallet_public::escrow_contract_details::contract_accepted, ms_id, 0), false, ""); - LOG_PRINT_CYAN("%%%%% Escrow proposal accepted (unconfirmed), Alice's transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0); - LOG_PRINT_CYAN("%%%%% Escrow proposal accepted (unconfirmed), Bob's transfers: " << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("%%%%% Escrow proposal accepted (unconfirmed), Alice's transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("%%%%% Escrow proposal accepted (unconfirmed), Bob's transfers: " << ENDL << bob_wlt->dump_transfers(), LOG_LEVEL_0); // mine a few blocks with no txs @@ -1047,8 +1047,8 @@ bool escrow_proposal_and_accept_expiration::c1(currency::core& c, size_t ev_inde CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Alice", alice_wlt, tools::wallet_public::escrow_contract_details::contract_accepted, ms_id, TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW + 1), false, ""); CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Bob", bob_wlt, tools::wallet_public::escrow_contract_details::contract_accepted, ms_id, TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW + 1), false, ""); - LOG_PRINT_CYAN("%%%%% Escrow acceptance tx expired and removed from tx pool, Alice's transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0); - LOG_PRINT_CYAN("%%%%% Escrow acceptance tx expired and removed from tx pool, Bob's transfers: " << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("%%%%% Escrow acceptance tx expired and removed from tx pool, Alice's transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("%%%%% Escrow acceptance tx expired and removed from tx pool, Bob's transfers: " << ENDL << bob_wlt->dump_transfers(), LOG_LEVEL_0); // try to accept expired proposal once again -- an exception should be thrown r = false; @@ -1318,7 +1318,7 @@ bool escrow_incorrect_proposal_acceptance::check_normal_acceptance(currency::cor std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); alice_wlt->refresh(); std::stringstream ss; - alice_wlt->dump_trunsfers(ss, false); + alice_wlt->dump_transfers(ss, false); LOG_PRINT_L0("check_normal_acceptance(" << release_instruction << "):" << ENDL << "Alice transfers: " << ENDL << ss.str()); uint64_t alice_balance = alice_wlt->balance(); uint64_t alice_balance_expected = m_alice_bob_start_amount - m_cpd.amount_a_pledge - m_cpd.amount_to_pay - TESTS_DEFAULT_FEE; @@ -1392,7 +1392,7 @@ bool escrow_incorrect_proposal_acceptance::check_incorrect_acceptance(currency:: alice_wlt->refresh(); uint64_t alice_balance = alice_wlt->balance(); std::stringstream ss; - alice_wlt->dump_trunsfers(ss, false); + alice_wlt->dump_transfers(ss, false); LOG_PRINT_L0("check_incorrect_acceptance(" << param << "):" << ENDL << "Alice balance: " << print_money(alice_balance) << ", transfers: " << ENDL << ss.str()); tools::escrow_contracts_container contracts; @@ -2110,7 +2110,7 @@ bool escrow_incorrect_cancel_proposal::check_normal_cancel_proposal(currency::co std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); alice_wlt->refresh(); std::stringstream ss; - alice_wlt->dump_trunsfers(ss, false); + alice_wlt->dump_transfers(ss, false); LOG_PRINT_L0("check_normal_cancel_proposal:" << ENDL << "Alice transfers: " << ENDL << ss.str()); uint64_t alice_balance = alice_wlt->balance(); uint64_t alice_balance_expected = m_alice_bob_start_amount - m_cpd.amount_a_pledge - m_cpd.amount_to_pay - TESTS_DEFAULT_FEE - TESTS_DEFAULT_FEE; // one fee for escrow request, second - for cancel request @@ -2198,7 +2198,7 @@ bool escrow_incorrect_cancel_proposal::check_incorrect_cancel_proposal_internal( std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); alice_wlt->refresh(); std::stringstream ss; - alice_wlt->dump_trunsfers(ss, false); + alice_wlt->dump_transfers(ss, false); LOG_PRINT_L0("Alice transfers: " << ENDL << ss.str()); uint64_t alice_balance = alice_wlt->balance(); uint64_t alice_balance_expected = m_alice_bob_start_amount - m_cpd.amount_a_pledge - m_cpd.amount_to_pay - TESTS_DEFAULT_FEE - TESTS_DEFAULT_FEE; // one fee for escrow request, second - for cancel request diff --git a/tests/core_tests/multisig_wallet_tests.cpp b/tests/core_tests/multisig_wallet_tests.cpp index 4c2dc2dc..55afd1f0 100644 --- a/tests/core_tests/multisig_wallet_tests.cpp +++ b/tests/core_tests/multisig_wallet_tests.cpp @@ -2576,7 +2576,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co alice_wlt->scan_tx_pool(stub); alice_wlt->get_transfers(transfers); - CHECK_AND_ASSERT_MES(transfers.size() == 0, false, "incorrect transfers size for Alice: " << transfers.size() << "\n" << alice_wlt->dump_trunsfers()); + CHECK_AND_ASSERT_MES(transfers.size() == 0, false, "incorrect transfers size for Alice: " << transfers.size() << "\n" << alice_wlt->dump_transfers()); alice_wlt->get_unconfirmed_transfers(unconfirmed_transfers); CHECK_AND_ASSERT_MES(unconfirmed_transfers.size() == 1, false, "incorrect unconfirmed transfers size for Alice: " << unconfirmed_transfers.size()); CHECK_AND_ASSERT_MES(alice_wlt->get_multisig_transfers().size() == 1, false, "incorrect multisig transfers size for Alice: " << alice_wlt->get_multisig_transfers().size()); @@ -2590,7 +2590,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co transfers.clear(); unconfirmed_transfers.clear(); alice_wlt->get_transfers(transfers); - CHECK_AND_ASSERT_MES(transfers.size() == 0, false, "incorrect transfers size for Alice: " << transfers.size() << "\n" << alice_wlt->dump_trunsfers()); + CHECK_AND_ASSERT_MES(transfers.size() == 0, false, "incorrect transfers size for Alice: " << transfers.size() << "\n" << alice_wlt->dump_transfers()); alice_wlt->get_unconfirmed_transfers(unconfirmed_transfers); CHECK_AND_ASSERT_MES(unconfirmed_transfers.size() == 1, false, "incorrect unconfirmed transfers size for Alice: " << unconfirmed_transfers.size()); CHECK_AND_ASSERT_MES(alice_wlt->get_multisig_transfers().size() == 1, false, "incorrect multisig transfers size for Alice: " << alice_wlt->get_multisig_transfers().size()); diff --git a/tests/core_tests/offers_test.cpp b/tests/core_tests/offers_test.cpp index 39c115ae..2812838b 100644 --- a/tests/core_tests/offers_test.cpp +++ b/tests/core_tests/offers_test.cpp @@ -658,7 +658,7 @@ bool offer_removing_and_selected_output::check_offers(currency::core& c, size_t std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); alice_wlt->refresh(); - LOG_PRINT_CYAN("Alice's transfers:" << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("Alice's transfers:" << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0); uint64_t alice_start_balance = alice_wlt->balance(); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -1354,7 +1354,7 @@ bool offer_cancellation_with_zero_fee::c1(currency::core& c, size_t ev_index, co bool r = false; std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); miner_wlt->refresh(); - LOG_PRINT_CYAN("Miners's transfers:" << ENDL << miner_wlt->dump_trunsfers(), LOG_LEVEL_0); + LOG_PRINT_CYAN("Miners's transfers:" << ENDL << miner_wlt->dump_transfers(), LOG_LEVEL_0); uint64_t miner_start_balance = miner_wlt->balance(); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); diff --git a/tests/core_tests/pos_validation.cpp b/tests/core_tests/pos_validation.cpp index 539b9259..d02d4bbc 100644 --- a/tests/core_tests/pos_validation.cpp +++ b/tests/core_tests/pos_validation.cpp @@ -53,7 +53,7 @@ bool gen_pos_coinstake_already_spent::generate(std::vector& ev CREATE_TEST_WALLET(miner_wlt, miner, blk_0); REFRESH_TEST_WALLET_AT_GEN_TIME(events, miner_wlt, blk_2, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); - LOG_PRINT_L0("miner's transfers:" << ENDL << miner_wlt->dump_trunsfers(false)); + LOG_PRINT_L0("miner's transfers:" << ENDL << miner_wlt->dump_transfers(false)); // Legend: (n) - PoW block, [m] - PoS block // 0 1 11 12 13 <-- blockchain height (assuming CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10) @@ -782,7 +782,7 @@ void pos_wallet_minting_same_amount_diff_outs::dump_wallets_entries(const std::v LOG_PRINT2(LOG2_FILENAME, ENDL << ENDL << ENDL << ENDL << ENDL << ENDL, LOG_LEVEL_0); for (size_t i = 0; i < minting_wallets.size(); ++i) { - LOG_PRINT2(LOG2_FILENAME, "wallet #" << i << ":" << ENDL << minting_wallets[i].w->dump_trunsfers() << ENDL, LOG_LEVEL_0); + LOG_PRINT2(LOG2_FILENAME, "wallet #" << i << ":" << ENDL << minting_wallets[i].w->dump_transfers() << ENDL, LOG_LEVEL_0); } #undef LOG2_FILENAME } @@ -860,7 +860,7 @@ bool pos_wallet_big_block_test::c1(currency::core& c, size_t ev_index, const std miner_wlt->refresh(); miner_wlt->scan_tx_pool(stub_bool); - LOG_PRINT_L0("miner transfers:" << ENDL << miner_wlt->dump_trunsfers(false)); + LOG_PRINT_L0("miner transfers:" << ENDL << miner_wlt->dump_transfers(false)); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect number of txs in the pool: " << c.get_pool_transactions_count()); diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index f7d10647..88da1f6e 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -2988,7 +2988,7 @@ bool mined_balance_wallet_test::c1(currency::core& c, size_t ev_index, const std miner_wlt->refresh(); std::stringstream ss; - miner_wlt->dump_trunsfers(ss, false); + miner_wlt->dump_transfers(ss, false); LOG_PRINT_CYAN("miner transfers: " << ENDL << ss.str(), LOG_LEVEL_0); CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt.get(), "miner", miner_mined_money, miner_mined_money), false, "wrong balance"); From 04364afc530530d91f6422b628f10b19c690741f Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 8 Jul 2025 02:44:05 +0300 Subject: [PATCH 28/65] coretests: wallet_rpc_cold_signing test improved to cover asset transferring along with native coins (exposes a bug) --- tests/core_tests/wallet_rpc_tests.cpp | 60 ++++++++++++++++++++------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index a7e99ab7..b6ebd12a 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -1217,12 +1217,7 @@ bool wallet_rpc_cold_signing::generate(std::vector& events) co MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); DO_CALLBACK(events, "configure_core"); - REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); - - MAKE_TX(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(100), blk_0r); - MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); - - REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); DO_CALLBACK(events, "c1"); @@ -1277,6 +1272,39 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: bob_wlt->refresh(); check_balance_via_wallet(*bob_wlt, "Bob", 0, 0, 0, 0, 0); + // for post HF4 cases transfer some assets along with native coins + crypto::public_key deployed_asset_id{}; + size_t deployed_asset_decimal_point = 0; + const bool use_assets = c.get_blockchain_storage().is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM); + if (use_assets) + { + // miner deploys new asset and sends 50 coins of it to Alice + tools::wallet_rpc_server miner_rpc(miner_wlt); + tools::wallet_public::COMMAND_ASSETS_DEPLOY::request req_deploy{}; + req_deploy.asset_descriptor.current_supply = 50; + req_deploy.asset_descriptor.decimal_point = deployed_asset_decimal_point; + req_deploy.asset_descriptor.full_name = "50 pounds per person"; + req_deploy.asset_descriptor.ticker = "50PPP"; + req_deploy.asset_descriptor.total_max_supply = 200; // for a family of four + req_deploy.destinations.emplace_back(tools::wallet_public::transfer_destination{50, m_accounts[ALICE_ACC_IDX].get_public_address_str(), null_pkey}); + req_deploy.do_not_split_destinations = true; + tools::wallet_public::COMMAND_ASSETS_DEPLOY::response res_deploy{}; + r = invoke_text_json_for_rpc(miner_rpc, "deploy_asset", req_deploy, res_deploy); + CHECK_AND_ASSERT_MES(r, false, "RPC 'deploy_asset' failed"); + deployed_asset_id = res_deploy.new_asset_id; + } + + // also, send some native coins + miner_wlt->transfer(MK_TEST_COINS(100), m_accounts[ALICE_ACC_IDX].get_public_address(), native_coin_asset_id); + + // confirm this tx and mine 10 block to unlock the coins + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == (use_assets ? 2 : 1), false, "enexpected pool txs count: " << c.get_pool_transactions_count()); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); + + // Alice: prepare watch-only wallet + account_base alice_acc_wo = m_accounts[ALICE_ACC_IDX]; alice_acc_wo.make_account_watch_only(); std::shared_ptr alice_wlt_wo = init_playtime_test_wallet(events, c, alice_acc_wo); @@ -1297,17 +1325,17 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: tools::wallet_rpc_server alice_rpc(alice_wlt); std::shared_ptr alice_rpc_wo_ptr{ new tools::wallet_rpc_server(alice_wlt_wo) }; - // send a cold-signed transaction + // send a cold-signed transaction: Alice -> Bob; 50 test coins + 50 of the asset tools::wallet_public::COMMAND_RPC_TRANSFER::request req{}; - req.destinations.emplace_back(); - req.destinations.back().amount = MK_TEST_COINS(50); - req.destinations.back().address = m_accounts[BOB_ACC_IDX].get_public_address_str(); + req.destinations.emplace_back(tools::wallet_public::transfer_destination{MK_TEST_COINS(50), m_accounts[BOB_ACC_IDX].get_public_address_str(), native_coin_asset_id}); + if (use_assets) + req.destinations.emplace_back(tools::wallet_public::transfer_destination{50, m_accounts[BOB_ACC_IDX].get_public_address_str(), deployed_asset_id}); req.fee = TESTS_DEFAULT_FEE; req.mixin = 10; r = make_cold_signing_transaction(*alice_rpc_wo_ptr, alice_rpc, req); CHECK_AND_ASSERT_MES(r, false, "make_cold_signing_transaction failed"); - uint64_t bob_expected_balance = req.destinations.back().amount; + uint64_t bob_expected_balance = req.destinations.front().amount; // mine few blocks to unlock Alice's coins CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "unexpected pool txs count: " << c.get_pool_transactions_count()); @@ -1340,7 +1368,7 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: CHECK_AND_ASSERT_EQ(blocks_fetched, 0); - // send a cold-signed transaction + // send a cold-signed transaction: Alice -> Bob; all rest test coins (should be 50 - 1 = 49) req = tools::wallet_public::COMMAND_RPC_TRANSFER::request{}; req.destinations.emplace_back(); req.destinations.back().amount = alice_expected_balance - TESTS_DEFAULT_FEE; @@ -1370,7 +1398,7 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: CURRENCY_MINED_MONEY_UNLOCK_WINDOW, alice_expected_balance, 0, 0, 0), false, ""); - // send a cold-signed transaction + // send a cold-signed transaction: Alice -> Bob; all rest test coins (should be 7 - 1 = 6) req = tools::wallet_public::COMMAND_RPC_TRANSFER::request{}; req.destinations.emplace_back(); req.destinations.back().amount = alice_expected_balance - TESTS_DEFAULT_FEE; @@ -1398,7 +1426,11 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: // finally, check Bob's balance - CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, bob_expected_balance, true, 3 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW, bob_expected_balance, 0, 0, 0), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, bob_expected_balance, true, 4 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW, bob_expected_balance, 0, 0, 0), false, ""); + if (use_assets) + { + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", 50, 0, 50, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, ""); + } return true; } From 2f368cbf2c5f1d9fafca410e2af1375700ef9cf3 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 8 Jul 2025 02:45:52 +0300 Subject: [PATCH 29/65] fixed missing member serialization in tx_source_entry --- src/currency_core/currency_format_utils_transactions.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index 0ce53e85..6bb04b01 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -78,6 +78,7 @@ namespace currency FIELD(ms_keys_count) FIELD(separately_signed_tx_complete) FIELD(htlc_origin) + FIELD(asset_id) END_SERIALIZE() }; From c241cb3f9b6bc3eb010398323890ff915781f602 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 9 Jul 2025 14:40:24 +0300 Subject: [PATCH 30/65] wallet2: restore_key_images_in_wo_wallet() implemented --- src/crypto/crypto.h | 3 +- src/wallet/wallet2.cpp | 103 +++++++++++++++++++++++++++++++++++++++++ src/wallet/wallet2.h | 4 +- 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 160929f8..08cf26d5 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -302,10 +302,11 @@ namespace crypto { } // namespace crypto POD_MAKE_HASHABLE(crypto, public_key) +POD_MAKE_LESS_OPERATOR(crypto, public_key) POD_MAKE_COMPARABLE(crypto, secret_key) POD_MAKE_HASHABLE(crypto, key_image) POD_MAKE_COMPARABLE(crypto, signature) POD_MAKE_COMPARABLE(crypto, key_derivation) POD_MAKE_LESS_OPERATOR(crypto, hash) POD_MAKE_LESS_OPERATOR(crypto, key_image) -POP_GCC_WARNINGS \ No newline at end of file +POP_GCC_WARNINGS diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 59107e5f..99504139 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -92,6 +92,11 @@ namespace tools m_core_runtime_config = currency::get_default_core_runtime_config(); } //--------------------------------------------------------------- + wallet2::~wallet2() + { + // do nothing + } + //--------------------------------------------------------------- uint64_t wallet2::get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const wallet_public::employed_tx_entries& td) { uint64_t max_unlock_time = 0; @@ -5231,7 +5236,11 @@ bool wallet2::reset_history() std::wstring file_path = m_wallet_file; account_base acc_tmp = m_account; auto tx_keys = m_tx_keys; + auto pending_key_images = m_pending_key_images; + crypto::hash genesis_id = m_chain.get_genesis(); clear(); + m_chain.set_genesis(genesis_id); + m_pending_key_images = pending_key_images; m_tx_keys = tx_keys; m_account = acc_tmp; m_password = pass; @@ -7858,6 +7867,100 @@ bool wallet2::is_need_to_split_outputs() return !is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM); } //---------------------------------------------------------------------------------------------------- +void wallet2::restore_key_images_in_wo_wallet(const std::wstring& filename, const std::string& password) const +{ + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!m_watch_only, "restore_key_images_in_wo_wallet can only be used in non watch-only wallet"); + bool r = false; + + // load the given watch-only wallet + wallet2 wo; + wo.load(filename, password); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(wo.is_watch_only(), epee::string_encoding::wstring_to_utf8(filename) << " is not a watch-only wallet"); + if (m_account.get_keys().view_secret_key != wo.get_account().get_keys().view_secret_key || + m_account.get_public_address() != wo.get_account().get_public_address()) + { + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, epee::string_encoding::wstring_to_utf8(filename) << " has keys that differ from this wallet's keys; wrong wallet?"); + } + + // + // 1. Find missing key images and calculate them using secret spend key. Populate missing_ki_items container. + // + struct missing_ki_item + { + crypto::public_key tx_pub_key; + crypto::public_key out_pub_key; + uint64_t output_index; + uint64_t transfer_index; + crypto::key_image ki; + }; + + std::set transfer_indices_to_include; + for(auto el : wo.m_pending_key_images) + { + const crypto::key_image& ki = el.second; + auto it = wo.m_key_images.find(ki); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != wo.m_key_images.end(), "restore_key_images_in_wo_wallet: m_key_images inconsistency, ki: " << ki); + size_t transfer_index = it->second; + transfer_indices_to_include.insert(transfer_index); + WLT_LOG_L1("restore_key_images_in_wo_wallet: transfer " << transfer_index << " is in m_pending_key_images, included"); + } + + for(auto el : wo.m_transfers) + { + size_t transfer_index = el.first; + if (el.second.m_key_image == null_ki) + { + transfer_indices_to_include.insert(transfer_index); + WLT_LOG_L1("restore_key_images_in_wo_wallet: ki is null for ti " << transfer_index << ", included"); + } + } + + // now in transfer_indices_to_include we have ordered and unique list of transfer indices + std::vector missing_ki_items; + std::set pk_uniqueness_set; + for(size_t transfer_index : transfer_indices_to_include) + { + const auto& td = wo.m_transfers.at(transfer_index); + auto& item = missing_ki_items.emplace_back(); + item.output_index = td.m_internal_output_index; + crypto::public_key out_pub_key{}; + r = get_out_pub_key_from_tx_out_v(td.output(), out_pub_key); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "restore_key_images_in_wo_wallet failed for ti: " << transfer_index); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pk_uniqueness_set.insert(out_pub_key).second, "restore_key_images_in_wo_wallet: out pub key in not unique: " << out_pub_key << ", ti: " << transfer_index); + item.out_pub_key = out_pub_key; + item.transfer_index = transfer_index; + item.tx_pub_key = get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx); + WLT_LOG_L0("restore_key_images_in_wo_wallet: including: " << item.out_pub_key << ", " << transfer_index); + + // calculate key image + keypair ephemeral{}; + generate_key_image_helper(m_account.get_keys(), item.tx_pub_key, item.output_index, ephemeral, item.ki); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ephemeral.pub == item.out_pub_key, "restore_key_images_in_wo_wallet: out pub key missmatch, ti: " << transfer_index); + }; + + // + // 2. Actually restore key images in the 'wo' object. + // + r = wo.m_pending_key_images_file_container.clear(); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "restore_key_images_in_wo_wallet: pending ki container clearing failed"); + wo.m_pending_key_images.clear(); + + for(size_t i = 0; i < missing_ki_items.size(); ++i) + { + const auto& item = missing_ki_items[i]; + auto& td = wo.m_transfers[item.transfer_index]; // item.transfer_index validity was checked above + + td.m_key_image = item.ki; // TODO: it's unclear whether we need to update m_transfers[].m_key_image since later I decided to clear history to trigger resync later. Probably, no. -- sowle + r = wo.m_pending_key_images.insert(std::make_pair(item.out_pub_key, item.ki)).second; + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "restore_key_images_in_wo_wallet: insert failed, out_pub_key: " << item.out_pub_key << ", i: " << i); + wo.m_pending_key_images_file_container.push_back(out_key_to_ki{item.out_pub_key, item.ki}); + LOG_PRINT_L0("restore_key_images_in_wo_wallet: added #" << i << " ti: " << item.transfer_index << ", pk: " << item.out_pub_key << ", ki: " << item.ki); + } + + wo.reset_history(); + wo.store(); +} +//---------------------------------------------------------------------------------------------------- void wallet2::prepare_tx_destinations(const assets_selection_context& needed_money_map, detail::split_strategy_id_t destination_split_strategy_id, const tx_dust_policy& dust_policy, diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 4d3fa218..c0b08519 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -262,7 +262,7 @@ namespace tools wallet2(const wallet2&) = delete; public: wallet2(); - virtual ~wallet2() {} + virtual ~wallet2(); static std::string transfer_flags_to_str(uint32_t flags); @@ -617,6 +617,8 @@ namespace tools void submit_transfer_files(const std::string& signed_tx_file, currency::transaction& tx); void submit_externally_signed_asset_tx(const currency::finalized_tx& ft, const crypto::generic_schnorr_sig_s& gss_sig, bool unlock_transfers_on_fail, currency::transaction& result_tx, bool& transfers_unlocked); void submit_externally_signed_asset_tx(const currency::finalized_tx& ft, const crypto::eth_signature& eth_sig, bool unlock_transfers_on_fail, currency::transaction& result_tx, bool& transfers_unlocked); + + void restore_key_images_in_wo_wallet(const std::wstring& filename, const std::string& password) const; void 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); From 5ac8b2081671c3de6b99b594937f4ee2754e3280 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 9 Jul 2025 14:41:22 +0300 Subject: [PATCH 31/65] coretests: wallet_rpc_cold_signing test improved to cover key image recovery in a watch-only wallet using a full keys wallet --- tests/core_tests/wallet_rpc_tests.cpp | 63 +++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index b6ebd12a..e8787411 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -1304,7 +1304,6 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); // Alice: prepare watch-only wallet - account_base alice_acc_wo = m_accounts[ALICE_ACC_IDX]; alice_acc_wo.make_account_watch_only(); std::shared_ptr alice_wlt_wo = init_playtime_test_wallet(events, c, alice_acc_wo); @@ -1422,15 +1421,73 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: // check Alice's balance CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("after sending the second cold-signed tx:", "Alice", alice_wlt_wo, alice_expected_balance, true, CURRENCY_MINED_MONEY_UNLOCK_WINDOW, alice_expected_balance, 0, 0, 0), false, ""); + if (use_assets) + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo.get(), "Alice", 0, 0, 0, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, ""); // finally, check Bob's balance CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, bob_expected_balance, true, 4 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW, bob_expected_balance, 0, 0, 0), false, ""); if (use_assets) - { CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", 50, 0, 50, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, ""); - } + + + // Alice watch-only: reload the wallet, make sure the balance is still okay (zero) + alice_rpc_wo_ptr.reset(); + alice_wlt_wo->reset_password(m_wallet_password); + alice_wlt_wo->store(m_wallet_filename); + CHECK_AND_ASSERT_EQ(alice_wlt_wo.unique(), true); + alice_wlt_wo.reset(new tools::wallet2); + alice_wlt_wo->load(m_wallet_filename, m_wallet_password); + alice_wlt_wo->set_core_proxy(m_core_proxy); + alice_wlt_wo->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config()); + set_wallet_options(alice_wlt_wo); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("after re-loading with zero balance:", "Alice", alice_wlt_wo, 0, true, 0, 0, 0, 0, 0), false, ""); + if (use_assets) + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo.get(), "Alice", 0, 0, 0, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, ""); + + + // Alice: remove outkey2ki file with key images copies and restore the wallet from watch-only account + std::string alice_seed_phrase = m_accounts[ALICE_ACC_IDX].get_seed_phrase(""); + CHECK_AND_ASSERT_EQ(alice_wlt_wo.unique(), true); + alice_wlt_wo.reset(); + CHECK_AND_ASSERT_MES(boost::filesystem::remove(epee::string_tools::cut_off_extension(m_wallet_filename) + L".outkey2ki"), false, "boost::filesystem::remove failed"); + CHECK_AND_ASSERT_MES(boost::filesystem::remove(m_wallet_filename), false, "boost::filesystem::remove failed"); + + alice_wlt_wo = init_playtime_test_wallet(events, c, alice_acc_wo); + alice_wlt_wo->set_core_proxy(m_core_proxy); + alice_wlt_wo->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config()); + set_wallet_options(alice_wlt_wo); + + // without key images Alice watch-only wallet is only able to detect incoming transfers and thus calculate incorrect balance + alice_expected_balance = MK_TEST_COINS(100 + 49 + 7); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("after sending the second cold-signed tx:", "Alice", alice_wlt_wo, alice_expected_balance, true, + 5 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1, alice_expected_balance, 0, 0, 0), false, ""); + if (use_assets) + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo.get(), "Alice", 50, 0, 50, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, ""); + + // store this broken watch-only wallet into a file ... + alice_wlt_wo->reset_password(m_wallet_password); + alice_wlt_wo->store(m_wallet_filename); + CHECK_AND_ASSERT_EQ(alice_wlt_wo.unique(), true); + alice_wlt_wo.reset(); + + // ... and repair it using full key wallet + alice_wlt->restore_key_images_in_wo_wallet(m_wallet_filename, m_wallet_password); + + alice_wlt_wo.reset(new tools::wallet2); + alice_wlt_wo->load(m_wallet_filename, m_wallet_password); + alice_wlt_wo->set_core_proxy(m_core_proxy); + alice_wlt_wo->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config()); + set_wallet_options(alice_wlt_wo); + + // re-check the balance, it should be zero now + alice_expected_balance = 0; + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("after sending the second cold-signed tx:", "Alice", alice_wlt_wo, alice_expected_balance, true, + 5 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1, alice_expected_balance, 0, 0, 0), false, ""); + if (use_assets) + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo.get(), "Alice", 0, 0, 0, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, ""); return true; } From db86b3fa15e9966599305e526f931eeeb57673bb Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 9 Jul 2025 14:42:18 +0300 Subject: [PATCH 32/65] simplewallet: --restore-ki-in-wo-wallet command-line option implemented --- src/simplewallet/simplewallet.cpp | 30 +++++++++++++++++++++++++++++- src/simplewallet/simplewallet.h | 2 ++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 4178ddee..ddb34a81 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -142,6 +142,7 @@ namespace const command_line::arg_descriptor arg_no_password_confirmations("no-password-confirmation", "Enable/Disable password confirmation for transactions", false); const command_line::arg_descriptor arg_seed_doctor("seed-doctor", "Experimental: if your seed is not working for recovery this is likely because you've made a mistake whene you were doing back up(typo, wrong words order, missing word). This experimental code will attempt to recover seed phrase from with few approaches."); const command_line::arg_descriptor arg_no_whitelist("no-white-list", "Do not load white list from interned."); + const command_line::arg_descriptor arg_restore_ki_in_wo_wallet("restore-ki-in-wo-wallet", "Watch-only missing key images restoration. Please, DON'T use it unless you 100% sure of what are you doing.", ""); const command_line::arg_descriptor< std::vector > arg_command ("command", ""); @@ -519,6 +520,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) bool r = open_wallet(m_wallet_file, pwd_container.password()); CHECK_AND_ASSERT_MES(r, false, "wallet could not be opened"); was_open = true; + if (!process_ki_restoration()) + return false; } process_wallet_command_line_params(vm, *m_wallet, false); @@ -559,6 +562,7 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_ m_voting_config_file = command_line::get_arg(vm, arg_voting_config_file); m_no_password_confirmations = command_line::get_arg(vm, arg_no_password_confirmations); m_no_whitelist = command_line::get_arg(vm, arg_no_whitelist); + m_restore_ki_in_wo_wallet = command_line::get_arg(vm, arg_restore_ki_in_wo_wallet); } //---------------------------------------------------------------------------------------------------- @@ -720,7 +724,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa try { m_wallet->load(epee::string_encoding::utf8_to_wstring(m_wallet_file), password); - message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str(); + print_wallet_opened_msg(); preconfig_wallet_obj(); display_vote_info(*m_wallet); @@ -783,6 +787,28 @@ bool simple_wallet::save(const std::vector &args) return true; } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::process_ki_restoration() +{ + bool r = false; + if (!m_restore_ki_in_wo_wallet.empty()) + { + std::wstring wo_filename = epee::string_encoding::utf8_to_wstring(m_restore_ki_in_wo_wallet); + CHECK_AND_ASSERT_THROW_MES(std::filesystem::exists(wo_filename), "cannot open " << m_restore_ki_in_wo_wallet); + + tools::password_container wo_password; + if (!wo_password.read_password("Enter password for wallet " + m_restore_ki_in_wo_wallet + " :")) + return false; + + m_wallet->restore_key_images_in_wo_wallet(wo_filename, wo_password.password()); + + success_msg_writer() << "Missing key images have been successfully repared in " << m_restore_ki_in_wo_wallet << ENDL; + + return false; // means the wallet processing should stop now + } + + return true; // means the wallet can load and work further normally +} +//---------------------------------------------------------------------------------------------------- #ifdef CPU_MINING_ENABLED bool simple_wallet::start_mining(const std::vector& args) { @@ -3245,6 +3271,8 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_seed_doctor); command_line::add_arg(desc_params, arg_derive_custom_seed); command_line::add_arg(desc_params, arg_no_whitelist); + command_line::add_arg(desc_params, arg_restore_ki_in_wo_wallet); + tools::wallet_rpc_server::init_options(desc_params); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 6577b6a7..789ada28 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -181,6 +181,7 @@ namespace currency private: void preconfig_wallet_obj(); + bool process_ki_restoration(); std::string m_wallet_file; std::string m_generate_new; @@ -199,6 +200,7 @@ namespace currency std::string m_voting_config_file; bool m_no_password_confirmations = false; bool m_no_whitelist = false; + std::string m_restore_ki_in_wo_wallet; crypto::hash m_password_hash; uint64_t m_password_salt; From 0554d7b8c4e7a8ba953a3413af36e6208ea39444 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 9 Jul 2025 17:16:01 +0300 Subject: [PATCH 33/65] wallet: clear_utxo_cold_sig_reservation() implemented + RPC clear_utxo_cold_sig_reservation added + coretest wallet_rpc_cold_signing improved to test this new RPC --- src/wallet/wallet2.cpp | 21 +++++++++++++++++ src/wallet/wallet2.h | 1 + src/wallet/wallet_public_structs_defs.h | 30 +++++++++++++++++++++++++ src/wallet/wallet_rpc_server.cpp | 25 +++++++++++++++++++++ src/wallet/wallet_rpc_server.h | 2 ++ tests/core_tests/wallet_rpc_tests.cpp | 10 +++++++++ 6 files changed, 89 insertions(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 99504139..50f96fdc 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -7961,6 +7961,27 @@ void wallet2::restore_key_images_in_wo_wallet(const std::wstring& filename, cons wo.store(); } //---------------------------------------------------------------------------------------------------- +void wallet2::clear_utxo_cold_sig_reservation(std::vector& affected_transfer_ids) +{ + affected_transfer_ids.clear(); + + for(auto& [tid, td] : m_transfers) + { + if (!td.is_spent() && (td.m_flags & WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION) != 0) + { + affected_transfer_ids.push_back(tid); + crypto::public_key pk{}; + get_out_pub_key_from_tx_out_v(td.output(), pk); + WLT_LOG_L0("clear_utxo_cold_sig_reservation: tid: " << tid << ", pk: " << pk << ", amount: " << td.amount() << + (!td.is_native_coin() ? std::string(", aid: ") + crypto::pod_to_hex(td.get_asset_id()) : std::string()) << + (td.m_key_image != null_ki ? std::string(", ki: ") + crypto::pod_to_hex(td.m_key_image) : std::string())); + } + } + + clear_transfers_from_flag(affected_transfer_ids, WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION, "clear_utxo_cold_sig_reservation"); + m_found_free_amounts.clear(); +} +//---------------------------------------------------------------------------------------------------- void wallet2::prepare_tx_destinations(const assets_selection_context& needed_money_map, detail::split_strategy_id_t destination_split_strategy_id, const tx_dust_policy& dust_policy, diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index c0b08519..8e20d0c0 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -619,6 +619,7 @@ namespace tools void submit_externally_signed_asset_tx(const currency::finalized_tx& ft, const crypto::eth_signature& eth_sig, bool unlock_transfers_on_fail, currency::transaction& result_tx, bool& transfers_unlocked); void restore_key_images_in_wo_wallet(const std::wstring& filename, const std::string& password) const; + void clear_utxo_cold_sig_reservation(std::vector& affected_transfer_ids); void 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); diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 3ac0f839..f3908c24 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -2159,5 +2159,35 @@ namespace wallet_public }; }; + struct COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION + { + DOC_COMMAND("Clears cold sig reservation flag for all unspent transaction outputs, that have one. Please, use with CAUTION!"); + + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response_item + { + crypto::public_key pk; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(pk) DOC_DSCR("Output's one-time public key") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::vector affected_outputs; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) DOC_DSCR("Status of the call") DOC_EXMP("OK") DOC_END + KV_SERIALIZE(affected_outputs) DOC_DSCR("List of affected outputs (for reference).") DOC_EXMP_AUTO(1) DOC_END + END_KV_SERIALIZE_MAP() + }; + }; + } // namespace wallet_rpc } // namespace tools diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 15a4d276..13922a20 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -1620,6 +1620,31 @@ namespace tools WALLET_RPC_CATCH_TRY_ENTRY(); } //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_clear_utxo_cold_sig_reservation(const wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::request& req, wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::response& res, epee::json_rpc::error& er, connection_context& cntx) + { + WALLET_RPC_BEGIN_TRY_ENTRY(); + + std::vector affected_transfer_ids; + w.get_wallet()->clear_utxo_cold_sig_reservation(affected_transfer_ids); + + for (auto tid : affected_transfer_ids) + { + transfer_details td{}; + if (!w.get_wallet()->get_transfer_info_by_index(tid, td)) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "internal error: get_transfer_info_by_index failed for tid " + epee::string_tools::num_to_string_fast(tid); + return false; + } + + res.affected_outputs.emplace_back(); + currency::get_out_pub_key_from_tx_out_v(td.output(), res.affected_outputs.back().pk); + } + + return true; + WALLET_RPC_CATCH_TRY_ENTRY(); + } + //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_decrypt_data(const wallet_public::COMMAND_DECRYPT_DATA::request& req, wallet_public::COMMAND_DECRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx) { WALLET_RPC_BEGIN_TRY_ENTRY(); diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 6962ed83..276b4f95 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -179,6 +179,7 @@ namespace tools //utility call MAP_JON_RPC_WE("proxy_to_daemon", on_proxy_to_daemon, wallet_public::COMMAND_PROXY_TO_DAEMON) + MAP_JON_RPC_WE("clear_utxo_cold_sig_reservation", on_clear_utxo_cold_sig_reservation, wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION) END_JSON_RPC_MAP() END_URI_MAP2() @@ -252,6 +253,7 @@ namespace tools bool on_decrypt_data(const wallet_public::COMMAND_DECRYPT_DATA::request& req, wallet_public::COMMAND_DECRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_proxy_to_daemon(const wallet_public::COMMAND_PROXY_TO_DAEMON::request& req, wallet_public::COMMAND_PROXY_TO_DAEMON::response& res, epee::json_rpc::error& er, connection_context& cntx); + bool on_clear_utxo_cold_sig_reservation(const wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::request& req, wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::response& res, epee::json_rpc::error& er, connection_context& cntx); //std::shared_ptr get_wallet(); diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index e8787411..004c1bf6 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -1234,6 +1234,16 @@ bool make_cold_signing_transaction(tools::wallet_rpc_server& rpc_wo, tools::wall r = invoke_text_json_for_rpc(rpc_wo, "transfer", req_transfer, res_transfer); CHECK_AND_ASSERT_MES(r, false, "RPC 'transfer' failed"); + // skip this reservation just for fun + tools::wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::request req_clear_csr{}; + tools::wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::response res_clear_csr{}; + invoke_text_json_for_rpc(rpc_wo, "clear_utxo_cold_sig_reservation", req_clear_csr, res_clear_csr); + CHECK_AND_ASSERT_MES(res_clear_csr.affected_outputs.size() > 0, false, "no outputs were affected after clear_utxo_cold_sig_reservation"); + + // watch only creates a transaction once again + res_transfer = tools::wallet_public::COMMAND_RPC_TRANSFER::response{}; + r = invoke_text_json_for_rpc(rpc_wo, "transfer", req_transfer, res_transfer); + CHECK_AND_ASSERT_MES(r, false, "RPC 'transfer' failed"); // secure wallet with full keys set signs the transaction tools::wallet_public::COMMAND_SIGN_TRANSFER::request req_sign{}; From 9589c952f827a3128bfc7d50649bce7337869627 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 9 Jul 2025 17:32:49 +0300 Subject: [PATCH 34/65] ui updated (PR 152) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 317979cd..1b080e0b 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 317979cdf88fc2ca785a3f1a0e0578b7a0f42ff5 +Subproject commit 1b080e0be4cdace91a0ba7c171e6ed349cf1aa25 From 28606d07efe8c7c169dda501cada8319dc96bc47 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 9 Jul 2025 17:33:17 +0300 Subject: [PATCH 35/65] === build number: 413 -> 414 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index 51f7e11f..d1735074 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 413 +#define PROJECT_VERSION_BUILD_NO 414 #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 "]" From 87cd247eb51cf40eda47ad1301df89a437350eb1 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 9 Jul 2025 19:10:33 +0300 Subject: [PATCH 36/65] wallet: clear_utxo_cold_sig_reservation() made available only for watch-only wallets --- src/wallet/wallet2.cpp | 1 + tests/core_tests/wallet_rpc_tests.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 50f96fdc..59d24d61 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -7963,6 +7963,7 @@ void wallet2::restore_key_images_in_wo_wallet(const std::wstring& filename, cons //---------------------------------------------------------------------------------------------------- void wallet2::clear_utxo_cold_sig_reservation(std::vector& affected_transfer_ids) { + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(m_watch_only, "clear_utxo_cold_sig_reservation can only be used in watch-only wallet"); affected_transfer_ids.clear(); for(auto& [tid, td] : m_transfers) diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index 004c1bf6..7d3739e4 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -1234,13 +1234,11 @@ bool make_cold_signing_transaction(tools::wallet_rpc_server& rpc_wo, tools::wall r = invoke_text_json_for_rpc(rpc_wo, "transfer", req_transfer, res_transfer); CHECK_AND_ASSERT_MES(r, false, "RPC 'transfer' failed"); - // skip this reservation just for fun + // (optional step) skip this reservation just for fun and then create a transaction once again tools::wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::request req_clear_csr{}; tools::wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::response res_clear_csr{}; invoke_text_json_for_rpc(rpc_wo, "clear_utxo_cold_sig_reservation", req_clear_csr, res_clear_csr); CHECK_AND_ASSERT_MES(res_clear_csr.affected_outputs.size() > 0, false, "no outputs were affected after clear_utxo_cold_sig_reservation"); - - // watch only creates a transaction once again res_transfer = tools::wallet_public::COMMAND_RPC_TRANSFER::response{}; r = invoke_text_json_for_rpc(rpc_wo, "transfer", req_transfer, res_transfer); CHECK_AND_ASSERT_MES(r, false, "RPC 'transfer' failed"); @@ -1252,8 +1250,11 @@ bool make_cold_signing_transaction(tools::wallet_rpc_server& rpc_wo, tools::wall r = invoke_text_json_for_rpc(rpc, "sign_transfer", req_sign, res_sign); CHECK_AND_ASSERT_MES(r, false, "RPC 'sign_transfer' failed"); + // (optional step) make sure clear_utxo_cold_sig_reservation cannot be called in a full keys wallet + r = !invoke_text_json_for_rpc(rpc, "clear_utxo_cold_sig_reservation", req_clear_csr, res_clear_csr); + CHECK_AND_ASSERT_MES(r, false, "clear_utxo_cold_sig_reservation called in full key wallet"); - // watch only wallet submits it + // watch only wallet submits signed transaction tools::wallet_public::COMMAND_SUBMIT_TRANSFER::request req_submit{}; req_submit.tx_signed_hex = res_sign.tx_signed_hex; tools::wallet_public::COMMAND_SUBMIT_TRANSFER::response res_submit{}; From 94b9741976909b2c89cf84887bc5a5e7867b448d Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 10 Jul 2025 04:00:56 +0300 Subject: [PATCH 37/65] an attempt to fil gcc linking (prior to gcc 9, the std::filesystem library required explicit linking) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5897025d..5cb293d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,7 @@ else() if (CLANG) set(LLVM_USE_LINKER "gold") else() - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -lstdc++fs") endif() endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)) From d56bf75bde405d4cb9ed4ade01a8839b7da1e81f Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 10 Jul 2025 04:32:36 +0300 Subject: [PATCH 38/65] an attempt 2 to fil gcc linking (prior to gcc 9, the std::filesystem library required explicit linking) --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cb293d8..5897025d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,7 @@ else() if (CLANG) set(LLVM_USE_LINKER "gold") else() - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -lstdc++fs") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") endif() endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27739818..2d715644 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -184,7 +184,7 @@ ENABLE_SHARED_PCH_EXECUTABLE(connectivity_tool) add_executable(simplewallet ${SIMPLEWALLET}) add_dependencies(simplewallet version) -target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) +target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto stdc++fs) ENABLE_SHARED_PCH(simplewallet SIMPLEWALLET) ENABLE_SHARED_PCH_EXECUTABLE(simplewallet) From 51990c9d2dbdfb3a51d91c7481e7937458c38626 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 11 Jul 2025 21:25:48 +0300 Subject: [PATCH 39/65] an attempt 3 to fix gcc linking (prior to gcc 9, the std::filesystem library required explicit linking) --- CMakeLists.txt | 1 + src/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5897025d..2010836c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,7 @@ else() set(LLVM_USE_LINKER "gold") else() set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") + link_libraries("$<$,$,9.0>>:-lstdc++fs>") # GCC < 9 requires additional linking for std::filesystem. Remove after stop supporting GCC 8.x -- sowle endif() endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2d715644..27739818 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -184,7 +184,7 @@ ENABLE_SHARED_PCH_EXECUTABLE(connectivity_tool) add_executable(simplewallet ${SIMPLEWALLET}) add_dependencies(simplewallet version) -target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto stdc++fs) +target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) ENABLE_SHARED_PCH(simplewallet SIMPLEWALLET) ENABLE_SHARED_PCH_EXECUTABLE(simplewallet) From 6ad7dad01d1f1aea737906fec4d4f546884d573f Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 11 Jul 2025 21:26:07 +0300 Subject: [PATCH 40/65] gcc warning fixed --- src/currency_core/block_chain_shortener.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/currency_core/block_chain_shortener.cpp b/src/currency_core/block_chain_shortener.cpp index 9cb53295..986658a1 100644 --- a/src/currency_core/block_chain_shortener.cpp +++ b/src/currency_core/block_chain_shortener.cpp @@ -13,7 +13,7 @@ #define SHORTENER_EVERY_100_BLOCKS_SIZE 144 #define SHORTENER_EVERY_1000_BLOCKS_SIZE 144 -static void exception_handler(){} +//static void exception_handler(){} From 65241adc1ca1690ac3e5d45cd7ab5025571394fc Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 11 Jul 2025 21:26:52 +0300 Subject: [PATCH 41/65] ui update (PR 153) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 1b080e0b..f2f81791 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 1b080e0be4cdace91a0ba7c171e6ed349cf1aa25 +Subproject commit f2f81791757d791f2a478d1e486af90b8f82a7a1 From 0cd2ef8ccb7341289fa6dc2e60b12b373db11a78 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 11 Jul 2025 21:45:24 +0300 Subject: [PATCH 42/65] wallet: various minor improvements (balance, balance raw, unknown asset) --- src/simplewallet/simplewallet.cpp | 8 +++--- src/wallet/wallet2.cpp | 48 ++++++++++++++++++++----------- src/wallet/wallet2.h | 6 ++-- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index ddb34a81..63a11799 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -291,7 +291,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, ph::_1), "Stop mining in daemon"); #endif // #ifdef CPU_MINING_ENABLED 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), "[raw] Show current wallet balance, with 'raw' param it displays all assets without filtering against whitelists"); + m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "[r,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"); @@ -932,7 +932,7 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf message_writer(color, false) << "height " << wti.height << ", tx " << wti.tx_hash << - " " << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(wti.subtransfers[0].amount, decimal_points) << (wti.subtransfers[0].is_income ? " received," : " spent") << " " << token_info; + " " << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(wti.subtransfers[0].amount, decimal_points) << (wti.subtransfers[0].is_income ? " received" : " spent") << " " << token_info; } else { @@ -946,7 +946,7 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf 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(24) << print_money_trailing_zeros_replaced_with_spaces(st.amount, decimal_points) << std::left << (st.is_income ? " received," : " spent") << " " << token_info; + << 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; } } @@ -1071,7 +1071,7 @@ bool simple_wallet::refresh(const std::vector& args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::show_balance(const std::vector& args /* = std::vector()*/) { - if (args.size() == 1 && args[0] == "raw") + if (args.size() == 1 && (args[0] == "raw" || args[0] == "r")) { success_msg_writer() << m_wallet->get_balance_str_raw(); } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 59d24d61..bd59f381 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3945,13 +3945,13 @@ bool wallet2::balance(std::list& balances, u return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags) const +bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags, bool ask_daemon_for_unknown /* = false */) const { asset_flags = aif_none; if (asset_id == currency::native_coin_asset_id) { asset_info = currency::get_native_coin_asset_descriptor(); - asset_flags |= aif_whitelisted; + asset_flags |= (aif_native_coin | aif_whitelisted); return true; } @@ -3978,9 +3978,19 @@ bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset if (it_cust != m_custom_assets.end()) { asset_info = it_cust->second; + asset_flags |= aif_custom; return true; } + if (ask_daemon_for_unknown) + { + if (daemon_get_asset_info(asset_id, asset_info)) + { + asset_flags |= aif_unknown; + return true; + } + } + return false; } //---------------------------------------------------------------------------------------------------- @@ -4137,7 +4147,8 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu bool native_coin = td.is_native_coin(); asset_descriptor_base adb{}; uint32_t asset_info_flags{}; - if (get_asset_info(td.get_asset_id(), adb, asset_info_flags) == show_only_unknown) + bool unknown_asset = !get_asset_info(td.get_asset_id(), adb, asset_info_flags, show_only_unknown) || (asset_info_flags & aif_unknown); + if (unknown_asset != show_only_unknown) { if (!show_only_unknown) ++unknown_assets_outs_count; @@ -4177,11 +4188,11 @@ 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 - // 0.21 / 98.51 DP2 a6974d5874e97e5f4ed5ad0a62f0975edbccb1bb55502fc75c7fe808f12f44d3 - // 190.123456789012 / 199.123456789012 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a - // 98.0 BGTVUW af2b12f3033337f9aea1845a6bc3fc966ed4d13227a3ace7706fca7dbcdaa7e2 - // 1000.034 DP3 d4aba1020f26927571771e04b585b4ffb211f52708d5e4c465bbdfa4a12e6271 + // balance unlocked / [balance total] ticker asset id + // 0.21 / 98.51 DP2 a6974d5874e97e5f4ed5ad0a62f0975edbccb1bb55502fc75c7fe808f12f44d3 + // 190.123456789012 / 199.123456789012 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a NATIVE + // 98.0 BGTVUW af2b12f3033337f9aea1845a6bc3fc966ed4d13227a3ace7706fca7dbcdaa7e2 + // 1000.034 DP3 d4aba1020f26927571771e04b585b4ffb211f52708d5e4c465bbdfa4a12e6271 static const char* header = " balance unlocked / [balance total] ticker asset id"; std::stringstream ss; @@ -4216,13 +4227,12 @@ std::string wallet2::get_balance_str() const //---------------------------------------------------------------------------------------------------- std::string wallet2::get_balance_str_raw() const { - // 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 + // balance unlocked / [balance total] ticker asset id DP flags + // 0.21 / 98.51 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a 12 NATIVE + // 2.0 MYFB 13615ffdfbdc09275a1dfc0fbdaf6a9b07849b835ffdfed0b9e1478ea8924774 1 custom + // 1000.0 BurnCT 14608811180d4bbad96a6b91405e329e4f2a10519e6dcea644f83b9f8ccb5863 12 unknown asset //WHITELIST: - // 7d3f348fbebfffc4e61a3686189cf870ea393e1c88b8f636acbfdacf9e4b2db2 CT + // a7e8e5b31c24f2d6a07e141701237b136d704c9a89f9a5d1ca4a8290df0b9edc WETH // ... static const char* header = " balance unlocked / [balance total] ticker asset id DP flags"; @@ -4239,7 +4249,7 @@ std::string wallet2::get_balance_str_raw() const { uint32_t asset_flags = 0; asset_descriptor_base asset_info{}; - bool has_info = get_asset_info(entry.first, asset_info, asset_flags); + bool has_info = get_asset_info(entry.first, asset_info, asset_flags, true); ss << " " << std::left << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(entry.second.unlocked, asset_info.decimal_point); if (entry.second.total == entry.second.unlocked) ss << std::string(21 + 3, ' '); @@ -4256,7 +4266,7 @@ std::string wallet2::get_balance_str_raw() const ss << " "; - if (entry.first == native_coin_asset_id) + if (asset_flags & aif_native_coin) { ss << "NATIVE"; } @@ -4266,6 +4276,10 @@ std::string wallet2::get_balance_str_raw() const ss << "own,"; if (asset_flags & aif_whitelisted) ss << "whitelisted,"; + if (asset_flags & aif_custom) + ss << "custom,"; + if (asset_flags & aif_unknown) + ss << "unknown asset,"; ss.seekp(-1, ss.cur); // trim comma } ss << ENDL; @@ -5827,7 +5841,7 @@ void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_ result_tx = ft.tx; } //---------------------------------------------------------------------------------------------------- -bool wallet2::daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb) +bool wallet2::daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb) const { COMMAND_RPC_GET_ASSET_INFO::request req; req.asset_id = asset_id; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 8e20d0c0..3c203644 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -449,7 +449,7 @@ namespace tools void burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::finalized_tx& ft, const std::vector& service_entries = std::vector(), const std::string& address_to_point = std::string(), uint64_t native_amount_to_point = 0); void transfer_asset_ownership(const crypto::public_key& asset_id, const currency::asset_owner_pub_key_v& new_owner_v, currency::finalized_tx& ft); - bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb); + bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb) const; bool set_core_proxy(const std::shared_ptr& proxy); void set_defragmentation_tx_settings(bool enabled, uint64_t min_outs, uint64_t max_outs, uint64_t max_allowed_amount = CURRENCY_BLOCK_REWARD, size_t decoys_count = SIZE_MAX); void set_pos_required_decoys_count(size_t v) { m_required_decoys_count = v; } @@ -466,8 +466,8 @@ namespace tools uint64_t unlocked_balance() 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; + enum asset_info_flags_t : uint32_t { aif_none = 0, aif_native_coin = 1 << 0, aif_whitelisted = 1 << 1, aif_own = 1 << 2, aif_custom = 1 << 3, aif_unknown = 1 << 4 }; + bool get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags, bool ask_daemon_for_unknown = false) 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; From 5e0c84e735606ff81584d43afe487fbd39a50724 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 11 Jul 2025 21:46:03 +0300 Subject: [PATCH 43/65] wallet: keep custom added assets while resetting history --- src/wallet/wallet2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index bd59f381..13989d91 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5252,7 +5252,9 @@ bool wallet2::reset_history() auto tx_keys = m_tx_keys; auto pending_key_images = m_pending_key_images; crypto::hash genesis_id = m_chain.get_genesis(); + auto custom_assets = m_custom_assets; clear(); + m_custom_assets = custom_assets; m_chain.set_genesis(genesis_id); m_pending_key_images = pending_key_images; m_tx_keys = tx_keys; From f28791637228ff9c03f73e7450c6a8d66f06f611 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 11 Jul 2025 21:46:56 +0300 Subject: [PATCH 44/65] === build number: 414 -> 415 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index d1735074..d557192b 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 414 +#define PROJECT_VERSION_BUILD_NO 415 #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 "]" From 6f8d727332bf02fd26b54838a4b0962373eaf0f3 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 14 Jul 2025 20:30:12 +0300 Subject: [PATCH 45/65] Revert "wallet: keep custom added assets while resetting history" This reverts commit 5e0c84e735606ff81584d43afe487fbd39a50724. --- src/wallet/wallet2.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 13989d91..bd59f381 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5252,9 +5252,7 @@ bool wallet2::reset_history() auto tx_keys = m_tx_keys; auto pending_key_images = m_pending_key_images; crypto::hash genesis_id = m_chain.get_genesis(); - auto custom_assets = m_custom_assets; clear(); - m_custom_assets = custom_assets; m_chain.set_genesis(genesis_id); m_pending_key_images = pending_key_images; m_tx_keys = tx_keys; From 75ad8c7a6932e021f8e6947314daa798f0172dbc Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 15 Jul 2025 14:30:55 +0400 Subject: [PATCH 46/65] made some of the api optional --- .../include/net/http_server_handlers_map2.h | 20 +++++++++++++++++++ src/rpc/core_rpc_server.cpp | 8 ++++++++ src/rpc/core_rpc_server.h | 8 +++++--- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index 05e0b691..5e73df90 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -507,6 +507,26 @@ namespace epee { return true;\ } +#define MAP_JON_RPC_CONDITIONAL(method_name, callback_f, command_type, predicate) \ + else if(predicate && auto_doc(current_zone_json_uri, method_name, true, docs) && callback_name == method_name) \ +{ \ + call_found = true; \ + PREPARE_OBJECTS_FROM_JSON(command_type) \ + if(!callback_f(req.params, resp.result, m_conn_context)) \ + { \ + epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ + fail_resp.jsonrpc = "2.0"; \ + fail_resp.method = req.method; \ + fail_resp.id = req.id; \ + fail_resp.error.code = -32603; \ + fail_resp.error.message = "Internal error"; \ + epee::serialization::store_t_to_json(static_cast(fail_resp), response_info.m_body); \ + return true; \ + } \ + FINALIZE_OBJECTS_TO_JSON(method_name) \ + return true;\ +} + #define MAP_JON_RPC_N(callback_f, command_type) MAP_JON_RPC(command_type::methodname(), callback_f, command_type) #define END_JSON_RPC_MAP() \ diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index a1d1d7cd..4793fe49 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -25,6 +25,7 @@ namespace currency const command_line::arg_descriptor arg_rpc_bind_ip ("rpc-bind-ip", "", "127.0.0.1"); const command_line::arg_descriptor arg_rpc_bind_port ("rpc-bind-port", "", std::to_string(RPC_DEFAULT_PORT)); const command_line::arg_descriptor arg_rpc_ignore_offline_status ("rpc-ignore-offline", "Let rpc calls despite online/offline status"); + const command_line::arg_descriptor arg_rpc_enable_rpc_api ("rpc-enable-admin-api", "Enable API commands that can alter state of pool or daemon(reset pool, remove txs etc)"); } //----------------------------------------------------------------------------------- void core_rpc_server::init_options(boost::program_options::options_description& desc) @@ -32,6 +33,8 @@ namespace currency command_line::add_arg(desc, arg_rpc_bind_ip); command_line::add_arg(desc, arg_rpc_bind_port); command_line::add_arg(desc, arg_rpc_ignore_offline_status); + command_line::add_arg(desc, arg_rpc_enable_rpc_api); + } //------------------------------------------------------------------------------------------------------------------------------ core_rpc_server::core_rpc_server(core& cr, nodetool::node_server >& p2p, @@ -50,6 +53,11 @@ namespace currency { m_ignore_offline_status = command_line::get_arg(vm, arg_rpc_ignore_offline_status); } + if (command_line::has_arg(vm, arg_rpc_enable_rpc_api)) + { + m_enabled_admin_api = command_line::get_arg(vm, arg_rpc_enable_rpc_api); + } + return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index fa5313e3..3dc4049d 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -171,9 +171,10 @@ namespace currency MAP_JON_RPC_WE("get_alt_block_details", on_get_alt_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) MAP_JON_RPC ("get_alt_blocks_details", on_get_alt_blocks_details, COMMAND_RPC_GET_ALT_BLOCKS_DETAILS) // - MAP_JON_RPC ("reset_transaction_pool", on_reset_transaction_pool, COMMAND_RPC_RESET_TX_POOL) - MAP_JON_RPC ("remove_tx_from_pool", on_remove_tx_from_pool, COMMAND_RPC_REMOVE_TX_FROM_POOL) - MAP_JON_RPC ("get_current_core_tx_expiration_median", on_get_current_core_tx_expiration_median, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN) + MAP_JON_RPC_CONDITIONAL("reset_transaction_pool", on_reset_transaction_pool, COMMAND_RPC_RESET_TX_POOL, m_enabled_admin_api) + MAP_JON_RPC_CONDITIONAL("remove_tx_from_pool", on_remove_tx_from_pool, COMMAND_RPC_REMOVE_TX_FROM_POOL, m_enabled_admin_api) + + MAP_JON_RPC("get_current_core_tx_expiration_median", on_get_current_core_tx_expiration_median, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN) // MAP_JON_RPC_WE("marketplace_global_get_offers_ex", on_get_offers_ex, COMMAND_RPC_GET_OFFERS_EX) MAP_JON_RPC_WE("validate_signature", on_validate_signature, COMMAND_VALIDATE_SIGNATURE) @@ -200,6 +201,7 @@ namespace currency std::string m_port; std::string m_bind_ip; bool m_ignore_offline_status; + bool m_enabled_admin_api = false; epee::net_utils::http::i_chain_handler* m_prpc_chain_handler = nullptr; }; } From a08772ea6a6ecf53f874fb6f9b2676830744f5df Mon Sep 17 00:00:00 2001 From: Dmitry Matsiukhov <46869283+dimmarvel@users.noreply.github.com> Date: Tue, 15 Jul 2025 23:36:53 +0300 Subject: [PATCH 47/65] coretests: tx_input_mixins test added (test that will combine spending old coins and new coins in one tx and use mixins as 15) * try to write test for 2 input with nmix * one of incorrect version * add test for input old/new * refactoring and add comments * delete garbage * fix from vector variant to unordered_map * add comment * using to typedef --- tests/core_tests/chaingen.cpp | 46 ++++++++++---- tests/core_tests/chaingen.h | 19 ++++-- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/tx_validation.cpp | 99 ++++++++++++++++++++++++++++++ tests/core_tests/tx_validation.h | 8 +++ 5 files changed, 155 insertions(+), 18 deletions(-) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index d6931f65..a2560f31 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1421,7 +1421,7 @@ bool fill_tx_sources(std::vector& sources, const std::vector& sources, const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix, const std::vector& sources_to_avoid, - bool check_for_spends, bool check_for_unlocktime, bool use_ref_by_id, uint64_t* p_sources_amount_found /* = nullptr */) + bool check_for_spends, bool check_for_unlocktime, bool use_ref_by_id, uint64_t* p_sources_amount_found /* = nullptr */, const mixins_per_input* nmix_map /* = nullptr */) { uint64_t fts_flags = (check_for_spends ? fts_check_for_spends : fts_none) | @@ -1429,17 +1429,18 @@ bool fill_tx_sources(std::vector& sources, const std: (use_ref_by_id ? fts_use_ref_by_id : fts_none) | fts_check_for_hf4_min_coinage; - return fill_tx_sources(sources, events, blk_head, from, amount, nmix, sources_to_avoid, fts_flags, p_sources_amount_found); + return fill_tx_sources(sources, events, blk_head, from, amount, nmix, sources_to_avoid, fts_flags, p_sources_amount_found, nmix_map); } bool fill_tx_sources(std::vector& sources, const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix, - const std::vector& sources_to_avoid, uint64_t fts_flags, uint64_t* p_sources_amount_found /* = nullptr */) + const std::vector& sources_to_avoid, uint64_t fts_flags, uint64_t* p_sources_amount_found /* = nullptr */, + const mixins_per_input* nmix_map /* = nullptr */) { std::unordered_map amounts; amounts[native_coin_asset_id] = amount; std::unordered_map sources_amounts; - if (!fill_tx_sources(sources, events, blk_head, from, amounts, nmix, sources_to_avoid, fts_flags, &sources_amounts)) + if (!fill_tx_sources(sources, events, blk_head, from, amounts, nmix, sources_to_avoid, fts_flags, &sources_amounts, nmix_map)) return false; if (p_sources_amount_found) *p_sources_amount_found = sources_amounts[native_coin_asset_id]; @@ -1448,7 +1449,8 @@ bool fill_tx_sources(std::vector& sources, const std: bool fill_tx_sources(std::vector& sources, const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, const std::unordered_map& amounts, size_t nmix, - const std::vector& sources_to_avoid, uint64_t fts_flags, std::unordered_map* p_sources_amounts /* = nullptr */) + const std::vector& sources_to_avoid, uint64_t fts_flags, std::unordered_map* p_sources_amounts /* = nullptr */, + const mixins_per_input* nmix_map = nullptr) { map_output_idx_t outs; map_output_t outs_mine; @@ -1558,7 +1560,23 @@ bool fill_tx_sources(std::vector& sources, const std: ts.real_out_amount_blinding_mask = oi.amount_blinding_mask; ts.real_output_in_tx_index = oi.out_no; ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // source tx public key - if (!fill_output_entries(outs[o.first], sender_out, nmix, fts_flags & fts_check_for_unlocktime, fts_flags & fts_use_ref_by_id, + + // If we use nmix_map, we should use local_nmix instead of nmix + // to allow different nmix for different inputs in the same transaction. + // If nmix_map is not provided, we use nmix as local_nmix. + size_t local_nmix = nmix; + if (nmix_map) + { + // Try to find an override for this input index 'i' + auto it = nmix_map->find(i); + if (it != nmix_map->end()) + { + local_nmix = it->second; + } + // leave local_nmix at its default + } + + if (!fill_output_entries(outs[o.first], sender_out, local_nmix, fts_flags & fts_check_for_unlocktime, fts_flags & fts_use_ref_by_id, next_block_height, head_block_ts, ts.real_output, ts.outputs)) { continue; @@ -1592,7 +1610,9 @@ bool fill_tx_sources_and_destinations(const std::vector& event bool check_for_spends, bool check_for_unlocktime, size_t minimum_sigs, - bool use_ref_by_id) + bool use_ref_by_id, + const mixins_per_input* nmix_map +) { CHECK_AND_ASSERT_MES(!to.empty(), false, "destination addresses vector is empty"); CHECK_AND_ASSERT_MES(amount + fee > amount, false, "amount + fee overflow!"); @@ -1601,7 +1621,7 @@ bool fill_tx_sources_and_destinations(const std::vector& event bool b_multisig = to.size() > 1; uint64_t source_amount_found = 0; - bool r = fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix, std::vector(), check_for_spends, check_for_unlocktime, use_ref_by_id, &source_amount_found); + bool r = fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix, std::vector(), check_for_spends, check_for_unlocktime, use_ref_by_id, &source_amount_found, nmix_map); CHECK_AND_ASSERT_MES(r, false, "couldn't fill transaction sources (nmix = " << nmix << "): " << ENDL << " required: " << print_money(amount + fee) << " = " << std::fixed << std::setprecision(1) << ceil(1.0 * (amount + fee) / TESTS_DEFAULT_FEE) << " x TESTS_DEFAULT_FEE" << ENDL << " found coins: " << print_money(source_amount_found) << " = " << std::fixed << std::setprecision(1) << ceil(1.0 * source_amount_found / TESTS_DEFAULT_FEE) << " x TESTS_DEFAULT_FEE" << ENDL << @@ -1673,9 +1693,10 @@ bool fill_tx_sources_and_destinations(const std::vector& event std::vector& destinations, bool check_for_spends, bool check_for_unlocktime, - bool use_ref_by_id) + bool use_ref_by_id, + const mixins_per_input* nmix_map) { - return fill_tx_sources_and_destinations(events, blk_head, from, std::list({ to }), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime, 0, use_ref_by_id); + return fill_tx_sources_and_destinations(events, blk_head, from, std::list({ to }), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime, 0, use_ref_by_id, nmix_map); } bool fill_tx_sources_and_destinations(const std::vector& events, const currency::block& blk_head, @@ -1685,9 +1706,10 @@ bool fill_tx_sources_and_destinations(const std::vector& event std::vector& destinations, bool check_for_spends, bool check_for_unlocktime, - bool use_ref_by_id) + bool use_ref_by_id, + const mixins_per_input* nmix_map) { - return fill_tx_sources_and_destinations(events, blk_head, from.get_keys(), to.get_public_address(), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime, use_ref_by_id); + return fill_tx_sources_and_destinations(events, blk_head, from.get_keys(), to.get_public_address(), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime, use_ref_by_id, nmix_map); } /* diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index e9bf05a3..6bbda6e7 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -227,6 +227,7 @@ VARIANT_TAG(binary_archive, core_hardforks_config, 0xd2); typedef boost::variant test_event_entry; typedef std::unordered_map map_hash2tx_t; +typedef std::unordered_map mixins_per_input; enum test_tx_split_strategy { tests_default_split_strategy /*height-based, TODO*/, tests_void_split_strategy, tests_null_split_strategy, tests_digits_split_strategy, tests_random_split_strategy }; struct test_gentime_settings @@ -755,13 +756,16 @@ bool fill_tx_sources(std::vector& sources, const std: bool fill_tx_sources(std::vector& sources, const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix, const std::vector& sources_to_avoid, bool check_for_spends = true, bool check_for_unlocktime = true, - bool use_ref_by_id = false, uint64_t* p_sources_amount_found = nullptr); + bool use_ref_by_id = false, uint64_t* p_sources_amount_found = nullptr, + const mixins_per_input* nmix_map = nullptr); bool fill_tx_sources(std::vector& sources, const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix, - const std::vector& sources_to_avoid, uint64_t fts_flags, uint64_t* p_sources_amount_found = nullptr); + const std::vector& sources_to_avoid, uint64_t fts_flags, uint64_t* p_sources_amount_found = nullptr, + const mixins_per_input* nmix_map = nullptr); bool fill_tx_sources(std::vector& sources, const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, const std::unordered_map& amounts, size_t nmix, - const std::vector& sources_to_avoid, uint64_t fts_flags, std::unordered_map* p_sources_amounts = nullptr); + const std::vector& sources_to_avoid, uint64_t fts_flags, std::unordered_map* p_sources_amounts = nullptr, + const mixins_per_input* nmix_map = nullptr); bool fill_tx_sources_and_destinations(const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, const std::list& to, @@ -770,7 +774,8 @@ bool fill_tx_sources_and_destinations(const std::vector& event bool check_for_spends = true, bool check_for_unlocktime = true, size_t minimum_sigs = SIZE_MAX, - bool use_ref_by_id = false); + bool use_ref_by_id = false, + const mixins_per_input* nmix_map = nullptr); bool fill_tx_sources_and_destinations(const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, const currency::account_public_address& to, uint64_t amount, uint64_t fee, size_t nmix, @@ -778,7 +783,8 @@ bool fill_tx_sources_and_destinations(const std::vector& event std::vector& destinations, bool check_for_spends = true, bool check_for_unlocktime = true, - bool use_ref_by_id = false); + bool use_ref_by_id = false, + const mixins_per_input* nmix_map = nullptr); bool fill_tx_sources_and_destinations(const std::vector& events, const currency::block& blk_head, const currency::account_base& from, const currency::account_base& to, uint64_t amount, uint64_t fee, size_t nmix, @@ -786,7 +792,8 @@ bool fill_tx_sources_and_destinations(const std::vector& event std::vector& destinations, bool check_for_spends = true, bool check_for_unlocktime = true, - bool use_ref_by_id = false); + bool use_ref_by_id = false, + const mixins_per_input* nmix_map = nullptr); uint64_t get_balance(const currency::account_keys& addr, const std::vector& blockchain, const map_hash2tx_t& mtx, bool dbg_log = false); uint64_t get_balance(const currency::account_base& addr, const std::vector& blockchain, const map_hash2tx_t& mtx, bool dbg_log = false); void balance_via_wallet(const tools::wallet2& w, const crypto::public_key& asset_id, uint64_t* p_total, uint64_t* p_unlocked = 0, uint64_t* p_awaiting_in = 0, uint64_t* p_awaiting_out = 0, uint64_t* p_mined = 0); diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 978da46a..801aa2f8 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1229,6 +1229,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "3"); GENERATE_AND_PLAY(input_refers_to_incompatible_by_type_output); GENERATE_AND_PLAY_HF(tx_pool_validation_and_chain_switch, "4-*"); + GENERATE_AND_PLAY(tx_input_mixins); // Double spend GENERATE_AND_PLAY(gen_double_spend_in_tx); diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 91274083..b3458bac 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -1836,6 +1836,7 @@ bool tx_pool_semantic_validation::generate(std::vector& events } CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + } // Two entries of the same type in extra. @@ -2728,3 +2729,101 @@ bool tx_pool_validation_and_chain_switch::c1(currency::core& c, size_t ev_index, return true; } +tx_input_mixins::tx_input_mixins() +{ + REGISTER_CALLBACK_METHOD(tx_input_mixins, configure_core); +} + +bool tx_input_mixins::configure_core(currency::core& c, size_t ev_index, const std::vector& events) +{ + currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config(); + pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; + pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH; + pc.hf4_minimum_mixins = 5; + pc.hard_forks.set_hardfork_height(1, 0); + pc.hard_forks.set_hardfork_height(2, 1); + pc.hard_forks.set_hardfork_height(3, 1); + pc.hard_forks.set_hardfork_height(4, 31); + c.get_blockchain_storage().set_core_runtime_config(pc); + return true; +} + +// Tests that post-HF4, legacy txin_to_key inputs accept any mixin count, while new txin_zc inputs enforce a >= 15 mixin minimum +// are in the same vin and work together +bool tx_input_mixins::generate(std::vector& events) const +{ + uint64_t ts = test_core_time::get_time(); + + GENERATE_ACCOUNT(miner_acc); + GENERATE_ACCOUNT(alice_acc); + GENERATE_ACCOUNT(bob_acc); + + m_hardforks.set_hardfork_height(1, 0); + m_hardforks.set_hardfork_height(2, 1); + m_hardforks.set_hardfork_height(3, 1); + m_hardforks.set_hardfork_height(4, 31); + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); + DO_CALLBACK(events, "configure_core"); + + // mine one block, then rewind enough to unlock initial coinbase funds + 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*2); + + // build tx_a_1: single txin_to_key output of 15 coins to Alice + transaction tx_a_1; + bool r = construct_tx_with_many_outputs(m_hardforks, events, blk_1r, miner_acc.get_keys(), + alice_acc.get_public_address(), MK_TEST_COINS(15), 1, TESTS_DEFAULT_FEE, tx_a_1); + CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs 1 failed"); + events.push_back(tx_a_1); + + // build tx_a_2: 16 outputs of 15 coins each to Bob for mixins + transaction tx_a_2; + r = construct_tx_with_many_outputs(m_hardforks, events, blk_1r, miner_acc.get_keys(), + bob_acc.get_public_address(), MK_TEST_COINS(15*16), 16, TESTS_DEFAULT_FEE, tx_a_2); + CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs 2 failed"); + events.push_back(tx_a_2); + + MAKE_NEXT_BLOCK_TX_LIST(events, blk_1r_1, blk_1r, miner_acc, std::list({ tx_a_1, tx_a_2 })); + + // mine a couple more blocks and rewind to generate new spendable outputs + MAKE_NEXT_BLOCK(events, blk_2, blk_1r_1, miner_acc); + REWIND_BLOCKS_N(events, blk_2r, blk_2, miner_acc, 4); + MAKE_NEXT_BLOCK(events, blk_3, blk_2r, miner_acc); + REWIND_BLOCKS_N(events, blk_4r, blk_3, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + // make sure HF4 is active at 31 height + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + + // build tx_b with zc hf4 input, send 15 coins from miner -> Alice + std::vector sources_b; + std::vector destinations_b; + CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations( + events, blk_4r, miner_acc, alice_acc, MK_TEST_COINS(15), TESTS_DEFAULT_FEE, 2, sources_b, destinations_b), + false, "fill_tx_sources_and_destinations failed"); + currency::transaction tx_b{}; + r = construct_tx(miner_acc.get_keys(), sources_b, destinations_b, events, this, tx_b); + CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + events.push_back(tx_b); + + // mine tx_b and rewind to unlock its outputs + MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4r, miner_acc, tx_b); + REWIND_BLOCKS_N(events, blk_5r, blk_5, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + std::vector sources_c; + std::vector destinations_c; + // For input #0 use 5 mixins (old-style ring-CT allows any mixins) + // For input #1 use 16 mixins (new-style txin_zc enforces >=15 once HF4 is live) + mixins_per_input nmix_map = { {0, 5}, {1, 16} }; + CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations( + events, blk_5r, alice_acc, bob_acc, MK_TEST_COINS(29), TESTS_DEFAULT_FEE, 5, sources_c, destinations_c, + true, true, false, &nmix_map), false, "fill_tx_sources_and_destinations failed"); + currency::transaction tx_c{}; + r = construct_tx(alice_acc.get_keys(), sources_c, destinations_c, events, this, tx_c); + LOG_PRINT_GREEN("tx_c alice -> bob \n" << obj_to_json_str(tx_c), LOG_LEVEL_0); + CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + events.push_back(tx_c); + + MAKE_NEXT_BLOCK_TX1(events, blk_6, blk_5r, miner_acc, tx_c); + + return true; +} diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 3428d1eb..5eeea597 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -183,3 +183,11 @@ struct tx_pool_validation_and_chain_switch : public wallet_test bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +struct tx_input_mixins: public test_chain_unit_enchanced +{ + tx_input_mixins(); + + bool configure_core(currency::core& c, size_t ev_index, const std::vector& events); + bool generate(std::vector& events) const; +}; From fed84de8b78f8c3904e6eac91d02786a0ecc0fd4 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 15 Jul 2025 23:59:20 +0300 Subject: [PATCH 48/65] compilation fix --- tests/core_tests/chaingen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index a2560f31..3e893503 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1450,7 +1450,7 @@ bool fill_tx_sources(std::vector& sources, const std: bool fill_tx_sources(std::vector& sources, const std::vector& events, const currency::block& blk_head, const currency::account_keys& from, const std::unordered_map& amounts, size_t nmix, const std::vector& sources_to_avoid, uint64_t fts_flags, std::unordered_map* p_sources_amounts /* = nullptr */, - const mixins_per_input* nmix_map = nullptr) + const mixins_per_input* nmix_map /* = nullptr */) { map_output_idx_t outs; map_output_t outs_mine; From 97b17221d97c6dd36b370f27e14d07418c06b679 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 18 Jul 2025 13:39:01 +0300 Subject: [PATCH 49/65] === build number: 418 -> 419 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index e67041c8..597939fc 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 418 +#define PROJECT_VERSION_BUILD_NO 419 #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 "]" From 4695229f2ab607fefa56f00712d710c58b98c345 Mon Sep 17 00:00:00 2001 From: Dmitry Matsiukhov <46869283+dimmarvel@users.noreply.github.com> Date: Fri, 18 Jul 2025 20:17:02 +0300 Subject: [PATCH 50/65] fix warnings (#546) * fix warnings * refactoring --- src/connectivity_tool/conn_tool.cpp | 2 +- src/currency_core/blockchain_storage.cpp | 4 +-- src/simplewallet/simplewallet.cpp | 10 +++--- src/wallet/wallet2.cpp | 4 +-- tests/core_tests/chaingen.cpp | 2 +- tests/core_tests/double_spend.inl | 2 +- tests/core_tests/hard_fork_4.cpp | 3 -- tests/core_tests/multiassets_test.cpp | 17 +++------- tests/core_tests/tx_validation.cpp | 2 +- tests/core_tests/wallet_rpc_tests.cpp | 1 - tests/core_tests/wallet_tests.cpp | 3 -- tests/functional_tests/crypto_tests.cpp | 33 ++++++++++--------- tests/functional_tests/crypto_tests_clsag.h | 2 -- .../crypto_tests_performance.h | 5 ++- .../crypto_tests_range_proofs.h | 2 +- .../functional_tests/difficulty_analysis.cpp | 3 +- tests/performance_tests/api_test.cpp | 2 +- .../chacha_stream_performance_test.cpp | 9 ++--- tests/performance_tests/construct_tx.h | 2 +- tests/performance_tests/main.cpp | 2 +- tests/unit_tests/chacha_stream_test.cpp | 2 +- tests/unit_tests/decoy_selection.cpp | 2 +- tests/unit_tests/multiassets_test.cpp | 2 -- 23 files changed, 46 insertions(+), 70 deletions(-) diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp index 1c8d5c62..e5aa90a8 100644 --- a/src/connectivity_tool/conn_tool.cpp +++ b/src/connectivity_tool/conn_tool.cpp @@ -826,7 +826,7 @@ bool handle_increment_build_no(po::variables_map& vm) bool handle_update_maintainers_info(po::variables_map& vm) { log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); - size_t rpc_port = RPC_DEFAULT_PORT; + [[maybe_unused]] size_t rpc_port = RPC_DEFAULT_PORT; if(!command_line::has_arg(vm, arg_rpc_port)) { std::cout << "ERROR: rpc port not set" << ENDL; diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index f7d4e38a..a6fb1142 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -7101,7 +7101,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt if (!m_is_in_checkpoint_zone) { auto cleanup = [&](){ - bool add_res = m_tx_pool.add_tx(tx, tvc, true, true); + m_tx_pool.add_tx(tx, tvc, true, true); m_tx_pool.add_transaction_to_black_list(tx); purge_block_data_from_blockchain(bl, tx_processed_count); bvc.m_verification_failed = true; @@ -8102,7 +8102,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, for (size_t pk_n = 0; pk_n < pub_keys.size(); ++pk_n) { - crypto::public_key& pk = pub_keys[pk_n]; + [[maybe_unused]] crypto::public_key& pk = pub_keys[pk_n]; crypto::hash tx_id = null_hash; uint64_t out_n = UINT64_MAX; auto &off = abs_key_offsets[pk_n]; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 63a11799..52cfa146 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -789,7 +789,6 @@ bool simple_wallet::save(const std::vector &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::process_ki_restoration() { - bool r = false; if (!m_restore_ki_in_wo_wallet.empty()) { std::wstring wo_filename = epee::string_encoding::utf8_to_wstring(m_restore_ki_in_wo_wallet); @@ -941,7 +940,7 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf ", tx " << wti.tx_hash; for (const auto& st : wti.subtransfers) { - epee::log_space::console_colors color = st.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta; + [[maybe_unused]] 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_token_info_string(st.asset_id, decimal_points); @@ -1174,7 +1173,7 @@ std::string wti_to_text_line(const tools::wallet_public::wallet_transfer_info& w //---------------------------------------------------------------------------------------------------- bool simple_wallet::export_recent_transfers(const std::vector& args) { - bool export_to_json = true; + [[maybe_unused]] bool export_to_json = true; bool ignore_pos = false; if (args.size() > 1) { @@ -2718,7 +2717,6 @@ bool simple_wallet::sweep_bare_outs(const std::vector &args) { CONFIRM_WITH_PASSWORD(); SIMPLE_WALLET_BEGIN_TRY_ENTRY(); - bool r = false; if (args.size() > 1) { @@ -3070,7 +3068,7 @@ int seed_doctor() } bool pass_protected = false; - bool success = account_base::is_seed_password_protected(seed, pass_protected); + account_base::is_seed_password_protected(seed, pass_protected); success_msg_writer() << "SECURED_SEED: " << (pass_protected ? "true" : "false"); if (pass_protected) @@ -3176,7 +3174,7 @@ int seed_doctor() success_msg_writer() << "No address and no checksum, recovery is limited only to date reset"; std::string result = boost::algorithm::join(words, " "); account_base acc; - bool r = acc.restore_from_seed_phrase(result, passphrase); + acc.restore_from_seed_phrase(result, passphrase); success_msg_writer() << "Potential seed candidate:\n" << result << "\nAddress: " << acc.get_public_address_str(); return EXIT_FAILURE; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 88249e7a..2b9b535e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6825,8 +6825,8 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys if (true) { size_t fake_outputs_count = fake_outputs_count_; - uint64_t zarcanum_start_from = m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM]; - uint64_t current_size = m_chain.get_blockchain_current_size(); + [[maybe_unused]] uint64_t zarcanum_start_from = m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM]; + [[maybe_unused]] uint64_t current_size = m_chain.get_blockchain_current_size(); bool need_to_request = fake_outputs_count != 0; COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request req = AUTO_VAL_INIT(req); diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 3e893503..87bfee59 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -2551,7 +2551,7 @@ bool generate_pos_block_with_extra_nonce(test_generator& generator, const std::v if (generator.get_hardforks().is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, height)) { std::vector sources; - bool ok = fill_tx_sources( + fill_tx_sources( sources, events, prev_block, miner.get_keys(), UINT64_MAX, 0, false, false, true ); diff --git a/tests/core_tests/double_spend.inl b/tests/core_tests/double_spend.inl index 19ec33e9..524d3edc 100644 --- a/tests/core_tests/double_spend.inl +++ b/tests/core_tests/double_spend.inl @@ -96,7 +96,7 @@ bool gen_double_spend_in_tx::generate(std::vector attachments; size_t tx_hardfork_id{}; - uint64_t tx_version = get_tx_version_from_events(events); + uint64_t tx_version = this->get_tx_version_from_events(events); if (!construct_tx(bob_account.get_keys(), sources, destinations, attachments, tx_1, tx_version, tx_hardfork_id, uint64_t(0))) return false; diff --git a/tests/core_tests/hard_fork_4.cpp b/tests/core_tests/hard_fork_4.cpp index dc5fc492..6729c498 100644 --- a/tests/core_tests/hard_fork_4.cpp +++ b/tests/core_tests/hard_fork_4.cpp @@ -227,8 +227,6 @@ bool hardfork_4_wallet_transfer_with_mandatory_mixins::generate(std::vector bool hardfork_4_pop_tx_from_global_index::c1(currency::core& c, size_t ev_index, const std::vector& events) { auto& bcs = c.get_blockchain_storage(); - bool r = false; //currency::outs_index_stat outs_stat{}; //bcs.get_outs_index_stat(outs_stat); // 24 - bad, 22 - good diff --git a/tests/core_tests/multiassets_test.cpp b/tests/core_tests/multiassets_test.cpp index a3f11010..b6c6a2b3 100644 --- a/tests/core_tests/multiassets_test.cpp +++ b/tests/core_tests/multiassets_test.cpp @@ -1469,8 +1469,6 @@ bool eth_signed_asset_basics::c1(currency::core& c, size_t ev_index, const std:: crypto::public_key asset_id = currency::null_pkey; miner_wlt->deploy_new_asset(adb, destinations, ft, asset_id); - const transaction& tx = ft.tx; - LOG_PRINT_L0("Deployed new asset: " << asset_id << ", tx_id: " << ft.tx_id); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); @@ -2122,7 +2120,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec std::vector destinations{}; const auto& ado{m_ados_register.at(asset_position::gamma)}; crypto::secret_key one_time{}; - size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_1r)); + //size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_1r)); //fill_ado_version_based_onhardfork(ado, hf_n); //fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n); @@ -2148,7 +2146,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec std::vector destinations{}; crypto::secret_key one_time{}; const auto& ado{m_ados_register.at(asset_position::alpha)}; - size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); + //size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); //fill_ado_version_based_onhardfork(ado, hf_n); //fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n); @@ -2173,7 +2171,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec std::vector destinations{}; crypto::secret_key one_time{}; const auto& ado{m_ados_register.at(asset_position::beta)}; - size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); + //size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); //fill_ado_version_based_onhardfork(ado, hf_n); //fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n); @@ -2210,7 +2208,6 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec const auto& ado_register{m_ados_register.at(asset_position::beta)}; std::vector sources{}; std::vector destinations{}; - crypto::secret_key one_time{}; tx_source_entry source{}; finalize_tx_param ftp{}; finalized_tx ftx{}; @@ -2452,8 +2449,6 @@ bool several_asset_emit_burn_txs_in_pool::generate(std::vector bool several_asset_emit_burn_txs_in_pool::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); miner_wlt->refresh(); std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); @@ -2614,7 +2609,6 @@ bool assets_transfer_with_smallest_amount::generate(std::vector= 4 // - bool r = false; uint64_t ts = test_core_time::get_time(); m_accounts.resize(TOTAL_ACCS_COUNT); account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts); @@ -2947,7 +2941,6 @@ bool asset_operations_and_chain_switching::generate(std::vector& events) { - bool r = false, stub = false;; std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); alice_wlt->refresh(); std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]); @@ -2962,7 +2955,7 @@ bool asset_operations_and_chain_switching::c1(currency::core& c, size_t ev_index bool asset_operations_and_chain_switching::c2(currency::core& c, size_t ev_index, const std::vector& events) { - bool r = false, stub = false;; + bool r = false; std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); alice_wlt->refresh(); std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]); @@ -2984,7 +2977,7 @@ bool asset_operations_and_chain_switching::c2(currency::core& c, size_t ev_index bool asset_operations_and_chain_switching::c3(currency::core& c, size_t ev_index, const std::vector& events) { - bool r = false, stub = false;; + bool r = false; std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); alice_wlt->refresh(); std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]); diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index b3458bac..20ada534 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -1651,6 +1651,7 @@ bool tx_version_against_hardfork::generate(std::vector& events { case ZANO_HARDFORK_04_ZARCANUM: tx_hardfork_id = 0; + [[fallthrough]]; case ZANO_HARDFORK_05: tx_version_good = TRANSACTION_VERSION_POST_HF4; tx_version_bad = TRANSACTION_VERSION_PRE_HF4; @@ -2568,7 +2569,6 @@ bool input_refers_to_incompatible_by_type_output::assert_zc_input_refers_bare_ou } { - bool all_inputs_have_explicit_native_asset_id{}; blockchain_storage::check_tx_inputs_context ctic{}; CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), ctic), false); diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index bd4bd7d5..902ee0ab 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -829,7 +829,6 @@ bool wallet_true_rpc_pos_mining::generate(std::vector& events) bool wallet_true_rpc_pos_mining::c1(currency::core& c, size_t ev_index, const std::vector& events) { - bool r = false; std::shared_ptr miner_wlt = init_playtime_test_wallet_with_true_http_rpc(events, c, MINER_ACC_IDX); std::shared_ptr alice_wlt = init_playtime_test_wallet_with_true_http_rpc(events, c, ALICE_ACC_IDX); diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 88da1f6e..557c830c 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -3799,7 +3799,6 @@ bool wallet_and_sweep_below::generate(std::vector& events) con bool wallet_and_sweep_below::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); uint64_t miner_balance = (3 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW - 1) * COIN; @@ -3960,14 +3959,12 @@ bool wallet_reorganize_and_trim_test::c1(currency::core& c, size_t ev_index, con mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 2); mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_REORGANIZE_AND_TRIM_TEST_REORG_SIZE); - uint64_t h1 = c.get_blockchain_storage().get_top_block_height(); miner_wlt->refresh(); uint64_t unlocked = 0; uint64_t total = miner_wlt->balance(unlocked); c.get_blockchain_storage().truncate_blockchain(c.get_blockchain_storage().get_top_block_height() - (WALLET_REORGANIZE_AND_TRIM_TEST_REORG_SIZE-1)); mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 10); - uint64_t h2 = c.get_blockchain_storage().get_top_block_height(); miner_wlt->refresh(); uint64_t unlocked2 = 0; uint64_t total2 = miner_wlt->balance(unlocked2); diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 599922f2..6ff25a18 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -690,12 +690,12 @@ size_t find_pos_hash(const boost::multiprecision::uint256_t& L_div_D, const curr TEST(crypto, pos) { //scalar_t D = 10000000000000001u; - scalar_t D = 13042196742415129u; // prime number - currency::wide_difficulty_type D_w = D.as_boost_mp_type().convert_to(); - uint64_t amount = 1000000000000; - size_t count_old = 0; - size_t count_new = 0; - size_t count_3 = 0; + [[maybe_unused]] scalar_t D = 13042196742415129u; // prime number + [[maybe_unused]] currency::wide_difficulty_type D_w = D.as_boost_mp_type().convert_to(); + [[maybe_unused]] uint64_t amount = 1000000000000; + [[maybe_unused]] size_t count_old = 0; + [[maybe_unused]] size_t count_new = 0; + [[maybe_unused]] size_t count_3 = 0; scalar_t x; x.make_random(); @@ -704,14 +704,14 @@ TEST(crypto, pos) const boost::multiprecision::uint256_t c_L_w = c_scalar_L.as_boost_mp_type(); const boost::multiprecision::uint256_t c_L_div_D_w = c_L_w / D_w; - boost::multiprecision::uint512_t h_tres = c_L_div_D_w * amount; + [[maybe_unused]] boost::multiprecision::uint512_t h_tres = c_L_div_D_w * amount; - currency::wide_difficulty_type final_diff = D_w / amount; + [[maybe_unused]] currency::wide_difficulty_type final_diff = D_w / amount; - boost::multiprecision::uint512_t Lv = boost::multiprecision::uint512_t(c_L_w) * amount; + [[maybe_unused]] boost::multiprecision::uint512_t Lv = boost::multiprecision::uint512_t(c_L_w) * amount; constexpr uint64_t c_coin = 1000000000000; - const uint64_t amounts[] = { + [[maybe_unused]] const uint64_t amounts[] = { c_coin / 100, c_coin / 50, c_coin / 20, @@ -738,9 +738,9 @@ TEST(crypto, pos) c_coin * 500000 }; - uint64_t kernel = 0; - scalar_t d0 = 0; - uint64_t d1 = 0; + [[maybe_unused]] uint64_t kernel = 0; + [[maybe_unused]] scalar_t d0 = 0; + [[maybe_unused]] uint64_t d1 = 0; /* @@ -1064,7 +1064,8 @@ TEST(crypto, hp) TEST(perf, cn_fast_hash) { //return true; - const crypto::hash h_initial = *(crypto::hash*)(&scalar_t::random()); + scalar_t s_rnd = scalar_t::random(); + const crypto::hash h_initial = *(crypto::hash*)(&s_rnd); std::vector> test_data; test_data.push_back(std::vector(32, 0)); @@ -1631,8 +1632,8 @@ TEST(crypto, schnorr_sig) { public_key invalid_pk = parse_tpod_from_hex_string("0000000000000000000000000000000000000000000000000000000000000001"); ASSERT_FALSE(check_key(invalid_pk)); - - hash m = *(crypto::hash*)(&scalar_t::random()); + scalar_t s_rnd = scalar_t::random(); + hash m = *(crypto::hash*)(&s_rnd); for(size_t i = 0; i < 100; ++i) { generic_schnorr_sig_s ss{}; diff --git a/tests/functional_tests/crypto_tests_clsag.h b/tests/functional_tests/crypto_tests_clsag.h index 96897e05..e9273b50 100644 --- a/tests/functional_tests/crypto_tests_clsag.h +++ b/tests/functional_tests/crypto_tests_clsag.h @@ -219,8 +219,6 @@ TEST(clsag, bad_sig) TEST(clsag, sig_difference) { - int cmp_res = 0; - clsag_gg_sig_check_t cc0, cc1; cc0.prepare_random_data(8); cc1 = cc0; // get the same input data diff --git a/tests/functional_tests/crypto_tests_performance.h b/tests/functional_tests/crypto_tests_performance.h index fff2f461..c1530268 100644 --- a/tests/functional_tests/crypto_tests_performance.h +++ b/tests/functional_tests/crypto_tests_performance.h @@ -344,7 +344,8 @@ TEST(perf, primitives) p = p + p; } ge_p3 Q; - ge_scalarmult_base(&Q, &scalar_t::random().m_s[0]); + scalar_t s_rnd = scalar_t::random(); + ge_scalarmult_base(&Q, &s_rnd.m_s[0]); std::vector results(rnd_indecies.size()); t.start(); @@ -1109,8 +1110,6 @@ struct pme_runner_t : public pme_runner_i TEST(perf, msm) { - bool r = false; - std::deque> runners; //runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 1)); //runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 2)); diff --git a/tests/functional_tests/crypto_tests_range_proofs.h b/tests/functional_tests/crypto_tests_range_proofs.h index 527e84d4..cb68deee 100644 --- a/tests/functional_tests/crypto_tests_range_proofs.h +++ b/tests/functional_tests/crypto_tests_range_proofs.h @@ -352,7 +352,7 @@ TEST(bppe, power_128) std::vector& commitments = commitments_vector.back(); scalar_vec_t masks, masks2; - for(auto& el: values) + for (size_t i = 0; i < values.size(); ++i) { masks.emplace_back(scalar_t::random()); masks2.emplace_back(scalar_t::random()); diff --git a/tests/functional_tests/difficulty_analysis.cpp b/tests/functional_tests/difficulty_analysis.cpp index 3df52f21..d68d2583 100644 --- a/tests/functional_tests/difficulty_analysis.cpp +++ b/tests/functional_tests/difficulty_analysis.cpp @@ -236,7 +236,6 @@ void perform_simulation_for_function(const std::map& timesta std::vector backward_cumul_difficulties; backward_cumul_difficulties.reserve(BBR_DIFFICULTY_WINDOW); std::copy(cumul_difficulties.rbegin(), cumul_difficulties.rbegin() + BBR_DIFFICULTY_WINDOW - 1, std::back_inserter(backward_cumul_difficulties)); - uint64_t ts = timestamps.back(); curren_difficulty = cb(backward_timestamps, backward_cumul_difficulties, BBR_DIFFICULTY_TARGET); } cumul_difficulties.push_back(cumul_difficulties.back() + curren_difficulty); @@ -357,7 +356,7 @@ void hash_rate_analysis(const std::string& path) uint64_t curren_hashrate = 0; uint64_t step = 10; uint64_t hash_rate_range = 10; - uint64_t second_windowf_or_hashrate = 20*60; + // uint64_t second_windowf_or_hashrate = 20*60; for (size_t i = hash_rate_range; i != blocks.size(); i++) { diff --git a/tests/performance_tests/api_test.cpp b/tests/performance_tests/api_test.cpp index 47fa456e..fb7678f2 100644 --- a/tests/performance_tests/api_test.cpp +++ b/tests/performance_tests/api_test.cpp @@ -19,7 +19,7 @@ int test_get_rand_outs() m_core_proxy->set_connection_addr("127.0.0.1:11211"); m_core_proxy->check_connection(); - bool r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, rsp); + m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, rsp); return 0; } diff --git a/tests/performance_tests/chacha_stream_performance_test.cpp b/tests/performance_tests/chacha_stream_performance_test.cpp index fdae7e36..8a331b2b 100644 --- a/tests/performance_tests/chacha_stream_performance_test.cpp +++ b/tests/performance_tests/chacha_stream_performance_test.cpp @@ -41,9 +41,8 @@ bool perform_crypt_stream_iteration(const std::list hits; diff --git a/tests/unit_tests/multiassets_test.cpp b/tests/unit_tests/multiassets_test.cpp index 533d8826..16b3fa7a 100644 --- a/tests/unit_tests/multiassets_test.cpp +++ b/tests/unit_tests/multiassets_test.cpp @@ -443,8 +443,6 @@ TEST(multiassets, native_serialization_get_or_calculate_asset_id_undefined) '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x97', '\x9e', '\xb7', '\x06', '\xac', '\xe2', '\xeb', '\x83', '\xf9', '\x12', 'V', 'X', '\xb2', '?', '\xb3', 'R', ' ', '\x84', '\x80', '\xcb', ';', '\x90', '\xc4', '>', '-', '\xf0', '\xd2', '\x98', '\xf9', 'u', 'N', '\xbc'}; - crypto::point_t expected_point_asset_id{}; - crypto::public_key expected_asset_id{}; crypto::point_t calculated_point_asset_id{}; crypto::public_key calculated_asset_id{}; const std::optional ado{deserialize(serialization_method::native, serialized_ado)}; From 94c2e65dada8fea3925188d867349a7eeae705d8 Mon Sep 17 00:00:00 2001 From: Dmitry Matsiukhov <46869283+dimmarvel@users.noreply.github.com> Date: Sat, 19 Jul 2025 15:49:10 +0300 Subject: [PATCH 51/65] coretests: tx_coinbase_separate_sig_flag test added; (separate flag for PoW miner tx coinbase (#538)) * add tests for pow separate tx flag * refactoring test, leave only poW validation --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/tx_validation.cpp | 36 ++++++++++++++++++++++++++++++ tests/core_tests/tx_validation.h | 5 +++++ 3 files changed, 42 insertions(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 801aa2f8..fc670958 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1229,6 +1229,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "3"); GENERATE_AND_PLAY(input_refers_to_incompatible_by_type_output); GENERATE_AND_PLAY_HF(tx_pool_validation_and_chain_switch, "4-*"); + GENERATE_AND_PLAY_HF(tx_coinbase_separate_sig_flag, "4-*"); GENERATE_AND_PLAY(tx_input_mixins); // Double spend diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 20ada534..78bc9fa3 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -2729,6 +2729,42 @@ bool tx_pool_validation_and_chain_switch::c1(currency::core& c, size_t ev_index, return true; } +// Сoinbase transactions must NOT allow the TX_FLAG_SIGNATURE_MODE_SEPARATE flag. +// Сhecks that setting this flag for coinbase fails, while a default coinbase (without the flag) succeeds. +bool tx_coinbase_separate_sig_flag::generate(std::vector& events) const +{ + GENERATE_ACCOUNT(miner); + + uint64_t ts = test_core_time::get_time(); + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts); + DO_CALLBACK(events, "configure_core"); + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); + + block blk_2; + auto coinbase_default_cb = [](transaction& miner_tx, const keypair&) -> bool { return true; }; + auto coinbase_separate_cb = [](transaction& miner_tx, const keypair&) -> bool + { + set_tx_flags(miner_tx, get_tx_flags(miner_tx) | TX_FLAG_SIGNATURE_MODE_SEPARATE); + return true; + }; + + // сonstruct a block with the forbidden flag, should fail after hf4 + bool with_separate_flag = generator.construct_block_gentime_with_coinbase_cb(blk_1r, miner, coinbase_separate_cb, blk_2); + CHECK_AND_ASSERT_MES(with_separate_flag, false, "expected failure because TX_FLAG_SIGNATURE_MODE_SEPARATE is forbidden for coinbase after HF4"); + + DO_CALLBACK(events, "mark_invalid_block"); + events.push_back(blk_2); + + // construct a default coinbase block, should succeed + bool default_tx = generator.construct_block_gentime_with_coinbase_cb(blk_1r, miner, coinbase_default_cb, blk_2); + CHECK_AND_ASSERT_MES(default_tx, true, "default coinbase must succeed"); + + events.push_back(blk_2); + + return true; +} + tx_input_mixins::tx_input_mixins() { REGISTER_CALLBACK_METHOD(tx_input_mixins, configure_core); diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 5eeea597..5a68d81d 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -184,6 +184,11 @@ struct tx_pool_validation_and_chain_switch : public wallet_test bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; +struct tx_coinbase_separate_sig_flag : public test_chain_unit_enchanced +{ + bool generate(std::vector& events) const; +}; + struct tx_input_mixins: public test_chain_unit_enchanced { tx_input_mixins(); From 854c198415f0766b60958c39099c29b75c71c551 Mon Sep 17 00:00:00 2001 From: sowle Date: Sun, 20 Jul 2025 02:34:45 +0300 Subject: [PATCH 52/65] reverted sanity check improvement --- src/serialization/stl_containers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serialization/stl_containers.h b/src/serialization/stl_containers.h index e347328a..34981ede 100644 --- a/src/serialization/stl_containers.h +++ b/src/serialization/stl_containers.h @@ -44,7 +44,7 @@ bool do_serialize(Archive &ar, std::vector &v) v.clear(); // very basic sanity check - if (ar.remaining_bytes() < (cnt * sizeof(T)) ) { + if (ar.remaining_bytes() < cnt) { ar.stream().setstate(std::ios::failbit); return false; } From b57fa844efa69cd9fb78eeb9aca56257b111a8f6 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 23 Jul 2025 19:20:19 +0300 Subject: [PATCH 53/65] ui update (PR 154, 155) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index f2f81791..fcc1aaf9 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit f2f81791757d791f2a478d1e486af90b8f82a7a1 +Subproject commit fcc1aaf997d4514ca2b93ee917fd4dee9461b79b From cd16b5c743d18053cdd0d423f85074d3aef9304c Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 23 Jul 2025 19:21:02 +0300 Subject: [PATCH 54/65] === build number: 422 -> 423 === --- src/version.h.in | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/version.h.in b/src/version.h.in index 86791731..4dd0c290 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,10 +8,6 @@ #define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -<<<<<<< HEAD -#define PROJECT_VERSION_BUILD_NO 421 -======= -#define PROJECT_VERSION_BUILD_NO 422 ->>>>>>> release +#define PROJECT_VERSION_BUILD_NO 423 #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 "]" From 260228433ca7d3b897b2dc220a548089db10e7d0 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 24 Jul 2025 18:07:42 +0300 Subject: [PATCH 55/65] === build number: 424 -> 425 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index 4dd0c290..d3bd4ae1 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 423 +#define PROJECT_VERSION_BUILD_NO 425 #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 "]" From 4923f644c4a35fa2b2363faa264e6825d895cb6e Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 24 Jul 2025 18:18:44 +0300 Subject: [PATCH 56/65] coretests: minor improvements for wallet_rpc_cold_signing --- tests/core_tests/wallet_rpc_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index 19c4b648..cf07ce5a 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -1347,7 +1347,7 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: miner_wlt->refresh(); bob_wlt->refresh(); - check_balance_via_wallet(*bob_wlt, "Bob", 0, 0, 0, 0, 0); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", 0, 0, 0, 0, 0), false, ""); // for post HF4 cases transfer some assets along with native coins crypto::public_key deployed_asset_id{}; @@ -1386,7 +1386,7 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: std::shared_ptr alice_wlt_wo = init_playtime_test_wallet(events, c, alice_acc_wo); alice_wlt_wo->refresh(); - check_balance_via_wallet(*alice_wlt_wo, "Alice (WO)", MK_TEST_COINS(100), 0, MK_TEST_COINS(100), 0, 0); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo, "Alice (WO)", MK_TEST_COINS(100), 0, MK_TEST_COINS(100), 0, 0), false, ""); // Alice: perform initial save-load to properly initialize internal wallet2 structures boost::filesystem::remove(epee::string_tools::cut_off_extension(m_wallet_filename) + L".outkey2ki"); From a93aefd5076e84ced26989b41323a60c627da1f0 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 24 Jul 2025 18:27:55 +0300 Subject: [PATCH 57/65] ui update (PR 156) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index fcc1aaf9..69df3c6d 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit fcc1aaf997d4514ca2b93ee917fd4dee9461b79b +Subproject commit 69df3c6d86e230dd406097676afa0d0b8c1d9231 From 96081db687a5175b1894b99ea8ffeb52d4d32110 Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 26 Jul 2025 02:26:08 +0300 Subject: [PATCH 58/65] coretests: wallet_rpc_multiple_receivers -- work in progress --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/wallet_rpc_tests.cpp | 94 +++++++++++++++++++++++++++ tests/core_tests/wallet_rpc_tests.h | 8 +++ 3 files changed, 103 insertions(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 26fde7c0..c5524110 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1104,6 +1104,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(wallet_rpc_exchange_suite, "3,4"); GENERATE_AND_PLAY_HF(wallet_true_rpc_pos_mining, "4-*"); GENERATE_AND_PLAY_HF(wallet_rpc_cold_signing, "3,5-*"); + // GENERATE_AND_PLAY_HF(wallet_rpc_multiple_receivers, "5-*"); work in progress -- sowle GENERATE_AND_PLAY(wallet_chain_switch_with_spending_the_same_ki); GENERATE_AND_PLAY(wallet_sending_to_integrated_address); GENERATE_AND_PLAY_HF(block_template_blacklist_test, "4-*"); diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index cf07ce5a..1f8b4dc9 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -1568,3 +1568,97 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std:: return true; } + +//------------------------------------------------------------------------------ + +// TODO: work in progress -- sowle +wallet_rpc_multiple_receivers::wallet_rpc_multiple_receivers() +{ + REGISTER_CALLBACK_METHOD(wallet_rpc_multiple_receivers, c1); +} + +void wallet_rpc_multiple_receivers::set_wallet_options(std::shared_ptr w) +{ + set_playtime_test_wallet_options(w); + w->set_concise_mode(false); +} + +bool wallet_rpc_multiple_receivers::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"); + + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); + + DO_CALLBACK(events, "c1"); + + return true; +} + +bool wallet_rpc_multiple_receivers::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); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX); + + tools::wallet_rpc_server miner_rpc(miner_wlt); + tools::wallet_rpc_server alice_rpc(alice_wlt); + + miner_wlt->refresh(); + //bob_wlt->refresh(); + //check_balance_via_wallet(*bob_wlt, "Bob", 0, 0, 0, 0, 0); + + // for post HF4 cases transfer some assets along with native coins + crypto::public_key deployed_asset_id{}; + size_t deployed_asset_decimal_point = 0; + + // miner deploys new asset and sends 50 coins of it to Alice + tools::wallet_public::COMMAND_ASSETS_DEPLOY::request req_deploy{}; + req_deploy.asset_descriptor.current_supply = 50; + req_deploy.asset_descriptor.decimal_point = deployed_asset_decimal_point; + req_deploy.asset_descriptor.full_name = "50 pounds per person"; + req_deploy.asset_descriptor.ticker = "50PPP"; + req_deploy.asset_descriptor.total_max_supply = 200; // for a family of four + req_deploy.destinations.emplace_back(tools::wallet_public::transfer_destination{50, m_accounts[ALICE_ACC_IDX].get_public_address_str(), null_pkey}); + req_deploy.do_not_split_destinations = true; + tools::wallet_public::COMMAND_ASSETS_DEPLOY::response res_deploy{}; + r = invoke_text_json_for_rpc(miner_rpc, "deploy_asset", req_deploy, res_deploy); + CHECK_AND_ASSERT_MES(r, false, "RPC 'deploy_asset' failed"); + deployed_asset_id = res_deploy.new_asset_id; + + + // + tools::wallet_public::COMMAND_RPC_TRANSFER::request tr_req{}; + tools::wallet_public::COMMAND_RPC_TRANSFER::response tr_res{}; + tr_req.destinations.emplace_back(tools::wallet_public::transfer_destination{MK_TEST_COINS(80), m_accounts[ALICE_ACC_IDX].get_public_address_str()}); + tr_req.destinations.emplace_back(tools::wallet_public::transfer_destination{MK_TEST_COINS(90), m_accounts[BOB_ACC_IDX].get_public_address_str()}); + tr_req.fee = TESTS_DEFAULT_FEE; + tr_req.mixin = 0; + tr_req.hide_receiver = false; + tr_req.push_payer = true; + r = invoke_text_json_for_rpc(miner_rpc, "transfer", tr_req, tr_res); + CHECK_AND_ASSERT_MES(r, false, "RPC failed"); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "enexpected pool txs count: " << c.get_pool_transactions_count()); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); + + + // Alice: prepare watch-only wallet + alice_wlt->refresh(); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", MK_TEST_COINS(80), 0, MK_TEST_COINS(80), 0, 0), false, ""); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", req_deploy.asset_descriptor.current_supply, 0, req_deploy.asset_descriptor.current_supply, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, ""); + + bob_wlt->refresh(); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", MK_TEST_COINS(90), 0, MK_TEST_COINS(90), 0, 0), false, ""); + + return true; +} + diff --git a/tests/core_tests/wallet_rpc_tests.h b/tests/core_tests/wallet_rpc_tests.h index 56855245..08e09017 100644 --- a/tests/core_tests/wallet_rpc_tests.h +++ b/tests/core_tests/wallet_rpc_tests.h @@ -74,3 +74,11 @@ struct wallet_rpc_cold_signing : public wallet_test mutable std::wstring m_wallet_filename = L"~coretests.wallet_rpc_cold_signing.file.tmp"; mutable std::string m_wallet_password = "ballerinacappuccina"; }; + +struct wallet_rpc_multiple_receivers : public wallet_test +{ + wallet_rpc_multiple_receivers(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); + void set_wallet_options(std::shared_ptr w); +}; From 3a9245f74336696ef707ed1d6537fbd33fc74135 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 31 Jul 2025 04:14:10 +0300 Subject: [PATCH 59/65] crypto::random refactoring and improvements (credits to @dimmarvel for spotting the thread safety issue) --- src/crypto/crypto.cpp | 54 +++++++++++++------------------ src/crypto/crypto.h | 20 +++++++++--- src/crypto/random.c | 29 +++++++++-------- src/crypto/random.h | 17 ++++------ tests/core_tests/random_helper.h | 8 ++--- tests/unit_tests/db_accessors.cpp | 2 +- tests/unit_tests/db_tests.cpp | 6 ++-- 7 files changed, 67 insertions(+), 69 deletions(-) diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index cfdfb866..b2b7c4bb 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2022 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -35,32 +35,20 @@ namespace crypto { const key_image I = *reinterpret_cast(&I_); const key_image L = *reinterpret_cast(&L_); - struct random_init_singleton - { - random_init_singleton() - { - grant_random_initialize(); - } - }; - - random_init_singleton init_rand; //place initializer here to avoid grant_random_initialize first call after threads will be possible(local static variables init is not thread-safe) - - using std::abort; - using std::int32_t; - using std::int64_t; - using std::lock_guard; - using std::mutex; - using std::size_t; - using std::uint32_t; - using std::uint64_t; - extern "C" { #include "crypto-ops.h" #include "random.h" } - mutex random_lock; + std::mutex& random_lock_accessor() noexcept + { + // this is a thread-safe approach + // note section 6.7: "If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization." + static std::mutex random_lock; + return random_lock; + } + static inline unsigned char *operator &(ec_point &point) { return &reinterpret_cast(point); @@ -78,9 +66,10 @@ namespace crypto { return &reinterpret_cast(scalar); } - static inline void random_scalar(ec_scalar &res) { + static inline void random_scalar_no_lock(ec_scalar &res) + { unsigned char tmp[64]; - generate_random_bytes(64, tmp); + generate_random_bytes_no_lock(64, tmp); sc_reduce(tmp); memcpy(&res, tmp, 32); } @@ -118,10 +107,11 @@ namespace crypto { sc_reduce32(&res); } - void crypto_ops::generate_keys(public_key &pub, secret_key &sec) { - lock_guard lock(random_lock); + void crypto_ops::generate_keys(public_key &pub, secret_key &sec) + { + std::lock_guard lock(random_lock_accessor()); ge_p3 point; - random_scalar(sec); + random_scalar_no_lock(sec); ge_scalarmult_base(&point, &sec); ge_p3_tobytes(&pub, &point); } @@ -239,7 +229,7 @@ namespace crypto { }; void crypto_ops::generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) { - lock_guard lock(random_lock); + std::lock_guard lock(random_lock_accessor()); ge_p3 tmp3; ec_scalar k; s_comm buf; @@ -255,7 +245,7 @@ namespace crypto { #endif buf.h = prefix_hash; buf.key = pub; - random_scalar(k); + random_scalar_no_lock(k); ge_scalarmult_base(&tmp3, &k); ge_p3_tobytes(&buf.comm, &tmp3); hash_to_scalar(&buf, sizeof(s_comm), sig.c); @@ -325,7 +315,7 @@ POP_VS_WARNINGS const public_key *const *pubs, size_t pubs_count, const secret_key &sec, size_t sec_index, signature *sig) { - lock_guard lock(random_lock); + std::lock_guard lock(random_lock_accessor()); size_t i; ge_p3 image_unp; ge_dsmp image_pre; @@ -362,15 +352,15 @@ POP_VS_WARNINGS ge_p2 tmp2; ge_p3 tmp3; if (i == sec_index) { - random_scalar(k); + random_scalar_no_lock(k); ge_scalarmult_base(&tmp3, &k); ge_p3_tobytes(&buf->ab[i].a, &tmp3); hash_to_ec(*pubs[i], tmp3); ge_scalarmult(&tmp2, &k, &tmp3); ge_tobytes(&buf->ab[i].b, &tmp2); } else { - random_scalar(sig[i].c); - random_scalar(sig[i].r); + random_scalar_no_lock(sig[i].c); + random_scalar_no_lock(sig[i].r); if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) { abort(); } diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 08cf26d5..9433ad4f 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -31,7 +31,7 @@ namespace crypto { #include "random.h" } - extern std::mutex random_lock; + std::mutex& random_lock_accessor() noexcept; #pragma pack(push, 1) POD_CLASS ec_point { @@ -114,17 +114,27 @@ namespace crypto { }; + // thread-safe version + inline void generate_random_bytes(size_t size, void* p_data) + { + std::lock_guard lock(random_lock_accessor()); + generate_random_bytes_no_lock(size, p_data); + } + + /* Generate a value filled with random bytes. */ template - typename std::enable_if::value, T>::type rand() { + typename std::enable_if::value, T>::type rand() + { typename std::remove_cv::type res; - std::lock_guard lock(random_lock); - generate_random_bytes(sizeof(T), &res); + std::lock_guard lock(random_lock_accessor()); + generate_random_bytes_no_lock(sizeof(T), &res); return res; } /* An adapter, to be used with std::shuffle, etc. + * Uses thread-safe crypto::rand<>(). */ struct uniform_random_bit_generator { diff --git a/src/crypto/random.c b/src/crypto/random.c index a54bdf74..e38fb18d 100644 --- a/src/crypto/random.c +++ b/src/crypto/random.c @@ -1,3 +1,4 @@ +// Copyright (c) 2018-2025 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. @@ -7,7 +8,6 @@ #include #include "hash-ops.h" -//#include "initializer.h" #include "random.h" static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE"); @@ -17,7 +17,7 @@ static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE"); #include #include -void generate_system_random_bytes(size_t n, void *result) { +void generate_system_random_bytes_no_lock(size_t n, void *result) { HCRYPTPROV prov; #define must_succeed(x) do if (!(x)) assert(0); while (0) if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) @@ -40,7 +40,7 @@ void generate_system_random_bytes(size_t n, void *result) { #include #include -void generate_system_random_bytes(size_t n, void *result) { +void generate_system_random_bytes_no_lock(size_t n, void *result) { int fd; if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) { exit(EXIT_FAILURE); @@ -70,6 +70,8 @@ void generate_system_random_bytes(size_t n, void *result) { static union hash_state state; +static_assert(sizeof(union hash_state) == RANDOM_STATE_SIZE, "RANDOM_STATE_SIZE and hash_state size missmatch"); + #if !defined(NDEBUG) static volatile int curstate; /* To catch thread safety problems. */ #endif @@ -86,7 +88,7 @@ FINALIZER(deinit_random) { //INITIALIZER(init_random) { void init_random(void) { - generate_system_random_bytes(32, &state); + generate_system_random_bytes_no_lock(RANDOM_STATE_SIZE, &state); //REGISTER_FINA\LIZER(deinit_random); #if !defined(NDEBUG) assert(curstate == 0); @@ -95,7 +97,7 @@ void init_random(void) } -void grant_random_initialize(void) +void grant_random_initialize_no_lock(void) { static bool initalized = false; if(!initalized) @@ -105,9 +107,9 @@ void grant_random_initialize(void) } } -void random_prng_initialize_with_seed(uint64_t seed) +void random_prng_initialize_with_seed_no_lock(uint64_t seed) { - grant_random_initialize(); + grant_random_initialize_no_lock(); #if !defined(NDEBUG) assert(curstate == 1); curstate = 3; @@ -122,9 +124,9 @@ void random_prng_initialize_with_seed(uint64_t seed) #endif } -void random_prng_get_state(void *state_buffer, const size_t buffer_size) +void random_prng_get_state_no_lock(void *state_buffer, const size_t buffer_size) { - grant_random_initialize(); + grant_random_initialize_no_lock(); #if !defined(NDEBUG) assert(curstate == 1); curstate = 4; @@ -139,9 +141,9 @@ void random_prng_get_state(void *state_buffer, const size_t buffer_size) #endif } -void random_prng_set_state(const void *state_buffer, const size_t buffer_size) +void random_prng_set_state_no_lock(const void *state_buffer, const size_t buffer_size) { - grant_random_initialize(); + grant_random_initialize_no_lock(); #if !defined(NDEBUG) assert(curstate == 1); curstate = 5; @@ -156,8 +158,9 @@ void random_prng_set_state(const void *state_buffer, const size_t buffer_size) #endif } -void generate_random_bytes(size_t n, void *result) { - grant_random_initialize(); +void generate_random_bytes_no_lock(size_t n, void *result) +{ + grant_random_initialize_no_lock(); #if !defined(NDEBUG) assert(curstate == 1); curstate = 2; diff --git a/src/crypto/random.h b/src/crypto/random.h index dbc79302..7db79b8b 100644 --- a/src/crypto/random.h +++ b/src/crypto/random.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Zano Project +// Copyright (c) 2018-2025 Zano Project // Copyright (c) 2014-2018 The Boolberry developers // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -9,13 +9,8 @@ #include #include -// use the cryptographically secure Pseudo-Random Number Generator provided by the operating system -void generate_system_random_bytes(size_t n, void *result); - -void generate_random_bytes(size_t n, void *result); - -// checks if PRNG is initialized and initializes it if necessary -void grant_random_initialize(void); +// NOT thread-safe, use with caution +void generate_random_bytes_no_lock(size_t n, void *result); #define RANDOM_STATE_SIZE 200 @@ -24,14 +19,14 @@ void grant_random_initialize(void); // reinitializes PRNG with the given seed // !!!ATTENTION!!!! Improper use of this routine may lead to SECURITY BREACH! // Use with care and ONLY for tests or debug purposes! -void random_prng_initialize_with_seed(uint64_t seed); +void random_prng_initialize_with_seed_no_lock(uint64_t seed); // gets internal RPNG state (state_buffer should be 200 bytes long) -void random_prng_get_state(void *state_buffer, const size_t buffer_size); +void random_prng_get_state_no_lock(void *state_buffer, const size_t buffer_size); // sets internal RPNG state (state_buffer should be 200 bytes long) // !!!ATTENTION!!!! Improper use of this routine may lead to SECURITY BREACH! // Use with care and ONLY for tests or debug purposes! -void random_prng_set_state(const void *state_buffer, const size_t buffer_size); +void random_prng_set_state_no_lock(const void *state_buffer, const size_t buffer_size); #endif // #ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES diff --git a/tests/core_tests/random_helper.h b/tests/core_tests/random_helper.h index 61d49f80..f548e324 100644 --- a/tests/core_tests/random_helper.h +++ b/tests/core_tests/random_helper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,15 +16,15 @@ struct random_state_test_restorer { random_state_test_restorer() { - crypto::random_prng_get_state(&m_state, sizeof m_state); + crypto::random_prng_get_state_no_lock(&m_state, sizeof m_state); } ~random_state_test_restorer() { - crypto::random_prng_set_state(&m_state, sizeof m_state); + crypto::random_prng_set_state_no_lock(&m_state, sizeof m_state); } static void reset_random(uint64_t seed = 0) { - crypto::random_prng_initialize_with_seed(seed); + crypto::random_prng_initialize_with_seed_no_lock(seed); } private: uint8_t m_state[RANDOM_STATE_SIZE]; diff --git a/tests/unit_tests/db_accessors.cpp b/tests/unit_tests/db_accessors.cpp index 4994d1fb..a549e776 100644 --- a/tests/unit_tests/db_accessors.cpp +++ b/tests/unit_tests/db_accessors.cpp @@ -317,7 +317,7 @@ struct bcs_stub_t TEST(db_accessor_tests, median_db_cache_test) { - crypto::random_prng_initialize_with_seed(0); // make this test deterministic (the same crypto::rand() sequence) + crypto::random_prng_initialize_with_seed_no_lock(0); // make this test deterministic (the same crypto::rand() sequence) epee::shared_recursive_mutex m_rw_lock; tools::db::basic_db_accessor m_db(std::shared_ptr(new tools::db::lmdb_db_backend), m_rw_lock); diff --git a/tests/unit_tests/db_tests.cpp b/tests/unit_tests/db_tests.cpp index 61a0ae19..4eb7a2d5 100644 --- a/tests/unit_tests/db_tests.cpp +++ b/tests/unit_tests/db_tests.cpp @@ -362,8 +362,8 @@ namespace db_test void multithread_test_1() { char prng_state[200] = {}; - crypto::random_prng_get_state(prng_state, sizeof prng_state); // store current RPNG state - crypto::random_prng_initialize_with_seed(0); // this mades this test deterministic + crypto::random_prng_get_state_no_lock(prng_state, sizeof prng_state); // store current RPNG state + crypto::random_prng_initialize_with_seed_no_lock(0); // this mades this test deterministic bool result = false; try @@ -377,7 +377,7 @@ namespace db_test } // restore PRNG state to keep other tests unaffected - crypto::random_prng_set_state(prng_state, sizeof prng_state); + crypto::random_prng_set_state_no_lock(prng_state, sizeof prng_state); ASSERT_TRUE(result); } From cc8ff1d5a355f7cb9036a9c35b5107c8326d013d Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 1 Aug 2025 04:26:08 +0300 Subject: [PATCH 60/65] minor fix (presumable, not worthy but anyway) --- tests/crypto/crypto.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/crypto/crypto.cpp b/tests/crypto/crypto.cpp index cbc5879c..381960a5 100644 --- a/tests/crypto/crypto.cpp +++ b/tests/crypto/crypto.cpp @@ -11,7 +11,7 @@ bool check_scalar(const crypto::ec_scalar &scalar) { } void random_scalar(crypto::ec_scalar &res) { - crypto::random_scalar(res); + crypto::random_scalar_no_lock(res); } void hash_to_scalar(const void *data, std::size_t length, crypto::ec_scalar &res) { From b9b175c00f789c72d5441e5098d932dbe1eb44df Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 7 Aug 2025 11:34:25 +0300 Subject: [PATCH 61/65] ui update (PR 157) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 69df3c6d..0a7bf9b4 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 69df3c6d86e230dd406097676afa0d0b8c1d9231 +Subproject commit 0a7bf9b4d5710e4d112173a9e87117206ac037eb From 11d4bbf1da658b85752173cccd9e92997c985681 Mon Sep 17 00:00:00 2001 From: sowle Date: Sun, 10 Aug 2025 05:24:25 +0300 Subject: [PATCH 62/65] crypto: generate_system_random_bytes_* refactored: improved error handling, win32 version moved to BCrypt API, split into normal and _or_die funcs Thanks to @gitToki for spotting the error handling issue! --- src/CMakeLists.txt | 8 +++- src/crypto/random.c | 94 ++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27739818..e6bdcea2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,13 +115,17 @@ else() set_source_files_properties("crypto/chacha8_stream.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-strict-prototypes") endif() +if(WIN32) + set(BCRYPT_LIB bcrypt) +endif() + add_library(crypto ${CRYPTO}) if(USE_BITCOIN_SECP256K1_FOR_ECDSA) add_dependencies(crypto secp256k1) - target_link_libraries(crypto secp256k1) + target_link_libraries(crypto secp256k1 ${BCRYPT_LIB}) else() add_dependencies(crypto OpenSSL::Crypto) - target_link_libraries(crypto OpenSSL::Crypto) + target_link_libraries(crypto OpenSSL::Crypto ${BCRYPT_LIB}) endif() add_library(currency_core ${CURRENCY_CORE}) diff --git a/src/crypto/random.c b/src/crypto/random.c index e38fb18d..f204c163 100644 --- a/src/crypto/random.c +++ b/src/crypto/random.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "hash-ops.h" #include "random.h" @@ -15,19 +17,29 @@ static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE"); #if defined(_WIN32) #include -#include +#include -void generate_system_random_bytes_no_lock(size_t n, void *result) { - HCRYPTPROV prov; -#define must_succeed(x) do if (!(x)) assert(0); while (0) - if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) +// thread-safe version +bool generate_system_random_bytes(size_t n, void *result) +{ + if (n == 0) + return true; + + if (result == NULL) + return false; + + NTSTATUS status = BCryptGenRandom(NULL, (PUCHAR)result, (ULONG)n, BCRYPT_USE_SYSTEM_PREFERRED_RNG); + return BCRYPT_SUCCESS(status); +} + +void generate_system_random_bytes_or_die(size_t n, void *result) +{ + if (!generate_system_random_bytes(n, result)) { - int err = GetLastError(); - assert(0); + fprintf(stderr, "Error: generate_system_random_bytes failed and this is fatal\n\n"); + fflush(stderr); + _exit(EXIT_FAILURE); } - must_succeed(CryptGenRandom(prov, (DWORD)n, result)); - must_succeed(CryptReleaseContext(prov, 0)); -#undef must_succeed } #else @@ -40,28 +52,49 @@ void generate_system_random_bytes_no_lock(size_t n, void *result) { #include #include -void generate_system_random_bytes_no_lock(size_t n, void *result) { +bool generate_system_random_bytes(size_t n, void *result) +{ int fd; - if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) { - exit(EXIT_FAILURE); - } - for (;;) { - ssize_t res = read(fd, result, n); - if ((size_t) res == n) { - break; - } - if (res < 0) { - if (errno != EINTR) { - exit(EXIT_FAILURE); + + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd < 0) + return false; + + size_t bytes_read = 0; + while (bytes_read < n) + { + ssize_t res = read(fd, (char*)result + bytes_read, n - bytes_read); + if (res < 0) + { + if (errno != EINTR) + { + close(fd); + return false; } - } else if (res == 0) { - exit(EXIT_FAILURE); - } else { - result = padd(result, (size_t) res); - n -= (size_t) res; + // EINTR - interrupted by signal, continue reading + } + else if (res == 0) + { + // EOF - should not happen with /dev/urandom + close(fd); + return false; + } + else + { + bytes_read += res; } } - if (close(fd) < 0) { + + close(fd); // don't check, 'cuz failing to close /dev/urandom is not truly fatal, the OS will clean up + return true; +} + +void generate_system_random_bytes_or_die(size_t n, void *result) +{ + if (!generate_system_random_bytes(n, result)) + { + fprintf(stderr, "FATAL: Failed to generate %zu random bytes: %s\n\n", n, strerror(errno)); + fflush(stderr); exit(EXIT_FAILURE); } } @@ -85,11 +118,10 @@ FINALIZER(deinit_random) { } */ -//INITIALIZER(init_random) { void init_random(void) { - generate_system_random_bytes_no_lock(RANDOM_STATE_SIZE, &state); - //REGISTER_FINA\LIZER(deinit_random); + generate_system_random_bytes_or_die(HASH_DATA_AREA, &state); + #if !defined(NDEBUG) assert(curstate == 0); curstate = 1; From d7d0ba0a416ef7a7862971c48a7fa1fcf0eddd30 Mon Sep 17 00:00:00 2001 From: zano build machine Date: Mon, 11 Aug 2025 00:17:35 +0300 Subject: [PATCH 63/65] === build number: 425 -> 426 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index d3bd4ae1..bb847f03 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 425 +#define PROJECT_VERSION_BUILD_NO 426 #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 "]" From 91ced14b2d94bd19db7722d282dc54f90bade5a9 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 12 Aug 2025 19:50:17 +0300 Subject: [PATCH 64/65] ui update (PR 158) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 0a7bf9b4..bcd40213 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 0a7bf9b4d5710e4d112173a9e87117206ac037eb +Subproject commit bcd4021364bbcd29a4208225de33a359ee35a447 From de5e0caebda8eab57841ea93e2197cf7b9303d86 Mon Sep 17 00:00:00 2001 From: zano build machine Date: Tue, 12 Aug 2025 19:51:10 +0300 Subject: [PATCH 65/65] === build number: 426 -> 427 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index bb847f03..7da710ba 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "8" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 426 +#define PROJECT_VERSION_BUILD_NO 427 #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 "]"