From 8f25f0d460d697214b48f0d62e90998ea4c49df9 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 26 Jun 2024 21:15:44 +0200 Subject: [PATCH 001/239] bitcoin-secp256k1 submodule added + native crypto test --- .gitmodules | 3 ++ contrib/CMakeLists.txt | 11 +++++ src/CMakeLists.txt | 2 + tests/functional_tests/crypto_tests.cpp | 60 +++++++++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/.gitmodules b/.gitmodules index 97a855bd..57896bbb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,6 @@ [submodule "contrib/jwt-cpp"] path = contrib/jwt-cpp url = https://github.com/Thalhammer/jwt-cpp.git +[submodule "contrib/bitcoin-secp256k1"] + path = contrib/bitcoin-secp256k1 + url = https://github.com/bitcoin-core/secp256k1.git diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index abfc4885..c1a5535f 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -5,6 +5,14 @@ add_subdirectory(zlib) add_subdirectory(db) add_subdirectory(ethereum) +option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." OFF) +option(SECP256K1_BUILD_TESTS "Build tests." OFF) +option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." OFF) +option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." OFF) +option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) +set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1) +add_subdirectory(bitcoin-secp256k1) + if( NOT DISABLE_TOR) add_subdirectory(tor-connect) endif() @@ -23,6 +31,9 @@ set_property(TARGET libminiupnpc-static PROPERTY FOLDER "contrib") set_property(TARGET zlibstatic PROPERTY FOLDER "contrib") set_property(TARGET mdbx PROPERTY FOLDER "contrib") set_property(TARGET lmdb PROPERTY FOLDER "contrib") +set_property(TARGET secp256k1 PROPERTY FOLDER "contrib") +set_property(TARGET secp256k1_precomputed PROPERTY FOLDER "contrib") + if( NOT DISABLE_TOR) set_property(TARGET tor-connect PROPERTY FOLDER "contrib") endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 200096f3..563b4266 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,8 @@ else() endif() add_library(crypto ${CRYPTO}) +add_dependencies(crypto secp256k1) +target_link_libraries(crypto secp256k1) add_library(currency_core ${CURRENCY_CORE}) add_dependencies(currency_core version ${PCH_LIB_NAME}) diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 546fff99..6cd876b5 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -1896,6 +1896,66 @@ TEST(crypto, generators_precomp) #undef CHECK_PRECOMP } +#include "bitcoin-secp256k1/include/secp256k1.h" +TEST(crypto, secp256k1_ecdsa_native) +{ + bool r = false; + + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + uint8_t randomness[32]; + crypto::generate_random_bytes(sizeof randomness, randomness); + secp256k1_context_randomize(ctx, randomness); + + uint8_t seckey[32] = {}; + while(true) + { + crypto::generate_random_bytes(sizeof seckey, seckey); + if (secp256k1_ec_seckey_verify(ctx, seckey)) + break; + } + + secp256k1_pubkey pubkey{}; + ASSERT_TRUE(secp256k1_ec_pubkey_create(ctx, &pubkey, seckey)); + + uint8_t compressed_pubkey[33] = {}; + size_t output_len = sizeof compressed_pubkey; + ASSERT_TRUE(secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &output_len, &pubkey, SECP256K1_EC_COMPRESSED)); + ASSERT_TRUE(output_len == sizeof compressed_pubkey); + + + secp256k1_ecdsa_signature secp256k1_ecdsa_sig{}; + hash msg_hash = hash_helper_t::h("message"); + ASSERT_TRUE(secp256k1_ecdsa_sign(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, seckey, NULL, NULL)); + + // Serialize the signature in a compact form. + unsigned char secp256k1_ecdsa_sig_serialized[64] = {}; + ASSERT_TRUE(secp256k1_ecdsa_signature_serialize_compact(ctx, secp256k1_ecdsa_sig_serialized, &secp256k1_ecdsa_sig)); + + // + // Verification + // + + secp256k1_ecdsa_sig = secp256k1_ecdsa_signature{}; + pubkey = secp256k1_pubkey{}; + + // Deserialize the signature. + ASSERT_TRUE(secp256k1_ecdsa_signature_parse_compact(ctx, &secp256k1_ecdsa_sig, secp256k1_ecdsa_sig_serialized)); + + // Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */ + ASSERT_TRUE(secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))); + + // verify a signature + ASSERT_TRUE(secp256k1_ecdsa_verify(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, &pubkey)); + + // verify using a static context + ASSERT_TRUE(secp256k1_ecdsa_verify(secp256k1_context_static, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, &pubkey)); + + + // Epilogue + secp256k1_context_destroy(ctx); + return true; +} + // From 3b6fa728b7fd392bf878b824468567a7a9fd68cf Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 1 Jul 2024 14:14:00 +0200 Subject: [PATCH 002/239] added bitcoin-secp256k1 submodule at version 5.0 --- contrib/bitcoin-secp256k1 | 1 + 1 file changed, 1 insertion(+) create mode 160000 contrib/bitcoin-secp256k1 diff --git a/contrib/bitcoin-secp256k1 b/contrib/bitcoin-secp256k1 new file mode 160000 index 00000000..e3a885d4 --- /dev/null +++ b/contrib/bitcoin-secp256k1 @@ -0,0 +1 @@ +Subproject commit e3a885d42a7800c1ccebad94ad1e2b82c4df5c65 From 486fb05f73dbdf13fa3c86e34a80f01cca36c78a Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 1 Jul 2024 21:35:27 +0200 Subject: [PATCH 003/239] updated submodule bitcoin-secp256k1 in attempt to fix gcc compilation issue --- contrib/bitcoin-secp256k1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/bitcoin-secp256k1 b/contrib/bitcoin-secp256k1 index e3a885d4..a5269373 160000 --- a/contrib/bitcoin-secp256k1 +++ b/contrib/bitcoin-secp256k1 @@ -1 +1 @@ -Subproject commit e3a885d42a7800c1ccebad94ad1e2b82c4df5c65 +Subproject commit a5269373fa13ff845f654d81b90629dd78495641 From f05d14a944df040cb3d8e944009aa8700f66f80e Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 2 Jul 2024 13:15:48 +0200 Subject: [PATCH 004/239] crypto: basic eth signature implementation + functional test --- src/crypto/eth_signature.cpp | 125 ++++++++++++++++++++++++ src/crypto/eth_signature.h | 39 ++++++++ tests/functional_tests/crypto_tests.cpp | 27 +++++ 3 files changed, 191 insertions(+) create mode 100644 src/crypto/eth_signature.cpp create mode 100644 src/crypto/eth_signature.h diff --git a/src/crypto/eth_signature.cpp b/src/crypto/eth_signature.cpp new file mode 100644 index 00000000..3aaec568 --- /dev/null +++ b/src/crypto/eth_signature.cpp @@ -0,0 +1,125 @@ +// Copyright (c) 2024 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "eth_signature.h" +#include "crypto.h" +#include "bitcoin-secp256k1/include/secp256k1.h" +#include "random.h" +#include "misc_language.h" + + +namespace crypto +{ + bool generate_eth_key_pair(eth_secret_key& sec_key, eth_public_key& pub_key) noexcept + { + try + { + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){ + secp256k1_context_destroy(ctx); + ctx = nullptr; + }); + + uint8_t randomness[32]; + crypto::generate_random_bytes(sizeof randomness, randomness); + if (!secp256k1_context_randomize(ctx, randomness)) + return false; + + for(size_t i = 1024; i != 0; --i) + { + crypto::generate_random_bytes(sizeof sec_key, sec_key.data); + if (secp256k1_ec_seckey_verify(ctx, sec_key.data)) + break; + if (i == 1) + return false; + } + + secp256k1_pubkey uncompressed_pub_key{}; + if (!secp256k1_ec_pubkey_create(ctx, &uncompressed_pub_key, sec_key.data)) + return false; + + size_t output_len = sizeof pub_key; + if (!secp256k1_ec_pubkey_serialize(ctx, pub_key.data, &output_len, &uncompressed_pub_key, SECP256K1_EC_COMPRESSED)) + return false; + + return true; + } + catch(...) + { + return false; + } + } + + + // generates secp256k1 ECDSA signature + bool generate_eth_signature(const hash& m, const eth_secret_key& sec_key, eth_signature& sig) noexcept + { + try + { + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){ + secp256k1_context_destroy(ctx); + ctx = nullptr; + }); + + uint8_t randomness[32]; + crypto::generate_random_bytes(sizeof randomness, randomness); + if (!secp256k1_context_randomize(ctx, randomness)) + return false; + + secp256k1_ecdsa_signature secp256k1_ecdsa_sig{}; + if (!secp256k1_ecdsa_sign(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)m.data, sec_key.data, NULL, NULL)) + return false; + + if (!secp256k1_ecdsa_signature_serialize_compact(ctx, sig.data, &secp256k1_ecdsa_sig)) + return false; + + return true; + } + catch(...) + { + return false; + } + } + + // verifies secp256k1 ECDSA signature + bool verify_eth_signature(const hash& m, const eth_public_key& pub_key, const eth_signature& sig) noexcept + { + try + { + // TODO (performance) consider using secp256k1_context_static for verification -- sowle + + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){ + secp256k1_context_destroy(ctx); + ctx = nullptr; + }); + + uint8_t randomness[32]; + crypto::generate_random_bytes(sizeof randomness, randomness); + if (!secp256k1_context_randomize(ctx, randomness)) + return false; + + secp256k1_ecdsa_signature secp256k1_ecdsa_sig{}; + secp256k1_pubkey uncompressed_pub_key{}; + + if (!secp256k1_ecdsa_signature_parse_compact(ctx, &secp256k1_ecdsa_sig, sig.data)) + return false; + + if (!secp256k1_ec_pubkey_parse(ctx, &uncompressed_pub_key, pub_key.data, sizeof pub_key)) + return false; + + // verify a signature + if (!secp256k1_ecdsa_verify(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)m.data, &uncompressed_pub_key)) + return false; + + return true; + } + catch(...) + { + return false; + } + } + + +} // namespace crypto diff --git a/src/crypto/eth_signature.h b/src/crypto/eth_signature.h new file mode 100644 index 00000000..c0434525 --- /dev/null +++ b/src/crypto/eth_signature.h @@ -0,0 +1,39 @@ +// Copyright (c) 2024 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once +#include +#include "hash.h" + +namespace crypto +{ + + // secp256k1 public key in serialized (compressed) form that is used in Etherium + struct eth_public_key + { + uint8_t data[33]; + }; + + // secp256k1 secret key + struct eth_secret_key + { + uint8_t data[32]; + }; + + // secp256k1 ECDSA signature is serialized (compressed) form that is used in Etherium + struct eth_signature + { + uint8_t data[64]; + }; + + // generates secp256k1 keypair + bool generate_eth_key_pair(eth_secret_key& sec_key, eth_public_key& pub_key) noexcept; + + // generates secp256k1 ECDSA signature + bool generate_eth_signature(const hash& m, const eth_secret_key& sec_key, eth_signature& sig) noexcept; + + // verifies secp256k1 ECDSA signature + bool verify_eth_signature(const hash& m, const eth_public_key& pub_key, const eth_signature& sig) noexcept; + + +} // namespace crypto diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 6cd876b5..a6907bef 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -1957,6 +1957,33 @@ TEST(crypto, secp256k1_ecdsa_native) } +TEST(crypto, eth_signature_basics) +{ + eth_secret_key sk{}; + eth_public_key pk{}; + + ASSERT_TRUE(generate_eth_key_pair(sk, pk)); + + eth_signature sig{}; + hash m = hash_helper_t::h("How many of you have ever felt personally victimized by elliptic curves?"); + + ASSERT_TRUE(generate_eth_signature(m, sk, sig)); + + const eth_signature const_sig = sig; + ASSERT_TRUE(verify_eth_signature(m, pk, const_sig)); + + for(size_t i = 0; i < sizeof sig; ++i) + { + eth_signature bad_sig = sig; + bad_sig.data[i] ^= 1 + (rand() % 254); // xor with a number fom [1; 255] to make sure this byte will change + ASSERT_FALSE(verify_eth_signature(m, pk, bad_sig)); + } + + return true; +} + + + // // test's runner From d7cf27033c6f4cd8e218771b1a9d8bc2c2aa4777 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 2 Jul 2024 13:16:30 +0200 Subject: [PATCH 005/239] forgotten include --- tests/functional_tests/crypto_tests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index a6907bef..d4217d47 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -20,6 +20,7 @@ #include "crypto/range_proofs.h" #include "../core_tests/random_helper.h" #include "crypto_torsion_elements.h" +#include "crypto/eth_signature.h" using namespace crypto; From e17ede1649fdcbdc99b8fde3cebc376eac6b9695 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 11 Jul 2024 22:04:42 +0200 Subject: [PATCH 006/239] rpc: set_ignore_connectivity_status() was ignored for some RPC, fixed --- src/rpc/core_rpc_server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 371d0a81..ee76e1ac 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -575,7 +575,7 @@ namespace currency //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_pos_mining_details(const COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, COMMAND_RPC_GET_POS_MINING_DETAILS::response& res, connection_context& cntx) { - if (!m_p2p.get_connections_count()) + if (!m_ignore_status && !m_p2p.get_connections_count()) { res.status = API_RETURN_CODE_DISCONNECTED; return true; @@ -793,7 +793,7 @@ namespace currency return true; } - if (!m_p2p.get_payload_object().get_synchronized_connections_count()) + if (!m_ignore_status && !m_p2p.get_payload_object().get_synchronized_connections_count()) { LOG_PRINT_L0("[on_send_raw_tx]: Failed to send, daemon not connected to net"); res.status = API_RETURN_CODE_DISCONNECTED; From 2582159a26948af286ab919dec157197d813fed4 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 11 Jul 2024 22:09:55 +0200 Subject: [PATCH 007/239] coretests: added ability to run "true" HTTP-RPC wallet tests via localhost connections --- tests/core_tests/wallet_tests_basic.cpp | 5 +++ tests/core_tests/wallet_tests_basic.h | 60 +++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/tests/core_tests/wallet_tests_basic.cpp b/tests/core_tests/wallet_tests_basic.cpp index 43707ac8..87066e8b 100644 --- a/tests/core_tests/wallet_tests_basic.cpp +++ b/tests/core_tests/wallet_tests_basic.cpp @@ -99,3 +99,8 @@ std::shared_ptr wallet_test::init_playtime_test_wallet(const std return init_playtime_test_wallet(events, c, m_accounts[account_index]); } +std::shared_ptr wallet_test::init_playtime_test_wallet_with_true_http_rpc(const std::vector& events, currency::core& c, size_t account_index) const +{ + CHECK_AND_ASSERT_THROW_MES(account_index < m_accounts.size(), "Invalid account index"); + return init_playtime_test_wallet_t(events, c, m_accounts[account_index], true); +} diff --git a/tests/core_tests/wallet_tests_basic.h b/tests/core_tests/wallet_tests_basic.h index bc45bcc8..72fa6fc5 100644 --- a/tests/core_tests/wallet_tests_basic.h +++ b/tests/core_tests/wallet_tests_basic.h @@ -1,10 +1,15 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2024 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. #pragma once #include "chaingen.h" +#include "currency_protocol/currency_protocol_handler.h" +#include "currency_core/currency_core.h" +#include "p2p/net_node.h" +#include "currency_core/bc_offers_service.h" +#include "rpc/core_rpc_server.h" struct wallet_test : virtual public test_chain_unit_enchanced { @@ -22,11 +27,30 @@ struct wallet_test : virtual public test_chain_unit_enchanced static std::string get_test_account_name_by_id(size_t acc_id); template - std::shared_ptr init_playtime_test_wallet_t(const std::vector& events, currency::core& c, const currency::account_base& acc) const + std::shared_ptr init_playtime_test_wallet_t(const std::vector& events, currency::core& c, const currency::account_base& acc, bool true_http_rpc = false) const { CHECK_AND_ASSERT_THROW_MES(events.size() > 0 && events[0].type() == typeid(currency::block), "Invalid events queue, can't find genesis block at the beginning"); crypto::hash genesis_hash = get_block_hash(boost::get(events[0])); + if (true_http_rpc) + { + m_core_proxy = std::make_shared(); + m_core_proxy->set_connectivity(100, 1); + CHECK_AND_ASSERT_MES(m_core_proxy->set_connection_addr("127.0.0.1:33777"), false, ""); + if (!m_core_proxy->check_connection()) + { + // if there's not http rpc core server yet, create one + boost::program_options::options_description desc_options; + currency::core_rpc_server::init_options(desc_options); + boost::program_options::variables_map vm{}; + char* argv[] = {"--rpc-bind-ip=127.0.0.1", "--rpc-bind-port=33777"}; + boost::program_options::store(boost::program_options::parse_command_line(sizeof argv / sizeof argv[0], argv, desc_options), vm); + m_http_rpc_server = std::make_shared(c, vm); + } + m_core_proxy->set_connectivity(30000, 1); + CHECK_AND_ASSERT_MES(m_core_proxy->check_connection(), false, "no connection"); + } + std::shared_ptr w(new wallet_t); w->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config()); w->assign_account(acc); @@ -64,12 +88,42 @@ protected: size_t account_index; }; + struct core_http_rpc_server_details + { + currency::t_currency_protocol_handler cph; + nodetool::node_server > p2p; + bc_services::bc_offers_service bos; + currency::core_rpc_server core_rpc_server; + + core_http_rpc_server_details(currency::core& c, const boost::program_options::variables_map& vm) + : cph(c, nullptr) + , p2p(cph) + , bos(nullptr) + , core_rpc_server(c, p2p, bos) + { + bos.set_disabled(true); + core_rpc_server.set_ignore_connectivity_status(true); + + bool r = core_rpc_server.init(vm); + CRYPTO_CHECK_AND_THROW_MES(r, "core_http_rpc_server_details: rpc server init failed"); + r = core_rpc_server.run(2, false); + CRYPTO_CHECK_AND_THROW_MES(r, "core_http_rpc_server_details: rpc server run failed"); + } + + ~core_http_rpc_server_details() + { + core_rpc_server.deinit(); + } + }; + std::shared_ptr init_playtime_test_wallet(const std::vector& events, currency::core& c, size_t account_index) const; std::shared_ptr init_playtime_test_wallet(const std::vector& events, currency::core& c, const currency::account_base& acc) const; + std::shared_ptr wallet_test::init_playtime_test_wallet_with_true_http_rpc(const std::vector& events, currency::core& c, size_t account_index) const; mutable std::vector m_accounts; mutable test_generator generator; - std::shared_ptr m_core_proxy; + mutable std::shared_ptr m_core_proxy; + mutable std::shared_ptr m_http_rpc_server; // "True" RPC via http on localhost }; From 567700635cf8e171cb8a4207fc839c05e30d5aa6 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 11 Jul 2024 22:10:37 +0200 Subject: [PATCH 008/239] coretests: wallet_true_rpc_pos_mining test added --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/wallet_rpc_tests.cpp | 123 ++++++++++++++++++++++++++ tests/core_tests/wallet_rpc_tests.h | 6 ++ 3 files changed, 130 insertions(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 1edd2a5a..456c8603 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1102,6 +1102,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(wallet_rpc_transfer); GENERATE_AND_PLAY(wallet_rpc_alias_tests); GENERATE_AND_PLAY_HF(wallet_rpc_exchange_suite, "3,4"); + GENERATE_AND_PLAY_HF(wallet_true_rpc_pos_mining, "4-*"); 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 3fa4b2d7..47b6d21b 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -801,3 +801,126 @@ bool wallet_rpc_exchange_suite::c1(currency::core& c, size_t ev_index, const std return true; } + +//------------------------------------------------------------------------------ + +wallet_true_rpc_pos_mining::wallet_true_rpc_pos_mining() +{ + REGISTER_CALLBACK_METHOD(wallet_true_rpc_pos_mining, c1); +} + +bool wallet_true_rpc_pos_mining::generate(std::vector& events) const +{ + 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); + account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); + DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks + REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); + + DO_CALLBACK(events, "c1"); + + return true; +} + +#include + +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); + + /*currency::t_currency_protocol_handler m_cprotocol(c, nullptr); + nodetool::node_server > p2p(m_cprotocol); + bc_services::bc_offers_service bos(nullptr); + bos.set_disabled(true); + currency::core_rpc_server core_rpc_wrapper(c, p2p, bos); + core_rpc_wrapper.set_ignore_connectivity_status(true); + + boost::program_options::options_description desc_options; + currency::core_rpc_server::init_options(desc_options); + boost::program_options::variables_map vm{}; + char* argv[] = {"--rpc-bind-ip=127.0.0.1", "--rpc-bind-port=33777"}; + boost::program_options::store(boost::program_options::parse_command_line(sizeof argv / sizeof argv[0], argv, desc_options), vm); + r = core_rpc_wrapper.init(vm); + CHECK_AND_ASSERT_MES(r, false, "rpc server init failed"); + r = core_rpc_wrapper.run(1, false); + CHECK_AND_ASSERT_MES(r, 1, "rpc server run failed"); + auto slh = epee::misc_utils::create_scope_leave_handler([&](){ + core_rpc_wrapper.deinit(); + }); + + + auto http_core_proxy = std::shared_ptr(new tools::default_http_core_proxy()); + http_core_proxy->set_connectivity(5000, 1); + CHECK_AND_ASSERT_MES(http_core_proxy->set_connection_addr("127.0.0.1:33777"), false, ""); + CHECK_AND_ASSERT_MES(http_core_proxy->check_connection(), false, "no connection"); + + miner_wlt->set_core_proxy(http_core_proxy);*/ + + uint64_t top_height = c.get_top_block_height(); + + size_t blocks_fetched = 0; + miner_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, top_height); + + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, top_height); + + //uint64_t balance_unlocked = 1, balance_awaiting_in = 1, balance_awaiting_out = 1, balance_mined = 1; + //uint64_t miner_initial_balance = miner_wlt->balance(balance_unlocked, balance_awaiting_in, balance_awaiting_out, balance_mined); + //CHECK_AND_ASSERT_EQ(miner_initial_balance, PREMINE_AMOUNT + CURRENCY_BLOCK_REWARD * top_height); + uint64_t miner_amount = PREMINE_AMOUNT + CURRENCY_BLOCK_REWARD * top_height; + uint64_t expected_unlocked = miner_amount - (CURRENCY_MINED_MONEY_UNLOCK_WINDOW - 1) * COIN; + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt, "miner", miner_amount, INVALID_BALANCE_VAL, expected_unlocked, 0, 0), false, ""); + + CHECK_AND_ASSERT_MES(miner_wlt->try_mint_pos(), false, "try_mint_pos failed"); + + CHECK_AND_ASSERT_EQ(c.get_top_block_height(), top_height + 1); + + miner_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 1); + + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt, "miner", miner_amount + COIN), false, ""); + + uint64_t amount_to_alice = MK_TEST_COINS(500); + miner_wlt->transfer(amount_to_alice, m_accounts[ALICE_ACC_IDX].get_public_address()); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "enexpected pool txs count: " << c.get_pool_transactions_count()); + CHECK_AND_ASSERT_MES(miner_wlt->try_mint_pos(), false, "try_mint_pos failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "enexpected pool txs count: " << c.get_pool_transactions_count()); + + miner_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 1); + + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt, "miner", miner_amount + 2 * COIN - amount_to_alice - TESTS_DEFAULT_FEE), false, ""); + + // Alice + + //alice_wlt->refresh(blocks_fetched); + //CHECK_AND_ASSERT_EQ(blocks_fetched, 2); + + //CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", amount_to_alice, 0, 0, 0, 0), false, ""); + + //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_blocks_in_playtime failed"); + + //alice_wlt->refresh(blocks_fetched); + //CHECK_AND_ASSERT_EQ(blocks_fetched, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + // + //CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", amount_to_alice, 0, amount_to_alice, 0, 0), false, ""); + + //std::this_thread::yield(); + //std::this_thread::sleep_for( std::chrono::milliseconds(1) ); + //CHECK_AND_ASSERT_MES(alice_wlt->try_mint_pos(), false, "try_mint_pos failed"); + + //alice_wlt->refresh(blocks_fetched); + //CHECK_AND_ASSERT_EQ(blocks_fetched, 1); + + //CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", amount_to_alice + CURRENCY_BLOCK_REWARD, 0, 0, 0, 0), false, ""); + + return true; +} diff --git a/tests/core_tests/wallet_rpc_tests.h b/tests/core_tests/wallet_rpc_tests.h index 0d939778..3793ad78 100644 --- a/tests/core_tests/wallet_rpc_tests.h +++ b/tests/core_tests/wallet_rpc_tests.h @@ -49,3 +49,9 @@ struct wallet_rpc_exchange_suite : public wallet_test bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; +struct wallet_true_rpc_pos_mining : public wallet_test +{ + wallet_true_rpc_pos_mining(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; From b556f2ad866d9bb17c6a4c781ec8170a8b240023 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 11 Jul 2024 22:10:54 +0200 Subject: [PATCH 009/239] minor improvements --- src/currency_protocol/currency_protocol_handler.inl | 1 + src/wallet/wallet2.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index 9f4c22de..e6d75eb2 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -7,6 +7,7 @@ #include #include "currency_core/currency_format_utils.h" #include "profile_tools.h" +#include namespace currency { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index d56be799..891d76c4 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5052,7 +5052,7 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco WLT_LOG_GREEN("Note: " << udtx.vin.size() << " inputs were aggregated into UTXO defragmentation tx " << get_transaction_hash(udtx), LOG_LEVEL_0); } m_core_proxy->call_COMMAND_RPC_GETBLOCKTEMPLATE(tmpl_req, tmpl_rsp); - WLT_CHECK_AND_ASSERT_MES(tmpl_rsp.status == API_RETURN_CODE_OK, false, "Failed to create block template after kernel hash found!"); + WLT_CHECK_AND_ASSERT_MES(tmpl_rsp.status == API_RETURN_CODE_OK, false, "Failed to create block template after kernel hash found! Status: " << tmpl_rsp.status); currency::block b = AUTO_VAL_INIT(b); currency::blobdata block_blob; From 7d442b4c9a51802cad8bb6175d708b01cad60645 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 12 Jul 2024 02:17:54 +0200 Subject: [PATCH 010/239] coretests: gen_wallet_mine_pos_block adapted for HF4 --- tests/core_tests/chaingen_main.cpp | 2 +- tests/core_tests/wallet_tests.cpp | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 456c8603..51e02734 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1070,7 +1070,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_wallet_refreshing_on_chain_switch_2); GENERATE_AND_PLAY(gen_wallet_unconfirmed_tx_from_tx_pool); GENERATE_AND_PLAY_HF(gen_wallet_save_load_and_balance, "*"); - GENERATE_AND_PLAY_HF(gen_wallet_mine_pos_block, "3"); + GENERATE_AND_PLAY_HF(gen_wallet_mine_pos_block, "3-*"); GENERATE_AND_PLAY(gen_wallet_unconfirmed_outdated_tx); GENERATE_AND_PLAY(gen_wallet_unlock_by_block_and_by_time); GENERATE_AND_PLAY(gen_wallet_payment_id); diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index ef10bf61..cba1fadb 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -639,8 +639,19 @@ bool gen_wallet_mine_pos_block::c1(currency::core& c, size_t ev_index, const std block top_block = AUTO_VAL_INIT(top_block); bool r = c.get_blockchain_storage().get_top_block(top_block); CHECK_AND_ASSERT_MES(r && is_pos_block(top_block), false, "get_top_block failed or smth goes wrong"); - uint64_t top_block_reward = get_outs_money_amount(top_block.miner_tx); - CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", top_block_reward, top_block_reward - MK_TEST_COINS(2000), 0, 0, 0), false, ""); + + uint64_t top_block_reward = 0, expected_mined = 0; + if (c.get_blockchain_storage().is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) + { + top_block_reward = MK_TEST_COINS(2000) + CURRENCY_BLOCK_REWARD; + expected_mined = INVALID_BALANCE_VAL; // Don't check mined balace for post-HF4 due to a lack of mined balance correctness TODO -- sowle + } + else + { + top_block_reward = get_outs_money_amount(top_block.miner_tx); + expected_mined = top_block_reward - MK_TEST_COINS(2000); + } + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", top_block_reward, expected_mined, 0, 0, 0), false, ""); alice_wlt->reset_password(g_wallet_password); alice_wlt->store(g_wallet_filename); From 7c3d21e31f83c0f6ba7e7f16a8626018746714ea Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 13 Jul 2024 00:31:49 +0200 Subject: [PATCH 011/239] coretests: minor fixes (gcc) --- tests/core_tests/wallet_tests_basic.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/core_tests/wallet_tests_basic.h b/tests/core_tests/wallet_tests_basic.h index 72fa6fc5..6515b4a7 100644 --- a/tests/core_tests/wallet_tests_basic.h +++ b/tests/core_tests/wallet_tests_basic.h @@ -36,7 +36,7 @@ struct wallet_test : virtual public test_chain_unit_enchanced { m_core_proxy = std::make_shared(); m_core_proxy->set_connectivity(100, 1); - CHECK_AND_ASSERT_MES(m_core_proxy->set_connection_addr("127.0.0.1:33777"), false, ""); + CHECK_AND_ASSERT_THROW_MES(m_core_proxy->set_connection_addr("127.0.0.1:33777"), "set_connection_addr failed"); if (!m_core_proxy->check_connection()) { // if there's not http rpc core server yet, create one @@ -48,7 +48,7 @@ struct wallet_test : virtual public test_chain_unit_enchanced m_http_rpc_server = std::make_shared(c, vm); } m_core_proxy->set_connectivity(30000, 1); - CHECK_AND_ASSERT_MES(m_core_proxy->check_connection(), false, "no connection"); + CHECK_AND_ASSERT_THROW_MES(m_core_proxy->check_connection(), "m_core_proxy: no connection"); } std::shared_ptr w(new wallet_t); @@ -118,7 +118,7 @@ protected: std::shared_ptr init_playtime_test_wallet(const std::vector& events, currency::core& c, size_t account_index) const; std::shared_ptr init_playtime_test_wallet(const std::vector& events, currency::core& c, const currency::account_base& acc) const; - std::shared_ptr wallet_test::init_playtime_test_wallet_with_true_http_rpc(const std::vector& events, currency::core& c, size_t account_index) const; + std::shared_ptr init_playtime_test_wallet_with_true_http_rpc(const std::vector& events, currency::core& c, size_t account_index) const; mutable std::vector m_accounts; mutable test_generator generator; From 270bb925f59d6d5ac0a4728901a003018fef09e7 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 17 Jul 2024 19:29:46 +0400 Subject: [PATCH 012/239] updated documentation --- src/daemon/daemon.cpp | 2 +- src/wallet/wallet_public_structs_defs.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 5f46b088..f5f768fc 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -61,7 +61,7 @@ struct core_critical_error_handler_t : public currency::i_critical_error_handler if (dont_stop_on_time_error) return false; // ignore such errors - LOG_ERROR(ENDL << ENDL << "Serious time sync problem detected, daemon will stop immediately" << ENDL << ENDL); + LOG_ERROR(ENDL << ENDL << "Serious TIME sync problem detected, daemon will stop immediately" << ENDL << ENDL); // stop handling dch.stop_handling(); diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index c71cb2d2..3c6eb174 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -690,7 +690,7 @@ namespace wallet_public KV_SERIALIZE(destinations) DOC_DSCR("List of destinations") DOC_EXMP_AUTO(1) DOC_END KV_SERIALIZE(fee) DOC_DSCR("Fee to be paid on behalf of sender's wallet(paid in native coins)") DOC_EXMP_AUTO(10000000000) DOC_END KV_SERIALIZE(mixin) DOC_DSCR("Specifies number of mixins(decoys) that would be used to create input, actual for pre-zarcanum outputs, for post-zarcanum outputs instead of this option, number that is defined by network hard rules(15+)") DOC_EXMP(15) DOC_END - KV_SERIALIZE(payment_id) DOC_DSCR("Hex-encoded payment_id, that normally used for user database by exchanges") DOC_EXMP_AUTO("1dfe5a88ff9effb3") DOC_END + KV_SERIALIZE(payment_id) DOC_DSCR("Hex-encoded payment_id, that normally used for user database by exchanges") DOC_EXMP_AUTO("") DOC_END KV_SERIALIZE(comment) DOC_DSCR("Text comment that is displayed in UI") DOC_EXMP_AUTO("Thanks for the coffe") DOC_END KV_SERIALIZE(push_payer) DOC_DSCR("Reveal information about sender of this transaction, basically add sender address to transaction in encrypted way, so only receiver can see who sent transaction") DOC_EXMP(false) DOC_END KV_SERIALIZE(hide_receiver) DOC_DSCR("This add to transaction information about remote address(destination), might be needed when the wallet restored from seed phrase and fully resynched, if this option were true, then sender won't be able to see remote address for sent transactions anymore.") DOC_EXMP(true) DOC_END @@ -706,9 +706,9 @@ namespace wallet_public uint64_t tx_size; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(tx_hash) + KV_SERIALIZE(tx_hash) DOC_DSCR("Has of the generated transaction(if succeded)") DOC_EXMP("01220e8304d46b940a86e383d55ca5887b34f158a7365bbcdd17c5a305814a93") DOC_END KV_SERIALIZE(tx_unsigned_hex) - KV_SERIALIZE(tx_size) + KV_SERIALIZE(tx_size) DOC_DSCR("Transaction size in bytes") DOC_EXMP(1234) DOC_END END_KV_SERIALIZE_MAP() }; }; From ef7320496046bd4086e1e6a1cc93301ceffe2f5a Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 17 Jul 2024 19:43:53 +0200 Subject: [PATCH 013/239] added support for std::optional to src/serialization and boost serialization --- .../keyvalue_serialization_overloads.h | 23 ++++++++ src/serialization/boost_types.h | 55 ++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index cb88897f..23ad8fce 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -473,6 +473,29 @@ namespace epee return r; } //------------------------------------------------------------------------------------------------------------------- + //std::optional + template + bool kv_serialize(const std::optional& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + if(d.has_value()) + { + return kv_serialize(*d, stg, hparent_section, pname); + } + return true; + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(std::optional& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + d = t_type{}; + bool r = kv_unserialize(*d, stg, hparent_section, pname); + if (!r) + { + d = std::nullopt; + } + return r; + } + //------------------------------------------------------------------------------------------------------------------- //boost::shared_ptr template bool kv_serialize(const boost::shared_ptr& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) diff --git a/src/serialization/boost_types.h b/src/serialization/boost_types.h index 154705b8..ca3e3d7b 100644 --- a/src/serialization/boost_types.h +++ b/src/serialization/boost_types.h @@ -1,3 +1,4 @@ +// Copyright (c) 2018-2024 Zano Project // Copyright (c) 2014-2017 The The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -7,7 +8,7 @@ #include - +// boost::optional template