From 33d385db5fcd5c95ef96344d741a631831a80fd2 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 27 Apr 2020 14:52:31 +0300 Subject: [PATCH 01/70] auditability: basic structures, serialization, helpers (WIP) --- src/currency_core/currency_basic.h | 109 ++++++++++++++++-- .../currency_boost_serialization.h | 21 ++++ src/currency_core/currency_format_utils.cpp | 2 +- src/currency_core/currency_format_utils.h | 21 ++++ 4 files changed, 140 insertions(+), 13 deletions(-) diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 74f5c824..20199fad 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -58,9 +58,9 @@ namespace currency /* */ /************************************************************************/ - //since structure used in blockchain as a key accessor, then be sure that there is no padding inside +//since structure used in blockchain as a key accessor, then be sure that there is no padding inside #pragma pack(push, 1) - struct account_public_address + struct account_public_address_old { crypto::public_key spend_public_key; crypto::public_key view_public_key; @@ -70,13 +70,73 @@ namespace currency FIELD(view_public_key) END_SERIALIZE() - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(spend_public_key) - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(view_public_key) - END_KV_SERIALIZE_MAP() + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(spend_public_key) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(view_public_key) + END_KV_SERIALIZE_MAP() }; #pragma pack(pop) + +#define ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER 1 + +#define ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE 0x01 // auditable address + +//since structure used in blockchain as a key accessor, then be sure that there is no padding inside +#pragma pack(push, 1) + struct account_public_address + { + /*account_public_address() + {} + + account_public_address(const account_public_address_old& rhs) + : version(ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) + , flags(0) + , spend_public_key(rhs.spend_public_key) + , view_public_key(rhs.view_public_key) + {}*/ + + uint8_t version; + uint8_t flags; + crypto::public_key spend_public_key; + crypto::public_key view_public_key; + + DEFINE_SERIALIZATION_VERSION(ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) + BEGIN_SERIALIZE_OBJECT() + VERSION_ENTRY(version) + FIELD(flags) + FIELD(spend_public_key) + FIELD(view_public_key) + if (version > ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) + return true; // backward compartibility + END_SERIALIZE() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(version) // is it necessary? + KV_SERIALIZE(flags) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(spend_public_key) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(view_public_key) + END_KV_SERIALIZE_MAP() + + static account_public_address from_old(const account_public_address_old& rhs) + { + account_public_address result = AUTO_VAL_INIT(result); + result.spend_public_key = rhs.spend_public_key; + result.view_public_key = rhs.view_public_key; + return result; + } + + account_public_address_old to_old() const + { + account_public_address_old result = AUTO_VAL_INIT(result); + result.spend_public_key = spend_public_key; + result.view_public_key = view_public_key; + return result; + } + }; +#pragma pack(pop) + + const static account_public_address null_pub_addr = AUTO_VAL_INIT(null_pub_addr); typedef std::vector ring_signature; @@ -224,9 +284,30 @@ namespace currency END_SERIALIZE() }; + struct tx_payer_old + { + account_public_address_old acc_addr; + + BEGIN_SERIALIZE() + FIELD(acc_addr) + END_SERIALIZE() + }; + struct tx_payer { - account_public_address acc_addr; + tx_payer() = default; + tx_payer(const tx_payer_old& old) : acc_addr(account_public_address::from_old(old.acc_addr)) {} + + account_public_address acc_addr{}; + + BEGIN_SERIALIZE() + FIELD(acc_addr) + END_SERIALIZE() + }; + + struct tx_receiver_old + { + account_public_address_old acc_addr; BEGIN_SERIALIZE() FIELD(acc_addr) @@ -235,7 +316,10 @@ namespace currency struct tx_receiver { - account_public_address acc_addr; + tx_receiver() = default; + tx_receiver(const tx_receiver_old& old) : acc_addr(account_public_address::from_old(old.acc_addr)) {} + + account_public_address acc_addr{}; BEGIN_SERIALIZE() FIELD(acc_addr) @@ -388,9 +472,10 @@ namespace currency END_SERIALIZE() }; - typedef boost::mpl::vector< - tx_service_attachment, tx_comment, tx_payer, tx_receiver, tx_derivation_hint, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time, + typedef boost::mpl::vector20< + tx_service_attachment, tx_comment, tx_payer_old, tx_receiver_old, tx_derivation_hint, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time, etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry, extra_user_data, extra_padding, etc_tx_uint16_t, etc_tx_details_unlock_time2 + , tx_payer, tx_receiver//, extra_alias_entry > all_payload_types; typedef boost::make_variant_over::type payload_items_v; @@ -602,7 +687,7 @@ SET_VARIANT_TAGS(currency::transaction, 5, "tx"); SET_VARIANT_TAGS(currency::block, 6, "block"); //attachment_v definitions SET_VARIANT_TAGS(currency::tx_comment, 7, "comment"); -SET_VARIANT_TAGS(currency::tx_payer, 8, "payer"); +SET_VARIANT_TAGS(currency::tx_payer_old, 8, "payer"); SET_VARIANT_TAGS(std::string, 9, "string"); SET_VARIANT_TAGS(currency::tx_crypto_checksum, 10, "checksum"); SET_VARIANT_TAGS(currency::tx_derivation_hint, 11, "derivation_hint"); diff --git a/src/currency_core/currency_boost_serialization.h b/src/currency_core/currency_boost_serialization.h index 99928b7a..e940ec11 100644 --- a/src/currency_core/currency_boost_serialization.h +++ b/src/currency_core/currency_boost_serialization.h @@ -29,10 +29,18 @@ namespace boost template inline void serialize(Archive &a, currency::account_public_address &x, const boost::serialization::version_type ver) { + a & x.version; + a & x.flags; a & x.spend_public_key; a & x.view_public_key; } + template + inline void serialize(Archive &a, currency::account_public_address_old &x, const boost::serialization::version_type ver) + { + a & x.spend_public_key; + a & x.view_public_key; + } template inline void serialize(Archive &a, currency::txout_to_key &x, const boost::serialization::version_type ver) @@ -90,11 +98,24 @@ namespace boost a & x.comment; } + template + inline void serialize(Archive &a, currency::tx_payer_old &x, const boost::serialization::version_type ver) + { + a & x.acc_addr; + } + template inline void serialize(Archive &a, currency::tx_payer &x, const boost::serialization::version_type ver) { a & x.acc_addr; } + + template + inline void serialize(Archive &a, currency::tx_receiver_old &x, const boost::serialization::version_type ver) + { + a & x.acc_addr; + } + template inline void serialize(Archive &a, currency::tx_receiver &x, const boost::serialization::version_type ver) { diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index feeab899..2c87a385 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -2026,7 +2026,7 @@ namespace currency //--------------------------------------------------------------- bool is_showing_sender_addres(const transaction& tx) { - return have_type_in_variant_container(tx.attachment); + return have_type_in_variant_container(tx.attachment) || have_type_in_variant_container(tx.attachment); } //--------------------------------------------------------------- bool is_mixin_tx(const transaction& tx) diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 48441033..abe217ab 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -27,6 +27,7 @@ #include "blockchain_storage_basic.h" #include "currency_format_utils_blocks.h" #include "currency_format_utils_transactions.h" +#include "core_runtime_config.h" // ------ get_tx_type_definition ------------- @@ -589,6 +590,26 @@ namespace currency return boost::apply_visitor(input_amount_getter(), v); } //--------------------------------------------------------------- + template + void create_and_add_tx_payer_to_container_from_address(container_t& container, const account_public_address& addr, uint64_t top_block_height, const core_runtime_config& crc) + { + if (top_block_height > crc.hard_fork_02_starts_after_height) + { + // after hardfork 2 + tx_payer result = AUTO_VAL_INIT(result); + result.acc_addr = addr; + container.push_back(result); + } + else + { + // before hardfork 2 + tx_payer_old result = AUTO_VAL_INIT(result); + result.acc_addr = addr.to_old(); + container.push_back(result); + } + } + //--------------------------------------------------------------- + //--------------------------------------------------------------- std::ostream& operator <<(std::ostream& o, const ref_by_id& r); //--------------------------------------------------------------- #ifndef ANDROID_BUILD From 3a2fb378a497c572136f3d058efe090be18035c0 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 27 Apr 2020 16:09:02 +0300 Subject: [PATCH 02/70] initial coretests for auditability, work in progress --- tests/core_tests/chaingen_tests_list.h | 1 + tests/core_tests/hard_fork_2.cpp | 72 ++++++++++++++++++++++++++ tests/core_tests/hard_fork_2.h | 22 ++++++++ tests/core_tests/wallet_tests.cpp | 2 +- 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 tests/core_tests/hard_fork_2.cpp create mode 100644 tests/core_tests/hard_fork_2.h diff --git a/tests/core_tests/chaingen_tests_list.h b/tests/core_tests/chaingen_tests_list.h index 635e1cd7..bccf06ee 100644 --- a/tests/core_tests/chaingen_tests_list.h +++ b/tests/core_tests/chaingen_tests_list.h @@ -37,3 +37,4 @@ #include "hard_fork_1_consensus_test.h" #include "hard_fork_1_bad_pos_source.h" #include "hard_fork_1.h" +#include "hard_fork_2.h" diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp new file mode 100644 index 00000000..a0c76fa9 --- /dev/null +++ b/tests/core_tests/hard_fork_2.cpp @@ -0,0 +1,72 @@ +// Copyright (c) 2020 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chaingen.h" +#include "hard_fork_2.h" +//#include "pos_block_builder.h" +//#include "tx_builder.h" +//#include "random_helper.h" + +using namespace currency; + +//------------------------------------------------------------------------------ + +hard_fork_2_base_test::hard_fork_2_base_test(size_t hardfork_height) + : m_hardfork_height(hardfork_height) +{ + REGISTER_CALLBACK_METHOD(hard_fork_2_base_test, configure_core); +} + +bool hard_fork_2_base_test::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.hard_fork_01_starts_after_height = m_hardfork_height; + pc.hard_fork_02_starts_after_height = m_hardfork_height; + c.get_blockchain_storage().set_core_runtime_config(pc); + return true; +} + +//------------------------------------------------------------------------------ + +hard_fork_2_tx_payer_in_wallet::hard_fork_2_tx_payer_in_wallet() + : hard_fork_2_base_test(16) +{ + REGISTER_CALLBACK_METHOD(hard_fork_2_tx_payer_in_wallet, c1); } + +bool hard_fork_2_tx_payer_in_wallet::generate(std::vector& events) const +{ + // Test idea: make sure that wallet uses tx_payer_old only before HF2 and tx_payer after + + 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(); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); + + DO_CALLBACK(events, "c1"); + + // REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); + + + return true; +} + +bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false, stub_bool = false; + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Miner", miner_wlt, COIN * (CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3), true), false, ""); + + /*r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + */ + + return true; +} diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h new file mode 100644 index 00000000..8e981f4b --- /dev/null +++ b/tests/core_tests/hard_fork_2.h @@ -0,0 +1,22 @@ +// Copyright (c) 2020 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 "chaingen.h" +#include "wallet_tests_basic.h" + +struct hard_fork_2_base_test : virtual public test_chain_unit_enchanced +{ + hard_fork_2_base_test(size_t hardfork_height); + bool configure_core(currency::core& c, size_t ev_index, const std::vector& events); + + size_t m_hardfork_height; +}; + +struct hard_fork_2_tx_payer_in_wallet : public hard_fork_2_base_test, public wallet_test +{ + hard_fork_2_tx_payer_in_wallet(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 1900c59e..74c9f24e 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1434,7 +1434,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0); REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_0r, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); - // these attachments will be use across all the transactions in this test + // these attachments will be used across all the transactions in this test currency::tx_payer a_tx_payer = AUTO_VAL_INIT(a_tx_payer); a_tx_payer.acc_addr = miner_acc.get_keys().account_address; currency::tx_comment a_tx_comment = AUTO_VAL_INIT(a_tx_comment); From da7d525801281aac86457a7fe4832812bbcf9872 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 27 Apr 2020 16:20:31 +0300 Subject: [PATCH 03/70] wallet: tx_payer/tx_payer_old are now added according to hardfork rule --- src/wallet/wallet2.cpp | 6 +++--- src/wallet/wallet_rpc_server.cpp | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4691854e..b80d7445 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -4501,9 +4501,9 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public set_payment_id_to_tx(ftp.attachments, payment_id); // put encrypted payer info into the extra ftp.crypt_address = destination_addr; - currency::tx_payer txp = AUTO_VAL_INIT(txp); - txp.acc_addr = m_account.get_public_address(); - ftp.extra.push_back(txp); + + currency::create_and_add_tx_payer_to_container_from_address(ftp.extra, m_account.get_public_address(), get_top_block_height(), m_core_runtime_config); + ftp.flags = 0; // ftp.multisig_id -- not required // ftp.prepared_destinations -- will be filled by prepare_tx_destinations diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 040ef071..a90ae5a7 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -292,9 +292,7 @@ namespace tools if (req.push_payer) { - currency::tx_payer txp = AUTO_VAL_INIT(txp); - txp.acc_addr = m_wallet.get_account().get_keys().account_address; - extra.push_back(txp); + currency::create_and_add_tx_payer_to_container_from_address(extra, m_wallet.get_account().get_keys().account_address, m_wallet.get_top_block_height(), m_wallet.get_core_runtime_config()); } if (!req.hide_receiver) { From 158aea723ca5f7fe3c8ab0f130c23a325388622a Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 27 Apr 2020 18:11:18 +0300 Subject: [PATCH 04/70] typo fixed --- src/wallet/wallet_public_structs_defs.h | 4 ++-- tests/core_tests/wallet_rpc_tests.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 9c354700..574a1ba6 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -300,7 +300,7 @@ namespace wallet_public - struct trnsfer_destination + struct transfer_destination { uint64_t amount; std::string address; @@ -314,7 +314,7 @@ namespace wallet_public { struct request { - std::list destinations; + std::list destinations; uint64_t fee; uint64_t mixin; //uint64_t unlock_time; diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index 554c93bf..12bb2f8a 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -117,7 +117,7 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind tools::wallet_public::COMMAND_RPC_TRANSFER::request req = AUTO_VAL_INIT(req); req.fee = TESTS_DEFAULT_FEE; req.mixin = 0; - tools::wallet_public::trnsfer_destination tds = AUTO_VAL_INIT(tds); + tools::wallet_public::transfer_destination tds = AUTO_VAL_INIT(tds); tds.address = alice_integrated_address; tds.amount = MK_TEST_COINS(3); req.destinations.push_back(tds); @@ -152,7 +152,7 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind // 3. standard address + invalid external payment id => fail req.destinations.clear(); - tools::wallet_public::trnsfer_destination tds2 = AUTO_VAL_INIT(tds2); + tools::wallet_public::transfer_destination tds2 = AUTO_VAL_INIT(tds2); tds2.address = m_accounts[ALICE_ACC_IDX].get_public_address_str(); tds2.amount = MK_TEST_COINS(7); req.destinations.push_back(tds2); From e30214d722da408301395665af26c4db2e83d144 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 27 Apr 2020 18:29:55 +0300 Subject: [PATCH 05/70] whitespace fix --- tests/core_tests/hard_fork_2.cpp | 145 ++++++++++++++++--------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index a0c76fa9..2a1ab65a 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -1,72 +1,73 @@ -// Copyright (c) 2020 Zano Project -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "chaingen.h" -#include "hard_fork_2.h" -//#include "pos_block_builder.h" -//#include "tx_builder.h" -//#include "random_helper.h" - -using namespace currency; - -//------------------------------------------------------------------------------ - -hard_fork_2_base_test::hard_fork_2_base_test(size_t hardfork_height) - : m_hardfork_height(hardfork_height) -{ - REGISTER_CALLBACK_METHOD(hard_fork_2_base_test, configure_core); -} - -bool hard_fork_2_base_test::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.hard_fork_01_starts_after_height = m_hardfork_height; - pc.hard_fork_02_starts_after_height = m_hardfork_height; - c.get_blockchain_storage().set_core_runtime_config(pc); - return true; -} - -//------------------------------------------------------------------------------ - -hard_fork_2_tx_payer_in_wallet::hard_fork_2_tx_payer_in_wallet() - : hard_fork_2_base_test(16) -{ - REGISTER_CALLBACK_METHOD(hard_fork_2_tx_payer_in_wallet, c1); } - -bool hard_fork_2_tx_payer_in_wallet::generate(std::vector& events) const -{ - // Test idea: make sure that wallet uses tx_payer_old only before HF2 and tx_payer after - - 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(); - - MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); - REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); - - DO_CALLBACK(events, "c1"); - - // REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); - - - return true; -} - -bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, const std::vector& events) -{ - bool r = false, stub_bool = false; - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); - - CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Miner", miner_wlt, COIN * (CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3), true), false, ""); - - /*r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); - CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - */ - - return true; -} +// Copyright (c) 2020 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chaingen.h" +#include "hard_fork_2.h" +//#include "pos_block_builder.h" +//#include "tx_builder.h" +//#include "random_helper.h" + +using namespace currency; + +//------------------------------------------------------------------------------ + +hard_fork_2_base_test::hard_fork_2_base_test(size_t hardfork_height) + : m_hardfork_height(hardfork_height) +{ + REGISTER_CALLBACK_METHOD(hard_fork_2_base_test, configure_core); +} + +bool hard_fork_2_base_test::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.hard_fork_01_starts_after_height = m_hardfork_height; + pc.hard_fork_02_starts_after_height = m_hardfork_height; + c.get_blockchain_storage().set_core_runtime_config(pc); + return true; +} + +//------------------------------------------------------------------------------ + +hard_fork_2_tx_payer_in_wallet::hard_fork_2_tx_payer_in_wallet() + : hard_fork_2_base_test(16) +{ + REGISTER_CALLBACK_METHOD(hard_fork_2_tx_payer_in_wallet, c1); +} + +bool hard_fork_2_tx_payer_in_wallet::generate(std::vector& events) const +{ + // Test idea: make sure that wallet uses tx_payer_old only before HF2 and tx_payer after + + 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(); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); + + DO_CALLBACK(events, "c1"); + + // REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); + + + return true; +} + +bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false, stub_bool = false; + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Miner", miner_wlt, COIN * (CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3), true), false, ""); + + /*r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + */ + + return true; +} From 1cb908a4841b693dc659ddaaa3544771c7d66bc0 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Apr 2020 15:10:59 +0300 Subject: [PATCH 06/70] handle_2_alternative_types_in_variant_container fixed --- src/currency_core/currency_format_utils_abstract.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/currency_core/currency_format_utils_abstract.h b/src/currency_core/currency_format_utils_abstract.h index d6a48212..cd739bf0 100644 --- a/src/currency_core/currency_format_utils_abstract.h +++ b/src/currency_core/currency_format_utils_abstract.h @@ -122,7 +122,7 @@ namespace currency else if (item.type() == typeid(B)) { found = true; - if (!cb(boost::get(item))) + if (!cb(boost::get(item))) break; } } From fc68a33bedfe2eb607d42442ac950bfa125d8613 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Apr 2020 15:51:41 +0300 Subject: [PATCH 07/70] coretests: wlt_lambda_on_transfer2_wrapper moved --- tests/core_tests/wallet_tests.cpp | 12 ------------ tests/core_tests/wallet_tests_basic.cpp | 2 ++ tests/core_tests/wallet_tests_basic.h | 12 ++++++++++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 74c9f24e..3bee8148 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -22,18 +22,6 @@ const std::string g_wallet_password = "dofatibmzibeziyekigo"; const currency::account_base null_account = AUTO_VAL_INIT(null_account); -struct wlt_lambda_on_transfer2_wrapper : public tools::i_wallet2_callback -{ - typedef std::function Func; - wlt_lambda_on_transfer2_wrapper(Func callback) : m_result(false), m_callback(callback) {} - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override - { - m_result = m_callback(wti, balance, unlocked_balance, total_mined); - } - bool m_result; - Func m_callback; -}; - POD_MAKE_COMPARABLE(currency, tx_out); // Determines which output is real and actually spent in tx inputs, when there are fake outputs. diff --git a/tests/core_tests/wallet_tests_basic.cpp b/tests/core_tests/wallet_tests_basic.cpp index 5c2744e2..fe4ec260 100644 --- a/tests/core_tests/wallet_tests_basic.cpp +++ b/tests/core_tests/wallet_tests_basic.cpp @@ -72,6 +72,7 @@ bool wallet_test::check_balance(currency::core& c, size_t ev_index, const std::v return true; } + std::shared_ptr wallet_test::init_playtime_test_wallet(const std::vector& events, currency::core& c, const account_base& acc) 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"); @@ -84,6 +85,7 @@ std::shared_ptr wallet_test::init_playtime_test_wallet(const std w->set_core_proxy(m_core_proxy); return w; } + std::shared_ptr wallet_test::init_playtime_test_wallet(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"); diff --git a/tests/core_tests/wallet_tests_basic.h b/tests/core_tests/wallet_tests_basic.h index 4627284c..1e921b29 100644 --- a/tests/core_tests/wallet_tests_basic.h +++ b/tests/core_tests/wallet_tests_basic.h @@ -87,3 +87,15 @@ struct wallet_callback_balance_checker : public tools::i_wallet2_callback uint64_t m_unlocked_balance; uint64_t m_total_mined; }; + +struct wlt_lambda_on_transfer2_wrapper : public tools::i_wallet2_callback +{ + typedef std::function Func; + wlt_lambda_on_transfer2_wrapper(Func callback) : m_result(false), m_callback(callback) {} + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override + { + m_result = m_callback(wti, balance, unlocked_balance, total_mined); + } + bool m_result; + Func m_callback; +}; From ead981b8382f16da6b420c0b905cfdf193145278 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Apr 2020 15:53:31 +0300 Subject: [PATCH 08/70] coretests: hard_fork_2_tx_payer_in_wallet test added --- tests/core_tests/chaingen_main.cpp | 9 ++- tests/core_tests/hard_fork_2.cpp | 94 +++++++++++++++++++++++++++++- tests/core_tests/hard_fork_2.h | 2 +- 3 files changed, 98 insertions(+), 7 deletions(-) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 68ff8c68..77323a26 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -987,7 +987,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_uint_overflow_2); - // Hardfok1 tests + // Hardfok 1 tests GENERATE_AND_PLAY(before_hard_fork_1_cumulative_difficulty); GENERATE_AND_PLAY(inthe_middle_hard_fork_1_cumulative_difficulty); GENERATE_AND_PLAY(after_hard_fork_1_cumulative_difficulty); @@ -998,10 +998,13 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(hard_fork_1_chain_switch_pow_only); GENERATE_AND_PLAY(hard_fork_1_checkpoint_basic_test); GENERATE_AND_PLAY(hard_fork_1_pos_locked_height_vs_time); - //GENERATE_AND_PLAY(gen_block_reward); */ - + + // Hardfork 2 tests + GENERATE_AND_PLAY(hard_fork_2_tx_payer_in_wallet); + // GENERATE_AND_PLAY(gen_block_reward); + // END OF TESTS */ size_t failed_postponed_tests_count = 0; uint64_t total_time = 0; diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 2a1ab65a..665d19b7 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -4,6 +4,7 @@ #include "chaingen.h" #include "hard_fork_2.h" +#include "../../src/wallet/wallet_rpc_server.h" //#include "pos_block_builder.h" //#include "tx_builder.h" //#include "random_helper.h" @@ -46,6 +47,9 @@ bool hard_fork_2_tx_payer_in_wallet::generate(std::vector& eve account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + generator.set_hardfork_height(1, m_hardfork_height); + generator.set_hardfork_height(2, m_hardfork_height); + DO_CALLBACK(events, "configure_core"); REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); DO_CALLBACK(events, "c1"); @@ -61,13 +65,97 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons bool r = false, stub_bool = false; CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); - CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Miner", miner_wlt, COIN * (CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3), true), false, ""); + miner_wlt->refresh(); - /*r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + // wallet RPC server + tools::wallet_rpc_server miner_wlt_rpc(*miner_wlt); + epee::json_rpc::error je; + tools::wallet_rpc_server::connection_context ctx; + + tools::wallet_public::COMMAND_RPC_TRANSFER::request req = AUTO_VAL_INIT(req); + tools::wallet_public::transfer_destination td{ MK_TEST_COINS(1), m_accounts[ALICE_ACC_IDX].get_public_address_str() }; + req.destinations.push_back(td); + req.fee = TESTS_DEFAULT_FEE; + req.push_payer = true; + + tools::wallet_public::COMMAND_RPC_TRANSFER::response res = AUTO_VAL_INIT(res); + + r = miner_wlt_rpc.on_transfer(req, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + crypto::hash tx_hash = null_hash; + CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); + + transaction tx = AUTO_VAL_INIT(tx); + CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); + + r = have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer_old is not found in extra"); + + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer is found in extra"); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - */ + + std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( + [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + CHECK_AND_ASSERT_MES(wti.show_sender, false, "show_sender is false"); + CHECK_AND_ASSERT_MES(wti.remote_addresses.size() == 1, false, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); + CHECK_AND_ASSERT_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.front is incorrect"); + return true; + } + )); + alice_wlt->callback(l); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(1)), false, ""); + + // mine blocks 15, 16, 17 to activate HF2 + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 3); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + miner_wlt->refresh(); + alice_wlt->refresh(); + + // check again + req.destinations.front().amount = MK_TEST_COINS(2); + r = miner_wlt_rpc.on_transfer(req, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + tx_hash = null_hash; + CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); + CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); + + r = have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer is not found in extra"); + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer_old is found in extra"); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( + [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + CHECK_AND_ASSERT_MES(wti.amount == MK_TEST_COINS(2), false, "incorrect wti.amount = " << print_money_brief(wti.amount)); + CHECK_AND_ASSERT_MES(wti.show_sender, false, "show_sender is false"); + CHECK_AND_ASSERT_MES(wti.remote_addresses.size() == 1, false, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); + CHECK_AND_ASSERT_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.front is incorrect"); + return true; + } + )); + alice_wlt->callback(l2); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(3)), false, ""); + + return true; } diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h index 8e981f4b..18769717 100644 --- a/tests/core_tests/hard_fork_2.h +++ b/tests/core_tests/hard_fork_2.h @@ -14,7 +14,7 @@ struct hard_fork_2_base_test : virtual public test_chain_unit_enchanced size_t m_hardfork_height; }; -struct hard_fork_2_tx_payer_in_wallet : public hard_fork_2_base_test, public wallet_test +struct hard_fork_2_tx_payer_in_wallet : public wallet_test, public hard_fork_2_base_test { hard_fork_2_tx_payer_in_wallet(); bool generate(std::vector& events) const; From d3f353935fc7e79804df9080fdd97e2327db234e Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Apr 2020 15:58:25 +0300 Subject: [PATCH 09/70] wallet2: correct handling of tx_payer/tx_payer_old (covered by hard_fork_2_tx_payer_in_wallet test) --- src/wallet/wallet2.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index b80d7445..9033d590 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -469,13 +469,13 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector& decrypted_att) { PROFILE_FUNC("wallet2::prepare_wti_decrypted_attachments"); - tx_payer tp = AUTO_VAL_INIT(tp); - wti.show_sender = get_type_in_variant_container(decrypted_att, tp); if (wti.is_income) { - if(wti.show_sender) - wti.remote_addresses.push_back(currency::get_account_address_as_str(tp.acc_addr)); + account_public_address sender_address = AUTO_VAL_INIT(sender_address); + wti.show_sender = handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { sender_address = p.acc_addr; return false; } ); + if (wti.show_sender) + wti.remote_addresses.push_back(currency::get_account_address_as_str(sender_address)); } else { From d3ce73e7acd95e1e0fb002ac857bb14e5fc8db10 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Apr 2020 15:59:23 +0300 Subject: [PATCH 10/70] wallets_manager: correct tx_payer/tx_payer_old handling --- src/wallet/wallets_manager.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 019b7ca9..21f06c89 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -1200,9 +1200,7 @@ std::string wallets_manager::transfer(size_t wallet_id, const view::transfer_par } if (tp.push_payer) { - currency::tx_payer txp = AUTO_VAL_INIT(txp); - txp.acc_addr = w->get()->get_account().get_keys().account_address; - extra.push_back(txp); + currency::create_and_add_tx_payer_to_container_from_address(extra, w->get()->get_account().get_keys().account_address, w->get()->get_top_block_height(), w->get()->get_core_runtime_config()); } if (!tp.hide_receiver) { From 1afab184c8d8c258d3862c66f5b37addbc57407c Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Apr 2020 16:41:04 +0300 Subject: [PATCH 11/70] tx_receiver/tx_receiver_old proper handling --- src/currency_core/currency_format_utils.h | 19 +++++++++++++++++++ src/wallet/wallet2.cpp | 12 +++++++++--- src/wallet/wallet_rpc_server.cpp | 7 ++----- src/wallet/wallets_manager.cpp | 6 +----- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index abe217ab..26f6554d 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -609,6 +609,25 @@ namespace currency } } //--------------------------------------------------------------- + template + void create_and_add_tx_receiver_to_container_from_address(container_t& container, const account_public_address& addr, uint64_t top_block_height, const core_runtime_config& crc) + { + if (top_block_height > crc.hard_fork_02_starts_after_height) + { + // after hardfork 2 + tx_receiver result = AUTO_VAL_INIT(result); + result.acc_addr = addr; + container.push_back(result); + } + else + { + // before hardfork 2 + tx_receiver_old result = AUTO_VAL_INIT(result); + result.acc_addr = addr.to_old(); + container.push_back(result); + } + } + //--------------------------------------------------------------- //--------------------------------------------------------------- std::ostream& operator <<(std::ostream& o, const ref_by_id& r); //--------------------------------------------------------------- diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 9033d590..757d862f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -480,9 +480,15 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i else { //TODO: actually recipients could be more then one, handle it in future - tx_receiver tr = AUTO_VAL_INIT(tr); - if (!wti.remote_addresses.size() && get_type_in_variant_container(decrypted_att, tr)) - wti.remote_addresses.push_back(currency::get_account_address_as_str(tr.acc_addr)); + //tx_receiver tr = AUTO_VAL_INIT(tr); + //if (!wti.remote_addresses.size() && get_type_in_variant_container(decrypted_att, tr)) + // wti.remote_addresses.push_back(currency::get_account_address_as_str(tr.acc_addr)); + + account_public_address receiver_address = AUTO_VAL_INIT(receiver_address); + handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { + wti.remote_addresses.push_back(currency::get_account_address_as_str(p.acc_addr)); + return true; // continue iterating through the container + }); } currency::tx_comment cm; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index a90ae5a7..70dfd113 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -294,16 +294,13 @@ namespace tools { currency::create_and_add_tx_payer_to_container_from_address(extra, m_wallet.get_account().get_keys().account_address, m_wallet.get_top_block_height(), m_wallet.get_core_runtime_config()); } + if (!req.hide_receiver) { for (auto& d : dsts) { for (auto& a : d.addr) - { - currency::tx_receiver txr = AUTO_VAL_INIT(txr); - txr.acc_addr = a; - extra.push_back(txr); - } + currency::create_and_add_tx_receiver_to_container_from_address(extra, a, m_wallet.get_top_block_height(), m_wallet.get_core_runtime_config()); } } diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 21f06c89..4e6c92e3 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -1207,11 +1207,7 @@ std::string wallets_manager::transfer(size_t wallet_id, const view::transfer_par for (auto& d : dsts) { for (auto& a : d.addr) - { - currency::tx_receiver txr = AUTO_VAL_INIT(txr); - txr.acc_addr = a; - extra.push_back(txr); - } + currency::create_and_add_tx_receiver_to_container_from_address(extra, a, w->get()->get_top_block_height(), w->get()->get_core_runtime_config()); } } w->get()->transfer(dsts, tp.mixin_count, unlock_time ? unlock_time + 1 : 0, fee, extra, attachments, res_tx); From a5516dbd7ebb5d9fceb3fe17e3a98bc36d3c9a6c Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 29 Apr 2020 21:04:40 +0300 Subject: [PATCH 12/70] coretests: hard_fork_2_tx_receiver_in_wallet test added --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/hard_fork_2.cpp | 143 ++++++++++++++++++++++++++++- tests/core_tests/hard_fork_2.h | 9 ++ 3 files changed, 150 insertions(+), 3 deletions(-) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 77323a26..c2bb6d96 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1001,6 +1001,7 @@ int main(int argc, char* argv[]) // Hardfork 2 tests GENERATE_AND_PLAY(hard_fork_2_tx_payer_in_wallet); + GENERATE_AND_PLAY(hard_fork_2_tx_receiver_in_wallet); // GENERATE_AND_PLAY(gen_block_reward); diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 665d19b7..48efa133 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -54,9 +54,6 @@ bool hard_fork_2_tx_payer_in_wallet::generate(std::vector& eve DO_CALLBACK(events, "c1"); - // REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); - - return true; } @@ -155,7 +152,147 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(3)), false, ""); + return true; +} +//------------------------------------------------------------------------------ + +hard_fork_2_tx_receiver_in_wallet::hard_fork_2_tx_receiver_in_wallet() + : hard_fork_2_base_test(23) + , m_alice_start_balance(0) +{ + REGISTER_CALLBACK_METHOD(hard_fork_2_tx_receiver_in_wallet, c1); +} + +bool hard_fork_2_tx_receiver_in_wallet::generate(std::vector& events) const +{ + // Test idea: make sure that wallet uses tx_receiver_old only before HF2 and tx_receiver after + + 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()); + generator.set_hardfork_height(1, m_hardfork_height); + generator.set_hardfork_height(2, m_hardfork_height); + DO_CALLBACK(events, "configure_core"); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); + + m_alice_start_balance = MK_TEST_COINS(111); + MAKE_TX(events, tx_0, miner_acc, alice_acc, m_alice_start_balance, 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, WALLET_DEFAULT_TX_SPENDABLE_AGE); + + DO_CALLBACK(events, "c1"); + + return true; +} + +bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false, stub_bool = false; + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); + + miner_wlt->refresh(); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, m_alice_start_balance), false, ""); + + // wallet RPC server + tools::wallet_rpc_server alice_wlt_rpc(*alice_wlt); + epee::json_rpc::error je; + tools::wallet_rpc_server::connection_context ctx; + + tools::wallet_public::COMMAND_RPC_TRANSFER::request req = AUTO_VAL_INIT(req); + tools::wallet_public::transfer_destination td1{ MK_TEST_COINS(1), m_accounts[MINER_ACC_IDX].get_public_address_str() }; + tools::wallet_public::transfer_destination td2{ MK_TEST_COINS(1), m_accounts[BOB_ACC_IDX].get_public_address_str() }; + req.destinations.push_back(td1); + req.destinations.push_back(td2); + req.fee = TESTS_DEFAULT_FEE; + req.hide_receiver = false; // just to emphasize, this is false be default + + LOG_PRINT_L0("Miner's address: " << m_accounts[MINER_ACC_IDX].get_public_address_str()); + LOG_PRINT_L0("Alice's address: " << m_accounts[ALICE_ACC_IDX].get_public_address_str()); + + tools::wallet_public::COMMAND_RPC_TRANSFER::response res = AUTO_VAL_INIT(res); + + r = alice_wlt_rpc.on_transfer(req, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + crypto::hash tx_hash = null_hash; + CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); + + transaction tx = AUTO_VAL_INIT(tx); + CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); + + r = have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_receiver_old is not found in extra"); + + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_receiver is found in extra"); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( + [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + CHECK_AND_ASSERT_MES(!wti.is_income, false, "wti.is_income is " << wti.is_income); + CHECK_AND_ASSERT_MES(wti.remote_addresses.size() == 2, false, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); + CHECK_AND_ASSERT_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.front is incorrect"); + CHECK_AND_ASSERT_MES(wti.remote_addresses.back() == m_accounts[BOB_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.back is incorrect"); + return true; + } + )); + alice_wlt->callback(l); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, m_alice_start_balance - MK_TEST_COINS(2) - TESTS_DEFAULT_FEE), false, ""); + + // mine blocks 23, 24, 25 to activate HF2 + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 3); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + miner_wlt->refresh(); + alice_wlt->refresh(); + + // check again + req.destinations.front().amount = MK_TEST_COINS(2); + req.destinations.back().amount = MK_TEST_COINS(2); + r = alice_wlt_rpc.on_transfer(req, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + tx_hash = null_hash; + CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); + CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); + + r = have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_receiver is not found in extra"); + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_receiver_old is found in extra"); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( + [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + CHECK_AND_ASSERT_MES(!wti.is_income, false, "wti.is_income is " << wti.is_income); + CHECK_AND_ASSERT_MES(wti.amount == MK_TEST_COINS(4), false, "incorrect wti.amount = " << print_money_brief(wti.amount)); + CHECK_AND_ASSERT_MES(wti.remote_addresses.size() == 2, false, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); + CHECK_AND_ASSERT_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.front is incorrect"); + CHECK_AND_ASSERT_MES(wti.remote_addresses.back() == m_accounts[BOB_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.back is incorrect"); + return true; + } + )); + alice_wlt->callback(l2); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, m_alice_start_balance - MK_TEST_COINS(6) - TESTS_DEFAULT_FEE * 2), false, ""); return true; } diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h index 18769717..7e64481f 100644 --- a/tests/core_tests/hard_fork_2.h +++ b/tests/core_tests/hard_fork_2.h @@ -20,3 +20,12 @@ struct hard_fork_2_tx_payer_in_wallet : public wallet_test, public hard_fork_2_b bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +struct hard_fork_2_tx_receiver_in_wallet : public wallet_test, public hard_fork_2_base_test +{ + hard_fork_2_tx_receiver_in_wallet(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); + + mutable uint64_t m_alice_start_balance; +}; From c00ca6d5bc945d7e4fd57841ad5c1a5f39c4db8e Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 29 Apr 2020 21:06:08 +0300 Subject: [PATCH 13/70] tx_receiver/tx_receiver_old handling fixed --- .../currency_format_utils_abstract.h | 1 + src/wallet/wallet2.cpp | 22 +++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/currency_core/currency_format_utils_abstract.h b/src/currency_core/currency_format_utils_abstract.h index cd739bf0..a796c974 100644 --- a/src/currency_core/currency_format_utils_abstract.h +++ b/src/currency_core/currency_format_utils_abstract.h @@ -107,6 +107,7 @@ namespace currency return false; } //--------------------------------------------------------------- + // callback should return true to continue iterating through the container template bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t& cb) { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 757d862f..73a6fb83 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -473,22 +473,22 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i if (wti.is_income) { account_public_address sender_address = AUTO_VAL_INIT(sender_address); - wti.show_sender = handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { sender_address = p.acc_addr; return false; } ); + wti.show_sender = handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { sender_address = p.acc_addr; return false; /* <- continue? */ } ); if (wti.show_sender) wti.remote_addresses.push_back(currency::get_account_address_as_str(sender_address)); } else { - //TODO: actually recipients could be more then one, handle it in future - //tx_receiver tr = AUTO_VAL_INIT(tr); - //if (!wti.remote_addresses.size() && get_type_in_variant_container(decrypted_att, tr)) - // wti.remote_addresses.push_back(currency::get_account_address_as_str(tr.acc_addr)); - - account_public_address receiver_address = AUTO_VAL_INIT(receiver_address); - handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { - wti.remote_addresses.push_back(currency::get_account_address_as_str(p.acc_addr)); - return true; // continue iterating through the container - }); + if (wti.remote_addresses.empty()) + { + account_public_address receiver_address = AUTO_VAL_INIT(receiver_address); + handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_receiver& p) { + std::string addr_str = currency::get_account_address_as_str(p.acc_addr); + wti.remote_addresses.push_back(addr_str); + LOG_PRINT_YELLOW("prepare_wti_decrypted_attachments, income=false, wti.amount = " << print_money_brief(wti.amount) << ", rem. addr = " << addr_str, LOG_LEVEL_0); + return true; // continue iterating through the container + }); + } } currency::tx_comment cm; From 03052970a6e87d987f21ab7883fdf613ca8ec861 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 29 Apr 2020 21:12:16 +0300 Subject: [PATCH 14/70] extra_alias_entry_base / struct extra_alias_entry_base_old --- src/currency_core/currency_basic.h | 42 +++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 20199fad..ab57f341 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -381,6 +381,31 @@ namespace currency }; + struct extra_alias_entry_base_old + { + account_public_address_old m_address; + std::string m_text_comment; + std::vector m_view_key; // only one or zero elments expected (std::vector is using as memory efficient container for such a case) + std::vector m_sign; // only one or zero elments expected (std::vector is using as memory efficient container for such a case) + + BEGIN_SERIALIZE() + FIELD(m_address) + FIELD(m_text_comment) + FIELD(m_view_key) + FIELD(m_sign) + END_SERIALIZE() + }; + + struct extra_alias_entry_old : public extra_alias_entry_base_old + { + std::string m_alias; + + BEGIN_SERIALIZE() + FIELD(m_alias) + FIELDS(*static_cast(this)) + END_SERIALIZE() + }; + struct extra_alias_entry_base { account_public_address m_address; @@ -396,13 +421,13 @@ namespace currency END_SERIALIZE() }; - struct extra_alias_entry: public extra_alias_entry_base + struct extra_alias_entry : public extra_alias_entry_base { std::string m_alias; BEGIN_SERIALIZE() FIELD(m_alias) - FIELDS(*static_cast(this)) + FIELDS(*static_cast(this)) END_SERIALIZE() }; @@ -701,7 +726,7 @@ SET_VARIANT_TAGS(currency::signed_parts, 17, "signed_outs"); //extra_v definitions SET_VARIANT_TAGS(currency::extra_attachment_info, 18, "extra_attach_info"); SET_VARIANT_TAGS(currency::extra_user_data, 19, "user_data"); -SET_VARIANT_TAGS(currency::extra_alias_entry, 20, "alias_entry"); +SET_VARIANT_TAGS(currency::extra_alias_entry_old, 20, "alias_entry"); SET_VARIANT_TAGS(currency::extra_padding, 21, "extra_padding"); SET_VARIANT_TAGS(crypto::public_key, 22, "pub_key"); SET_VARIANT_TAGS(currency::etc_tx_uint16_t, 23, "etc_tx_uint16"); @@ -712,7 +737,16 @@ SET_VARIANT_TAGS(uint64_t, 26, "uint64_t"); //etc SET_VARIANT_TAGS(currency::etc_tx_time, 27, "etc_tx_time"); SET_VARIANT_TAGS(uint32_t, 28, "uint32_t"); -SET_VARIANT_TAGS(currency::tx_receiver, 29, "payer"); +SET_VARIANT_TAGS(currency::tx_receiver_old, 29, "payer"); // -- original +//SET_VARIANT_TAGS(currency::tx_receiver_old, 29, "receiver"); SET_VARIANT_TAGS(currency::etc_tx_details_unlock_time2, 30, "unlock_time2"); +SET_VARIANT_TAGS(currency::tx_payer, 31, "payer2"); +SET_VARIANT_TAGS(currency::tx_receiver, 32, "receiver2"); + +// @#@ TODO @#@ +SET_VARIANT_TAGS(currency::extra_alias_entry, 33, "alias_entry2"); + + + #undef SET_VARIANT_TAGS From 8a19cd7ae0b7ee664040b01e3032fadeb07a2c18 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 30 Apr 2020 10:30:14 +0300 Subject: [PATCH 15/70] gcc compilation fixup --- src/currency_core/currency_format_utils_abstract.h | 2 +- src/wallet/wallet2.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/currency_core/currency_format_utils_abstract.h b/src/currency_core/currency_format_utils_abstract.h index a796c974..5f1c7cf6 100644 --- a/src/currency_core/currency_format_utils_abstract.h +++ b/src/currency_core/currency_format_utils_abstract.h @@ -109,7 +109,7 @@ namespace currency //--------------------------------------------------------------- // callback should return true to continue iterating through the container template - bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t& cb) + bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t cb) { bool found = false; for (auto& item : container) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 73a6fb83..0d74da26 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -481,7 +481,6 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i { if (wti.remote_addresses.empty()) { - account_public_address receiver_address = AUTO_VAL_INIT(receiver_address); handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_receiver& p) { std::string addr_str = currency::get_account_address_as_str(p.acc_addr); wti.remote_addresses.push_back(addr_str); From c018cc89ae6f6834a33535357253ae29d5594e0f Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 30 Apr 2020 10:31:50 +0300 Subject: [PATCH 16/70] extra_alias_entry serialization --- .../currency_boost_serialization.h | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/currency_core/currency_boost_serialization.h b/src/currency_core/currency_boost_serialization.h index e940ec11..5e39113c 100644 --- a/src/currency_core/currency_boost_serialization.h +++ b/src/currency_core/currency_boost_serialization.h @@ -157,14 +157,6 @@ namespace boost a & x.m_sign; } - - template - inline void serialize(Archive &a, currency::signed_parts &x, const boost::serialization::version_type ver) - { - a & x.n_outs; - a & x.n_extras; - } - template inline void serialize(Archive &a, currency::extra_alias_entry &x, const boost::serialization::version_type ver) { @@ -172,6 +164,29 @@ namespace boost a & static_cast(x); } + template + inline void serialize(Archive &a, currency::extra_alias_entry_base_old &x, const boost::serialization::version_type ver) + { + a & x.m_address; + a & x.m_text_comment; + a & x.m_view_key; + a & x.m_sign; + } + + template + inline void serialize(Archive &a, currency::extra_alias_entry_old &x, const boost::serialization::version_type ver) + { + a & x.m_alias; + a & static_cast(x); + } + + template + inline void serialize(Archive &a, currency::signed_parts &x, const boost::serialization::version_type ver) + { + a & x.n_outs; + a & x.n_extras; + } + template inline void serialize(Archive &a, currency::extra_padding &x, const boost::serialization::version_type ver) { From 42a752d12b96193d9adcb135cd79dfdcef8c8653 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 30 Apr 2020 18:50:22 +0300 Subject: [PATCH 17/70] new addresses formats + unit tests --- src/currency_core/currency_basic.h | 26 ++--- .../currency_boost_serialization.h | 2 +- src/currency_core/currency_config.h | 5 +- src/currency_core/currency_format_utils.cpp | 86 ++++++++++++--- tests/unit_tests/base58.cpp | 100 ++++++++++++++++++ 5 files changed, 185 insertions(+), 34 deletions(-) diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index ab57f341..da8291dc 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -86,36 +86,26 @@ namespace currency #pragma pack(push, 1) struct account_public_address { - /*account_public_address() - {} - - account_public_address(const account_public_address_old& rhs) - : version(ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) - , flags(0) - , spend_public_key(rhs.spend_public_key) - , view_public_key(rhs.view_public_key) - {}*/ - - uint8_t version; - uint8_t flags; crypto::public_key spend_public_key; crypto::public_key view_public_key; + //uint8_t version; + uint8_t flags; DEFINE_SERIALIZATION_VERSION(ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) BEGIN_SERIALIZE_OBJECT() - VERSION_ENTRY(version) - FIELD(flags) FIELD(spend_public_key) FIELD(view_public_key) - if (version > ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) - return true; // backward compartibility + //VERSION_ENTRY(version) + FIELD(flags) + //if (version > ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) + // return true; // backward compartibility END_SERIALIZE() BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(version) // is it necessary? - KV_SERIALIZE(flags) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(spend_public_key) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(view_public_key) + //KV_SERIALIZE(version) // is it necessary? + KV_SERIALIZE(flags) END_KV_SERIALIZE_MAP() static account_public_address from_old(const account_public_address_old& rhs) diff --git a/src/currency_core/currency_boost_serialization.h b/src/currency_core/currency_boost_serialization.h index 5e39113c..0b6622e3 100644 --- a/src/currency_core/currency_boost_serialization.h +++ b/src/currency_core/currency_boost_serialization.h @@ -29,7 +29,7 @@ namespace boost template inline void serialize(Archive &a, currency::account_public_address &x, const boost::serialization::version_type ver) { - a & x.version; + //a & x.version; a & x.flags; a & x.spend_public_key; a & x.view_public_key; diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 95eee0db..019dd1bd 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -20,8 +20,11 @@ #define CURRENCY_MAX_BLOCK_NUMBER 500000000 #define CURRENCY_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used! #define CURRENCY_TX_MAX_ALLOWED_OUTS 2000 -#define CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX 197 // addresses start with 'Z' +#define CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX 0xc5 // addresses start with 'Zx' #define CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX 0x3678 // integrated addresses start with 'iZ' +#define CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX 0x36f8 // integrated addresses start with 'iZ' (new format) +#define CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX 0x98c8 // auditable addresses start with 'aZx' +#define CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX 0x8a49 // auditable integrated addresses start with 'aiZX' #define CURRENCY_MINED_MONEY_UNLOCK_WINDOW 10 #define CURRENT_TRANSACTION_VERSION 1 #define CURRENT_BLOCK_MAJOR_VERSION 1 diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 2c87a385..390d1b6d 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -2511,12 +2511,24 @@ namespace currency //----------------------------------------------------------------------- std::string get_account_address_as_str(const account_public_address& addr) { - return tools::base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr)); + if (addr.flags == 0) + return tools::base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr.to_old())); // classic Zano address + + if (addr.flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE) + return tools::base58::encode_addr(CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr)); // new format Zano address (auditable) + + return tools::base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr)); // new format Zano address (normal) } //----------------------------------------------------------------------- std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const payment_id_t& payment_id) { - return tools::base58::encode_addr(CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr) + payment_id); + if (addr.flags == 0) + return tools::base58::encode_addr(CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr.to_old()) + payment_id); // classic integrated Zano address + + if (addr.flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE) + return tools::base58::encode_addr(CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr) + payment_id); // new format integrated Zano address (auditable) + + return tools::base58::encode_addr(CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX, t_serializable_object_to_blob(addr) + payment_id); // new format integrated Zano address (normal) } //----------------------------------------------------------------------- bool get_account_address_from_str(account_public_address& addr, const std::string& str) @@ -2527,7 +2539,7 @@ namespace currency //----------------------------------------------------------------------- bool get_account_address_and_payment_id_from_str(account_public_address& addr, payment_id_t& payment_id, const std::string& str) { - static const size_t addr_blob_size = sizeof(account_public_address); + payment_id.clear(); blobdata blob; uint64_t prefix; if (!tools::base58::decode_addr(str, prefix, blob)) @@ -2536,42 +2548,88 @@ namespace currency return false; } - if (blob.size() < addr_blob_size) + if (blob.size() < sizeof(account_public_address_old)) { - LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is less, than expected " << addr_blob_size); + LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is less, than expected " << sizeof(account_public_address_old)); return false; } - if (blob.size() > addr_blob_size + BC_PAYMENT_ID_SERVICE_SIZE_MAX) + if (blob.size() > sizeof(account_public_address) + BC_PAYMENT_ID_SERVICE_SIZE_MAX) { - LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is more, than allowed " << addr_blob_size + BC_PAYMENT_ID_SERVICE_SIZE_MAX); + LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is more, than allowed " << sizeof(account_public_address) + BC_PAYMENT_ID_SERVICE_SIZE_MAX); return false; } + bool parse_as_old_format = false; + if (prefix == CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX) { - // nothing + // normal address + if (blob.size() == sizeof(account_public_address_old)) + { + parse_as_old_format = true; + } + else if (blob.size() == sizeof(account_public_address)) + { + parse_as_old_format = false; + } + else + { + LOG_PRINT_L1("Account public address cannot be parsed from \"" << str << "\", incorrect size"); + return false; + } + } + else if (prefix == CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX) + { + // auditable, parse as new format + parse_as_old_format = false; } else if (prefix == CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX) { - payment_id = blob.substr(addr_blob_size); - blob = blob.substr(0, addr_blob_size); + payment_id = blob.substr(sizeof(account_public_address_old)); + blob = blob.substr(0, sizeof(account_public_address_old)); + parse_as_old_format = true; + } + else if (prefix == CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX || prefix == CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX) + { + payment_id = blob.substr(sizeof(account_public_address)); + blob = blob.substr(0, sizeof(account_public_address)); + parse_as_old_format = false; } else { - LOG_PRINT_L1("Address " << str << " has wrong prefix " << prefix << ", expected " << CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX << " or " << CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX); + LOG_PRINT_L1("Address " << str << " has wrong prefix " << prefix); return false; } - if (!::serialization::parse_binary(blob, addr)) + if (parse_as_old_format) { - LOG_PRINT_L1("Account public address keys can't be parsed for address \"" << str << "\""); + account_public_address_old addr_old = AUTO_VAL_INIT(addr_old); + if (!::serialization::parse_binary(blob, addr_old)) + { + LOG_PRINT_L1("Account public address (old) cannot be parsed from \"" << str << "\""); + return false; + } + addr = account_public_address::from_old(addr_old); + } + else + { + if (!::serialization::parse_binary(blob, addr)) + { + LOG_PRINT_L1("Account public address cannot be parsed from \"" << str << "\""); + return false; + } + } + + if (payment_id.size() > BC_PAYMENT_ID_SERVICE_SIZE_MAX) + { + LOG_PRINT_L1("Failed to parse address from \"" << str << "\": payment id size exceeded: " << payment_id.size()); return false; } if (!crypto::check_key(addr.spend_public_key) || !crypto::check_key(addr.view_public_key)) { - LOG_PRINT_L1("Failed to validate address keys for address \"" << str << "\""); + LOG_PRINT_L1("Failed to validate address keys for public address \"" << str << "\""); return false; } diff --git a/tests/unit_tests/base58.cpp b/tests/unit_tests/base58.cpp index d55c9a74..33e209fc 100644 --- a/tests/unit_tests/base58.cpp +++ b/tests/unit_tests/base58.cpp @@ -551,3 +551,103 @@ TEST(integ_address, payment_id_sizes) ASSERT_NE(addr2, addr); ASSERT_NE(integrated_payment_id, payment_id); } + + +struct addr_entry_t +{ + std::string address; + std::string view_pub_key; + std::string spend_pub_key; + std::string payment_id_hex; + uint8_t flags; +}; + +addr_entry_t addr_entries[] = + { + { + // classic normal address + "ZxD5aoLDPTdcaRx4uCpyW4XiLfEXejepAVz8cSY2fwHNEiJNu6NmpBBDLGTJzCsUvn3acCVDVDPMV8yQXdPooAp338Se7AxeH", // address + "a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key + "9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key + "", // payment_id_hex + 0 // flags + }, + { + // classic integrated address + "iZ2Zi6RmTWwcaRx4uCpyW4XiLfEXejepAVz8cSY2fwHNEiJNu6NmpBBDLGTJzCsUvn3acCVDVDPMV8yQXdPooAp3iTqEsjvJoco1aLSZXS6T", // address + "a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key + "9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key + "87440d0b9acc42f1", // payment_id_hex + 0 // flags + }, + { + // new format normal address with custom flags + "ZxD5aoLDPTdcaRx4uCpyW4XiLfEXejepAVz8cSY2fwHNEiJNu6NmpBBDLGTJzCsUvn3acCVDVDPMV8yQXdPooAp3APrDvRoL5C", // address + "a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key + "9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key + "", // payment_id_hex + 0xfe // flags + }, + { + // new format integrated address with custom flags + "iZ4mBxubNfqcaRx4uCpyW4XiLfEXejepAVz8cSY2fwHNEiJNu6NmpBBDLGTJzCsUvn3acCVDVDPMV8yQXdPooAp3iTrG7nU5rRCWmcozLaMoY95sAbo6", // address + "a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key + "9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key + "3ba0527bcfb1fa93630d28eed6", // payment_id + 0xfe // flags + }, + { + // normal auditable address + "aZxb9Et6FhP9AinRwcPqSqBKjckre7PgoZjK3q5YG2fUKHYWFZMWjB6YAEAdw4yDDUGEQ7CGEgbqhGRKeadGV1jLYcEJMEmqQFn", // address + "a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key + "9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key + "", // payment_id + ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE // flags + }, + { + // auditable integrated address + "aiZXDondHWu9AinRwcPqSqBKjckre7PgoZjK3q5YG2fUKHYWFZMWjB6YAEAdw4yDDUGEQ7CGEgbqhGRKeadGV1jLYcEJM9xJH8EbjuRiMJgFmPRATsEV9", // address + "a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key + "9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key + "3ba0527bcfb1fa93630d28eed6", // payment_id + ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE // flags + } + }; + +void check_add_entry(const addr_entry_t& ae) +{ + std::string payment_id, payment_id_hex; + currency::account_public_address addr = AUTO_VAL_INIT(addr); + + ASSERT_TRUE(currency::get_account_address_and_payment_id_from_str(addr, payment_id, ae.address)); + payment_id_hex = epee::string_tools::buff_to_hex_nodelimer(payment_id); + + ASSERT_EQ(ae.flags, addr.flags); + ASSERT_EQ(ae.payment_id_hex, payment_id_hex); + ASSERT_EQ(ae.view_pub_key, epee::string_tools::pod_to_hex(addr.view_public_key)); + ASSERT_EQ(ae.spend_pub_key, epee::string_tools::pod_to_hex(addr.spend_public_key)); +} + +TEST(auditable_addresses, basic) +{ + /* + currency::account_keys keys = AUTO_VAL_INIT(keys); + epee::string_tools::parse_tpod_from_hex_string("248b019d145d485576ecb0367d92b5a12e8aa15084b59ef15014a7a22d1f3b0c", keys.spend_secret_key); + dependent_key(keys.spend_secret_key, keys.view_secret_key); + crypto::secret_key_to_public_key(keys.view_secret_key, keys.account_address.view_public_key); + crypto::secret_key_to_public_key(keys.spend_secret_key, keys.account_address.spend_public_key); + + keys.account_address.flags = 0xfe; + + std::string payment_id; + epee::string_tools::parse_hexstr_to_binbuff(std::string("3ba0527bcfb1fa93630d28eed6"), payment_id); + + std::cout << currency::get_account_address_as_str(keys.account_address) << " " << epee::string_tools::pod_to_hex(keys.account_address.view_public_key) << " " << epee::string_tools::pod_to_hex(keys.account_address.spend_public_key) << ENDL; + std::cout << currency::get_account_address_and_payment_id_as_str(keys.account_address, payment_id) << " " << epee::string_tools::pod_to_hex(keys.account_address.view_public_key) << " " << epee::string_tools::pod_to_hex(keys.account_address.spend_public_key) << ENDL; + */ + + + for (size_t i = 0; i < sizeof addr_entries / sizeof addr_entries[0]; ++i) + check_add_entry(addr_entries[i]); + +} From b9569ce89b970e47b8240aa3d05a2e6569adef6b Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 1 May 2020 12:56:09 +0300 Subject: [PATCH 18/70] extra_alias_entry/extra_alias_entry_old fixes, all types added to payload_items and compiles ok --- src/currency_core/currency_basic.h | 34 ++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index da8291dc..f1f79d05 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -398,6 +398,15 @@ namespace currency struct extra_alias_entry_base { + extra_alias_entry_base() = default; + extra_alias_entry_base(const extra_alias_entry_base_old& old) + : m_address(account_public_address::from_old(old.m_address)) + , m_text_comment(old.m_text_comment) + , m_view_key(old.m_view_key) + , m_sign(old.m_sign) + { + } + account_public_address m_address; std::string m_text_comment; std::vector m_view_key; // only one or zero elments expected (std::vector is using as memory efficient container for such a case) @@ -413,12 +422,29 @@ namespace currency struct extra_alias_entry : public extra_alias_entry_base { + extra_alias_entry() = default; + extra_alias_entry(const extra_alias_entry_old& old) + : extra_alias_entry_base(old) + , m_alias(old.m_alias) + {} + std::string m_alias; BEGIN_SERIALIZE() FIELD(m_alias) FIELDS(*static_cast(this)) - END_SERIALIZE() + END_SERIALIZE() + + extra_alias_entry_old to_old() const + { + extra_alias_entry_old result = AUTO_VAL_INIT(result); + result.m_address = m_address.to_old(); + result.m_text_comment = m_text_comment; + result.m_view_key = m_view_key; + result.m_sign = m_sign; + result.m_alias = m_alias; + return result; + } }; @@ -487,10 +513,10 @@ namespace currency END_SERIALIZE() }; - typedef boost::mpl::vector20< + typedef boost::mpl::vector21< tx_service_attachment, tx_comment, tx_payer_old, tx_receiver_old, tx_derivation_hint, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time, - etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry, extra_user_data, extra_padding, etc_tx_uint16_t, etc_tx_details_unlock_time2 - , tx_payer, tx_receiver//, extra_alias_entry + etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry_old, extra_user_data, extra_padding, etc_tx_uint16_t, etc_tx_details_unlock_time2, + tx_payer, tx_receiver, extra_alias_entry > all_payload_types; typedef boost::make_variant_over::type payload_items_v; From 599558ef9b60cf349ea0a7db5f446165c9f9d928 Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 2 May 2020 23:56:12 +0300 Subject: [PATCH 19/70] minor improvements --- src/common/mnemonic-encoding.cpp | 7 +++---- src/common/mnemonic-encoding.h | 2 ++ src/wallet/wallet_errors.h | 12 ++++++++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/common/mnemonic-encoding.cpp b/src/common/mnemonic-encoding.cpp index e5f46641..b5a22c24 100644 --- a/src/common/mnemonic-encoding.cpp +++ b/src/common/mnemonic-encoding.cpp @@ -48,8 +48,6 @@ namespace tools { using namespace std; - const int NUMWORDS = 1626; - const map wordsMap = { {"like", 0}, {"just", 1}, @@ -3358,7 +3356,7 @@ namespace tools throw runtime_error("Invalid binary data size for mnemonic encoding"); // 4 bytes -> 3 words. 8 digits base 16 -> 3 digits base 1626 string res; - for (unsigned int i=0; i < binary.size() / 4; i++, res += ' ') + for (unsigned int i=0; i < binary.size() / 4; i++) { const uint32_t* val = reinterpret_cast(&binary[i * 4]); @@ -3369,8 +3367,9 @@ namespace tools res += wordsArray[w1] + " "; res += wordsArray[w2] + " "; - res += wordsArray[w3]; + res += wordsArray[w3] + " "; } + res.erase(--res.end()); // remove trailing space return res; } std::string word_by_num(uint32_t n) diff --git a/src/common/mnemonic-encoding.h b/src/common/mnemonic-encoding.h index 409a935b..2e92ffa4 100644 --- a/src/common/mnemonic-encoding.h +++ b/src/common/mnemonic-encoding.h @@ -40,6 +40,8 @@ namespace tools { namespace mnemonic_encoding { + constexpr int NUMWORDS = 1626; + std::vector text2binary(const std::string& text); std::string binary2text(const std::vector& binary); std::string word_by_num(uint32_t n); diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 1430b35d..a0b9834e 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -68,6 +68,12 @@ namespace tools return ss.str(); } + virtual char const* what() const + { + m_what = to_string(); + return m_what.c_str(); + } + protected: wallet_error_base(std::string&& loc, const std::string& message) : Base(message) @@ -77,6 +83,7 @@ namespace tools private: std::string m_loc; + mutable std::string m_what; }; //---------------------------------------------------------------------------------------------------- const char* const failed_rpc_request_messages[] = { @@ -113,8 +120,9 @@ namespace tools std::string m_status; }; //---------------------------------------------------------------------------------------------------- - typedef wallet_error_base wallet_logic_error; - typedef wallet_error_base wallet_runtime_error; + typedef wallet_error_base wallet_error; + typedef wallet_error wallet_logic_error; + typedef wallet_error wallet_runtime_error; //---------------------------------------------------------------------------------------------------- struct wallet_internal_error : public wallet_runtime_error { From 1441b5b27f343b83f8d10b992025119418b38039 Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 2 May 2020 23:59:37 +0300 Subject: [PATCH 20/70] seed phase improvements: 26 words + checksum + auditable wallets support --- src/crypto/crypto.cpp | 51 ++++--- src/crypto/crypto.h | 21 ++- src/currency_core/account.cpp | 142 +++++++++++++------- src/currency_core/account.h | 20 +-- src/currency_core/currency_basic.h | 3 +- src/currency_core/currency_format_utils.cpp | 2 +- src/simplewallet/simplewallet.cpp | 40 +++--- src/simplewallet/simplewallet.h | 3 +- src/wallet/wallet2.cpp | 4 +- src/wallet/wallet2.h | 2 +- src/wallet/wallets_manager.cpp | 2 +- 11 files changed, 168 insertions(+), 122 deletions(-) diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index eba65c8c..ec93366d 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -85,34 +85,31 @@ namespace crypto { memcpy(&res, tmp, 32); } - void crypto_ops::keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size) - { - unsigned char tmp[64] = { 0 }; - - if (!(sizeof(tmp) >= brain_wallet_seed_size)) - { - throw std::runtime_error("size mismatch"); - } - - memcpy(tmp, a_part, brain_wallet_seed_size); - - cn_fast_hash(tmp, 32, (char*)&tmp[32]); - - sc_reduce(tmp); - memcpy(&sec, tmp, 32); - ge_p3 point; - ge_scalarmult_base(&point, &sec); - ge_p3_tobytes(&pub, &point); - } - - void crypto_ops::generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed, size_t brain_wallet_seed_size) + void crypto_ops::keys_from_default(const unsigned char* a_part, public_key &pub, secret_key &sec, size_t keys_seed_binary_size) { - std::vector tmp_vector; - tmp_vector.resize(brain_wallet_seed_size, 0); - unsigned char *tmp = &tmp_vector[0]; - generate_random_bytes(brain_wallet_seed_size, tmp); - seed.assign((const char*)tmp, brain_wallet_seed_size); - keys_from_default(tmp, pub, sec, brain_wallet_seed_size); + unsigned char tmp[64] = { 0 }; + + if (!(sizeof(tmp) >= keys_seed_binary_size)) + { + throw std::runtime_error("size mismatch"); + } + + memcpy(tmp, a_part, keys_seed_binary_size); + + cn_fast_hash(tmp, 32, (char*)&tmp[32]); + + sc_reduce(tmp); + memcpy(&sec, tmp, 32); + ge_p3 point; + ge_scalarmult_base(&point, &sec); + ge_p3_tobytes(&pub, &point); + } + + void crypto_ops::generate_seed_keys(public_key &pub, secret_key &sec, std::vector& keys_seed_binary, size_t keys_seed_binary_size) + { + keys_seed_binary.resize(keys_seed_binary_size, 0); + generate_random_bytes(keys_seed_binary_size, keys_seed_binary.data()); + keys_from_default(keys_seed_binary.data(), pub, sec, keys_seed_binary_size); } static inline void hash_to_scalar(const void *data, size_t length, ec_scalar &res) diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index e7b2da6a..f6a3aebf 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -74,10 +74,10 @@ namespace crypto { static void generate_keys(public_key &, secret_key &); friend void generate_keys(public_key &, secret_key &); - static void generate_brain_keys(public_key &, secret_key &, std::string& seed, size_t brain_wallet_seed_size); - friend void generate_brain_keys(public_key &, secret_key &, std::string& seed, size_t brain_wallet_seed_size); - static void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size); - friend void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size); + static void generate_seed_keys(public_key &pub, secret_key &sec, std::vector& keys_seed_binary, size_t keys_seed_binary_size); + friend void generate_seed_keys(public_key &pub, secret_key &sec, std::vector& keys_seed_binary, size_t keys_seed_binary_size); + static void keys_from_default(const unsigned char* a_part, public_key &pub, secret_key &sec, size_t keys_seed_binary_size); + friend void keys_from_default(const unsigned char* a_part, public_key &pub, secret_key &sec, size_t keys_seed_binary_size); static void dependent_key(const secret_key& first, secret_key& second); friend void dependent_key(const secret_key& first, secret_key& second); static bool check_key(const public_key &); @@ -136,14 +136,14 @@ namespace crypto { crypto_ops::generate_keys(pub, sec); } - inline void generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed, size_t brain_wallet_seed_size) { - crypto_ops::generate_brain_keys(pub, sec, seed, brain_wallet_seed_size); + inline void generate_seed_keys(public_key &pub, secret_key &sec, std::vector& keys_seed_binary, size_t keys_seed_binary_size) + { + crypto_ops::generate_seed_keys(pub, sec, keys_seed_binary, keys_seed_binary_size); } - - inline void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size) + inline void keys_from_default(const unsigned char* a_part, public_key &pub, secret_key &sec, size_t keys_seed_binary_size) { - crypto_ops::keys_from_default(a_part, pub, sec, brain_wallet_seed_size); + crypto_ops::keys_from_default(a_part, pub, sec, keys_seed_binary_size); } inline void dependent_key(const secret_key& first, secret_key& second){ @@ -290,8 +290,7 @@ namespace crypto { bool m_ready; }; -} - +} // namespace crypto POD_MAKE_HASHABLE(crypto, public_key) POD_MAKE_COMPARABLE(crypto, secret_key) diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 543338ed..d732bd62 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -17,15 +17,10 @@ using namespace std; -DISABLE_VS_WARNINGS(4244 4345) - - +//DISABLE_VS_WARNINGS(4244 4345) namespace currency { - - - //----------------------------------------------------------------- account_base::account_base() { @@ -37,18 +32,22 @@ namespace currency // fill sensitive data with random bytes crypto::generate_random_bytes(sizeof m_keys.spend_secret_key, &m_keys.spend_secret_key); crypto::generate_random_bytes(sizeof m_keys.view_secret_key, &m_keys.view_secret_key); - crypto::generate_random_bytes(m_seed.size(), &m_seed[0]); + if (m_keys_seed_binary.size()) + crypto::generate_random_bytes(m_keys_seed_binary.size(), &m_keys_seed_binary[0]); // clear m_keys = account_keys(); m_creation_timestamp = 0; - m_seed.clear(); + m_keys_seed_binary.clear(); } //----------------------------------------------------------------- - void account_base::generate() + void account_base::generate(bool auditable /* = false */) { - generate_brain_keys(m_keys.account_address.spend_public_key, m_keys.spend_secret_key, m_seed, BRAINWALLET_DEFAULT_SEED_SIZE); - dependent_key(m_keys.spend_secret_key, m_keys.view_secret_key); + if (auditable) + m_keys.account_address.flags = ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE; + + crypto::generate_seed_keys(m_keys.account_address.spend_public_key, m_keys.spend_secret_key, m_keys_seed_binary, BRAINWALLET_DEFAULT_SEED_SIZE); + crypto::dependent_key(m_keys.spend_secret_key, m_keys.view_secret_key); if (!crypto::secret_key_to_public_key(m_keys.view_secret_key, m_keys.account_address.view_public_key)) throw std::runtime_error("Failed to create public view key"); @@ -61,65 +60,108 @@ namespace currency return m_keys; } //----------------------------------------------------------------- - std::string account_base::get_restore_data() const - { - return m_seed; - } - //----------------------------------------------------------------- - std::string account_base::get_restore_braindata() const { - std::string restore_buff = get_restore_data(); - if (restore_buff.empty()) + if (m_keys_seed_binary.empty()) return ""; - std::vector v; - v.assign((unsigned char*)restore_buff.data(), (unsigned char*)restore_buff.data() + restore_buff.size()); - std::string seed_brain_data = tools::mnemonic_encoding::binary2text(v); + std::string keys_seed_text = tools::mnemonic_encoding::binary2text(m_keys_seed_binary); std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp); - seed_brain_data = seed_brain_data + timestamp_word; - return seed_brain_data; + + // floor creation time to WALLET_BRAIN_DATE_QUANTUM to make checksum calculation stable + uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word); + + constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum + crypto::hash h = crypto::cn_fast_hash(m_keys_seed_binary.data(), m_keys_seed_binary.size()); + *reinterpret_cast(&h) = creation_timestamp_rounded; + h = crypto::cn_fast_hash(&h, sizeof h); + uint64_t h_64 = *reinterpret_cast(&h); + uint16_t checksum = h_64 % (checksum_max + 1); + + uint8_t auditable_flag = 0; + if (m_keys.account_address.flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE) + auditable_flag = 1; + + uint64_t auditable_flag_and_checksum = (auditable_flag & 1) | (checksum << 1); + std::string auditable_flag_and_checksum_word = tools::mnemonic_encoding::word_by_num(auditable_flag_and_checksum); + + return keys_seed_text + " " + timestamp_word + " " + auditable_flag_and_checksum_word; } //----------------------------------------------------------------- - bool account_base::restore_keys(const std::string& restore_data) + bool account_base::restore_keys(const std::vector& keys_seed_binary) { - //CHECK_AND_ASSERT_MES(restore_data.size() == ACCOUNT_RESTORE_DATA_SIZE, false, "wrong restore data size"); - if (restore_data.size() == BRAINWALLET_DEFAULT_SEED_SIZE) - { - crypto::keys_from_default((unsigned char*)restore_data.data(), m_keys.account_address.spend_public_key, m_keys.spend_secret_key, BRAINWALLET_DEFAULT_SEED_SIZE); - } - else - { - LOG_ERROR("wrong restore data size=" << restore_data.size()); - return false; - } - m_seed = restore_data; + CHECK_AND_ASSERT_MES(keys_seed_binary.size() == BRAINWALLET_DEFAULT_SEED_SIZE, false, "wrong restore data size: " << keys_seed_binary.size()); + crypto::keys_from_default(keys_seed_binary.data(), m_keys.account_address.spend_public_key, m_keys.spend_secret_key, keys_seed_binary.size()); crypto::dependent_key(m_keys.spend_secret_key, m_keys.view_secret_key); bool r = crypto::secret_key_to_public_key(m_keys.view_secret_key, m_keys.account_address.view_public_key); CHECK_AND_ASSERT_MES(r, false, "failed to secret_key_to_public_key for view key"); - set_createtime(0); return true; } //----------------------------------------------------------------- - bool account_base::restore_keys_from_braindata(const std::string& restore_data_) + bool account_base::restore_keys_from_braindata(const std::string& seed_phrase) { //cut the last timestamp word from restore_dats std::list words; - boost::split(words, restore_data_, boost::is_space()); - CHECK_AND_ASSERT_MES(words.size() == BRAINWALLET_DEFAULT_WORDS_COUNT, false, "Words count missmatch: " << words.size()); - - std::string timestamp_word = words.back(); - words.erase(--words.end()); - - std::string restore_data_local = boost::algorithm::join(words, " "); + boost::split(words, seed_phrase, boost::is_space()); - std::vector bin = tools::mnemonic_encoding::text2binary(restore_data_local); - if (!bin.size()) + std::string keys_seed_text, timestamp_word, auditable_flag_and_checksum_word; + if (words.size() == SEED_PHRASE_V1_WORDS_COUNT) + { + // 24 seed words + one timestamp word = 25 total + timestamp_word = words.back(); + words.erase(--words.end()); + keys_seed_text = boost::algorithm::join(words, " "); + } + else if (words.size() == SEED_PHRASE_V2_WORDS_COUNT) + { + // 24 seed words + one timestamp word + one flags & checksum = 26 total + auditable_flag_and_checksum_word = words.back(); + words.erase(--words.end()); + timestamp_word = words.back(); + words.erase(--words.end()); + keys_seed_text = boost::algorithm::join(words, " "); + } + else + { + LOG_ERROR("Invalid seed words count: " << words.size()); return false; + } + + uint64_t auditable_flag_and_checksum = 0; + try + { + auditable_flag_and_checksum = tools::mnemonic_encoding::num_by_word(auditable_flag_and_checksum_word); + } + catch(...) + { + LOG_ERROR("cannot convert seed word: " << auditable_flag_and_checksum_word); + return false; + } + + bool auditable_flag = (auditable_flag_and_checksum & 1) != 0; // auditable flag is the lower 1 bit + uint16_t checksum = auditable_flag_and_checksum >> 1; // checksum -- everything else + constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum + + std::vector keys_seed_binary = tools::mnemonic_encoding::text2binary(keys_seed_text); + CHECK_AND_ASSERT_MES(keys_seed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security - std::string restore_buff((const char*)&bin[0], bin.size()); - bool r = restore_keys(restore_buff); - CHECK_AND_ASSERT_MES(r, false, "restore_keys failed"); m_creation_timestamp = get_timstamp_from_word(timestamp_word); + + // check the checksum + crypto::hash h = crypto::cn_fast_hash(keys_seed_binary.data(), keys_seed_binary.size()); + *reinterpret_cast(&h) = m_creation_timestamp; + h = crypto::cn_fast_hash(&h, sizeof h); + uint64_t h_64 = *reinterpret_cast(&h); + uint16_t checksum_calculated = h_64 % (checksum_max + 1); + CHECK_AND_ASSERT_MES(checksum == checksum_calculated, false, "seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words"); + + bool r = restore_keys(keys_seed_binary); + CHECK_AND_ASSERT_MES(r, false, "restore_keys failed"); + + m_keys_seed_binary = keys_seed_binary; + + if (auditable_flag) + m_keys.account_address.flags |= ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE; + return true; } //----------------------------------------------------------------- diff --git a/src/currency_core/account.h b/src/currency_core/account.h index 0a049a89..64e9340e 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -12,7 +12,8 @@ #define BRAINWALLET_DEFAULT_SEED_SIZE 32 #define ACCOUNT_RESTORE_DATA_SIZE BRAINWALLET_DEFAULT_SEED_SIZE -#define BRAINWALLET_DEFAULT_WORDS_COUNT 25 +#define SEED_PHRASE_V1_WORDS_COUNT 25 +#define SEED_PHRASE_V2_WORDS_COUNT 26 @@ -47,15 +48,13 @@ namespace currency { public: account_base(); - void generate(); + void generate(bool auditable = false); const account_keys& get_keys() const; const account_public_address& get_public_address() const { return m_keys.account_address; }; std::string get_public_address_str() const; - std::string get_restore_data() const; + std::string get_restore_braindata() const; - - bool restore_keys(const std::string& restore_data); - bool restore_keys_from_braindata(const std::string& restore_data); + bool restore_keys_from_braindata(const std::string& seed_phrase); uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } @@ -70,20 +69,23 @@ namespace currency { a & m_keys; a & m_creation_timestamp; - a & m_seed; + a & m_keys_seed_binary; } BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_keys) KV_SERIALIZE(m_creation_timestamp) - KV_SERIALIZE(m_seed) + KV_SERIALIZE(m_keys_seed_binary) END_KV_SERIALIZE_MAP() private: void set_null(); + bool restore_keys(const std::vector& keys_seed_binary); + account_keys m_keys; uint64_t m_creation_timestamp; - std::string m_seed; + + std::vector m_keys_seed_binary; }; diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index f1f79d05..93d5f63d 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -426,7 +426,8 @@ namespace currency extra_alias_entry(const extra_alias_entry_old& old) : extra_alias_entry_base(old) , m_alias(old.m_alias) - {} + { + } std::string m_alias; diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 390d1b6d..b3247fce 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -1251,7 +1251,7 @@ namespace currency { uint64_t date_offset = timestamp > WALLET_BRAIN_DATE_OFFSET ? timestamp - WALLET_BRAIN_DATE_OFFSET : 0; uint64_t weeks_count = date_offset / WALLET_BRAIN_DATE_QUANTUM; - CHECK_AND_ASSERT_THROW_MES(weeks_count < std::numeric_limits::max(), "internal error: unable to converto to uint32, val = " << weeks_count); + CHECK_AND_ASSERT_THROW_MES(weeks_count < std::numeric_limits::max(), "internal error: unable to convert to uint32, val = " << weeks_count); uint32_t weeks_count_32 = static_cast(weeks_count); return tools::mnemonic_encoding::word_by_num(weeks_count_32); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 65cdba9e..e76bad79 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -40,6 +40,7 @@ namespace { const command_line::arg_descriptor arg_wallet_file = {"wallet-file", "Use wallet ", ""}; const command_line::arg_descriptor arg_generate_new_wallet = {"generate-new-wallet", "Generate new wallet and save it to or
.wallet by default", ""}; + const command_line::arg_descriptor arg_generate_new_auditable_wallet = {"generate-new-auditable-wallet", "Generate new auditable wallet and store it to ", ""}; const command_line::arg_descriptor arg_daemon_address = {"daemon-address", "Use daemon instance at :", ""}; const command_line::arg_descriptor arg_daemon_host = {"daemon-host", "Use daemon instance at host instead of localhost", ""}; const command_line::arg_descriptor arg_password = {"password", "Wallet password", "", true}; @@ -270,9 +271,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } - if (m_wallet_file.empty() && m_generate_new.empty() && m_restore_wallet.empty()) + if (m_wallet_file.empty() && m_generate_new.empty() && m_restore_wallet.empty() && m_generate_new_aw.empty()) { - fail_msg_writer() << "you must specify --wallet-file, --generate-new-wallet or --restore-wallet"; + fail_msg_writer() << "you must specify --wallet-file, --generate-new-wallet, --generate-new-auditable-wallet or --restore-wallet"; return false; } @@ -311,9 +312,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!m_generate_new.empty()) { - bool r = new_wallet(m_generate_new, pwd_container.password()); - CHECK_AND_ASSERT_MES(r, false, "account creation failed"); - + bool r = new_wallet(m_generate_new, pwd_container.password(), false); + CHECK_AND_ASSERT_MES(r, false, "failed to create new wallet"); + } + else if (!m_generate_new_aw.empty()) + { + bool r = new_wallet(m_generate_new_aw, pwd_container.password(), true); + CHECK_AND_ASSERT_MES(r, false, "failed to create new auditable wallet"); } else if (!m_restore_wallet.empty()) { @@ -354,6 +359,7 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_ { m_wallet_file = command_line::get_arg(vm, arg_wallet_file); m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet); + m_generate_new_aw = command_line::get_arg(vm, arg_generate_new_auditable_wallet); m_daemon_address = command_line::get_arg(vm, arg_daemon_address); m_daemon_host = command_line::get_arg(vm, arg_daemon_host); m_daemon_port = command_line::get_arg(vm, arg_daemon_port); @@ -374,7 +380,7 @@ bool simple_wallet::try_connect_to_daemon() return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password) +bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password, bool create_auditable_wallet) { m_wallet_file = wallet_file; @@ -383,10 +389,10 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas m_wallet->set_do_rise_transfer(false); try { - m_wallet->generate(epee::string_encoding::utf8_to_wstring(m_wallet_file), password); - message_writer(epee::log_space::console_color_white, true) << "Generated new wallet: " << m_wallet->get_account().get_public_address_str(); + 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(); std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush; - if(m_do_not_set_date) + if (m_do_not_set_date) m_wallet->reset_creation_time(0); if (m_print_brain_wallet) @@ -407,11 +413,6 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas success_msg_writer() << "**********************************************************************\n" << "Your wallet has been generated.\n" << - "To start synchronizing with the daemon use \"refresh\" command.\n" << - "Use \"help\" command to see the list of available commands.\n" << - "Always use \"exit\" command when closing simplewallet to save\n" << - "current session's state. Otherwise, you will possibly need to synchronize \n" << - "your wallet again. Your wallet key is NOT under risk anyway.\n" << "**********************************************************************"; return true; } @@ -433,7 +434,7 @@ bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::st } catch (const std::exception& e) { - fail_msg_writer() << "failed to restore wallet: " << e.what(); + fail_msg_writer() << "failed to restore wallet, check your seed phrase!" << ENDL << e.what(); return false; } @@ -1322,7 +1323,7 @@ bool simple_wallet::print_address(const std::vector &args/* = std:: bool simple_wallet::show_seed(const std::vector &args) { success_msg_writer() << "Here's your wallet's seed phrase. Write it down and keep in a safe place."; - success_msg_writer(true) << "Anyone who knows the following 25 words can access your wallet:"; + success_msg_writer(true) << "Anyone who knows the following 26 words can access your wallet:"; std::cout << m_wallet->get_account().get_restore_braindata() << std::endl << std::flush; return true; } @@ -1693,6 +1694,8 @@ int main(int argc, char* argv[]) const char* const* argv = argv_vec.data(); #endif + epee::debug::get_set_enable_assert(true, false); + string_tools::set_module_name_and_folder(argv[0]); po::options_description desc_general("General options"); @@ -1702,6 +1705,7 @@ int main(int argc, char* argv[]) po::options_description desc_params("Wallet options"); command_line::add_arg(desc_params, arg_wallet_file); command_line::add_arg(desc_params, arg_generate_new_wallet); + command_line::add_arg(desc_params, arg_generate_new_auditable_wallet); command_line::add_arg(desc_params, arg_password); command_line::add_arg(desc_params, arg_daemon_address); command_line::add_arg(desc_params, arg_daemon_host); @@ -1848,7 +1852,7 @@ int main(int argc, char* argv[]) { LOG_PRINT_L0("Initializing wallet..."); wal.init(daemon_address); - if (command_line::get_arg(vm, arg_generate_new_wallet).size()) + 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; if (!offline_mode) @@ -1903,7 +1907,7 @@ int main(int argc, char* argv[]) sw->set_offline_mode(offline_mode); r = sw->init(vm); CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet"); - if (command_line::get_arg(vm, arg_generate_new_wallet).size()) + 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; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 8c57697b..c1ea6d04 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -44,7 +44,7 @@ namespace currency bool run_console_handler(); - bool new_wallet(const std::string &wallet_file, const std::string& password); + bool new_wallet(const std::string &wallet_file, const std::string& password, bool create_auditable_wallet); bool open_wallet(const std::string &wallet_file, const std::string& password); bool restore_wallet(const std::string &wallet_file, const std::string &restore_seed, const std::string& password); bool close_wallet(); @@ -153,6 +153,7 @@ namespace currency private: std::string m_wallet_file; std::string m_generate_new; + std::string m_generate_new_aw; std::string m_import_path; std::string m_daemon_address; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0d74da26..5477153f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1997,7 +1997,7 @@ void wallet2::assign_account(const currency::account_base& acc) init_log_prefix(); } //---------------------------------------------------------------------------------------------------- -void wallet2::generate(const std::wstring& path, const std::string& pass) +void wallet2::generate(const std::wstring& path, const std::string& pass, bool auditable_wallet) { WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(validate_password(pass), "new wallet generation failed: password contains forbidden characters") clear(); @@ -2006,7 +2006,7 @@ void wallet2::generate(const std::wstring& path, const std::string& pass) check_for_free_space_and_throw_if_it_lacks(m_wallet_file); m_password = pass; - m_account.generate(); + m_account.generate(auditable_wallet); init_log_prefix(); boost::system::error_code ignored_ec; THROW_IF_TRUE_WALLET_EX(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file)); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 4e3daada..0f258c03 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -449,7 +449,7 @@ namespace tools END_SERIALIZE() }; void assign_account(const currency::account_base& acc); - void generate(const std::wstring& path, const std::string& password); + void generate(const std::wstring& path, const std::string& password, bool auditable_wallet); void restore(const std::wstring& path, const std::string& pass, const std::string& restore_key); void load(const std::wstring& path, const std::string& password); void store(); diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 4e6c92e3..9b921be8 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -840,7 +840,7 @@ std::string wallets_manager::generate_wallet(const std::wstring& path, const std try { - w->generate(path, password); + w->generate(path, password, false); owr.seed = w->get_account().get_restore_braindata(); } catch (const tools::error::file_exists&) From a11bdf39f2c6f229f805c729be38bab8640d2b8c Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 4 May 2020 14:57:29 +0300 Subject: [PATCH 21/70] wallet2: correct using of extra_alias_entry / extra_alias_entry_old --- src/wallet/wallet2.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 5477153f..637d0b3a 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3050,7 +3050,11 @@ void wallet2::request_alias_registration(const currency::extra_alias_entry& ai, std::vector destinations; std::vector extra; std::vector attachments; - extra.push_back(ai); + + if (get_top_block_height() > m_core_runtime_config.hard_fork_02_starts_after_height) + extra.push_back(ai); + else + extra.push_back(ai.to_old()); currency::tx_destination_entry tx_dest_alias_reward; tx_dest_alias_reward.addr.resize(1); @@ -3080,7 +3084,12 @@ void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::tr std::vector destinations; std::vector extra; std::vector attachments; - extra.push_back(ai); + + if (get_top_block_height() > m_core_runtime_config.hard_fork_02_starts_after_height) + extra.push_back(ai); + else + extra.push_back(ai.to_old()); + transfer(destinations, 0, 0, fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false); } //---------------------------------------------------------------------------------------------------- From a41d73cf8e1c75f26d3cb9d681c985fea6b36a4f Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 7 May 2020 14:57:45 +0300 Subject: [PATCH 22/70] serialization fixes from predevelop --- src/currency_core/account.h | 6 +++--- src/currency_core/currency_basic.h | 9 ++------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/currency_core/account.h b/src/currency_core/account.h index 64e9340e..01134418 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -35,9 +35,9 @@ namespace currency crypto::secret_key view_secret_key; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(account_address) - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(spend_secret_key) - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(view_secret_key) + KV_SERIALIZE_N(account_address, "m_account_address") + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(spend_secret_key, "m_spend_secret_key") + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(view_secret_key, "m_view_secret_key") END_KV_SERIALIZE_MAP() }; diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 93d5f63d..8c7c9b2e 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -71,8 +71,8 @@ namespace currency END_SERIALIZE() BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(spend_public_key) - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(view_public_key) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(spend_public_key, "m_spend_public_key") + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(view_public_key, "m_view_public_key") END_KV_SERIALIZE_MAP() }; #pragma pack(pop) @@ -88,23 +88,18 @@ namespace currency { crypto::public_key spend_public_key; crypto::public_key view_public_key; - //uint8_t version; uint8_t flags; DEFINE_SERIALIZATION_VERSION(ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) BEGIN_SERIALIZE_OBJECT() FIELD(spend_public_key) FIELD(view_public_key) - //VERSION_ENTRY(version) FIELD(flags) - //if (version > ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER) - // return true; // backward compartibility END_SERIALIZE() BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(spend_public_key) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(view_public_key) - //KV_SERIALIZE(version) // is it necessary? KV_SERIALIZE(flags) END_KV_SERIALIZE_MAP() From 3701b138b69e27bce4f899ca8799c36749a2f091 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 7 May 2020 15:01:01 +0300 Subject: [PATCH 23/70] unit_tests: wallet_seed.basic_test added, exposes a bug --- tests/unit_tests/brain_wallet_test.cpp | 141 ++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 4 deletions(-) diff --git a/tests/unit_tests/brain_wallet_test.cpp b/tests/unit_tests/brain_wallet_test.cpp index 70fc6e7a..1336f6dd 100644 --- a/tests/unit_tests/brain_wallet_test.cpp +++ b/tests/unit_tests/brain_wallet_test.cpp @@ -13,10 +13,10 @@ TEST(brain_wallet, store_restore_test) { currency::account_base acc; acc.generate(); - auto restore_data = acc.get_restore_data(); + auto seed_phrase = acc.get_restore_braindata(); currency::account_base acc2; - bool r = acc2.restore_keys(restore_data); + bool r = acc2.restore_from_braindata(seed_phrase); ASSERT_TRUE(r); if (memcmp(&acc2.get_keys(), &acc.get_keys(), sizeof(currency::account_keys))) @@ -29,10 +29,10 @@ TEST(brain_wallet, store_restore_test) { currency::account_base acc; acc.generate(); - auto restore_data = acc.get_restore_braindata(); + auto seed_phrase = acc.get_restore_braindata(); currency::account_base acc2; - bool r = acc2.restore_keys_from_braindata(restore_data); + bool r = acc2.restore_from_braindata(seed_phrase); ASSERT_TRUE(r); if (memcmp(&acc2.get_keys(), &acc.get_keys(), sizeof(currency::account_keys))) @@ -42,3 +42,136 @@ TEST(brain_wallet, store_restore_test) } } + +struct wallet_seed_entry +{ + std::string seed_phrase; + std::string spend_secret_key; + std::string view_secret_key; + uint64_t timestamp; + bool auditable; + bool valid; +}; + +wallet_seed_entry wallet_seed_entries[] = +{ + { + // legacy 24-word seed phrase -- invalid + "dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew", + "", + "", + 0, + false, + false + }, + { + // old-style 25-word seed phrase -- valid + "dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew", + "5e051454d7226b5734ebd64f754b57db4c655ecda00bd324f1b241d0b6381c0f", + "7dde5590fdf430568c00556ac2accf09da6cde9a29a4bc7d1cb6fd267130f006", + 0, + false, + true + }, + { + // old-style 25-word seed phrase -- valid + "conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation", + "71162f207499bc16260957c36a6586bb931d54be33ff56b94d565dfedbb3c70e", + "8454372096986c457f4e7dceef2f39b6050c35d87b31d9c9eb8d37bf8f1f430f", + 0, + false, + true + }, + { + // old-style 25-word seed phrase -- invalid word + "dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew!", + "", + "", + 0, + false, + false + }, + { + // old-style 25-word seed phrase -- invalid word + "six six six six six six six six six sex six six six six six six six six six six six six six six six", + "", + "", + 0, + false, + false + }, + { + // new-style 26-word seed phrase -- invalid word + "six six six six six six six six six six six six six six six six six six six six six six six six six sex", + "", + "", + 0, + false, + false + }, + { + // new-style 26-word seed phrase -- invalid checksum + "six six six six six six six six six six six six six six six six six six six six six six six six six six", + "", + "", + 0, + false, + false + }, + { + // new-style 26-word seed phrase - valid + "six six six six six six six six six six six six six six six six six six six six six six six six six frown", + "F54F61E3B974AD86171AE4944205C7BD0395BD7845899CDA8B1FBC5C947BB402", + "A18715058BBD914959C3A735B2022E9AE1D04452BC1FAD9E63C53668B7F57907", + 1922832000, + false, + true + }, + { + // new-style 26-word seed phrase auditable - valid + "six six six six six six six six six six six six six six six six six six six six six six six six six grace", + "F54F61E3B974AD86171AE4944205C7BD0395BD7845899CDA8B1FBC5C947BB402", + "A18715058BBD914959C3A735B2022E9AE1D04452BC1FAD9E63C53668B7F57907", + 1922832000, + true, + true + }, + +}; + +TEST(wallet_seed, basic_test) +{ + for (size_t i = 0; i < sizeof wallet_seed_entries / sizeof wallet_seed_entries[0]; ++i) + { + const wallet_seed_entry& wse = wallet_seed_entries[i]; + currency::account_base acc; + bool r = false; + try + { + r = acc.restore_from_braindata(wse.seed_phrase); + } + catch (...) + { + r = false; + } + ASSERT_EQ(r, wse.valid); + + if (r) + { + if (wse.timestamp) + ASSERT_EQ(wse.timestamp, acc.get_createtime()); + + ASSERT_EQ(wse.auditable, acc.get_public_address().is_auditable()); + + // check keys + crypto::secret_key v, s; + ASSERT_TRUE(epee::string_tools::parse_tpod_from_hex_string(wse.spend_secret_key, s)); + ASSERT_EQ(s, acc.get_keys().spend_secret_key); + + ASSERT_TRUE(epee::string_tools::parse_tpod_from_hex_string(wse.view_secret_key, v)); + ASSERT_EQ(v, acc.get_keys().view_secret_key); + } + + } + +} From a4b607e0c008d76866831ef3bc26c1b90b033cc5 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 7 May 2020 15:02:35 +0300 Subject: [PATCH 24/70] fixed a bug in new format seed phrase restoring --- src/currency_core/account.cpp | 39 ++++++++++++++---------------- src/currency_core/account.h | 2 +- src/currency_core/currency_basic.h | 5 ++++ src/wallet/wallet2.cpp | 4 +-- src/wallet/wallet2.h | 2 +- src/wallet/wallets_manager.cpp | 2 +- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index d732bd62..1e492975 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -97,7 +97,7 @@ namespace currency return true; } //----------------------------------------------------------------- - bool account_base::restore_keys_from_braindata(const std::string& seed_phrase) + bool account_base::restore_from_braindata(const std::string& seed_phrase) { //cut the last timestamp word from restore_dats std::list words; @@ -126,33 +126,30 @@ namespace currency return false; } - uint64_t auditable_flag_and_checksum = 0; - try - { + uint64_t auditable_flag_and_checksum = UINT64_MAX; + if (!auditable_flag_and_checksum_word.empty()) auditable_flag_and_checksum = tools::mnemonic_encoding::num_by_word(auditable_flag_and_checksum_word); - } - catch(...) - { - LOG_ERROR("cannot convert seed word: " << auditable_flag_and_checksum_word); - return false; - } - - bool auditable_flag = (auditable_flag_and_checksum & 1) != 0; // auditable flag is the lower 1 bit - uint16_t checksum = auditable_flag_and_checksum >> 1; // checksum -- everything else - constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum std::vector keys_seed_binary = tools::mnemonic_encoding::text2binary(keys_seed_text); CHECK_AND_ASSERT_MES(keys_seed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security m_creation_timestamp = get_timstamp_from_word(timestamp_word); - // check the checksum - crypto::hash h = crypto::cn_fast_hash(keys_seed_binary.data(), keys_seed_binary.size()); - *reinterpret_cast(&h) = m_creation_timestamp; - h = crypto::cn_fast_hash(&h, sizeof h); - uint64_t h_64 = *reinterpret_cast(&h); - uint16_t checksum_calculated = h_64 % (checksum_max + 1); - CHECK_AND_ASSERT_MES(checksum == checksum_calculated, false, "seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words"); + bool auditable_flag = false; + + // check the checksum if checksum word provided + if (auditable_flag_and_checksum != UINT64_MAX) + { + auditable_flag = (auditable_flag_and_checksum & 1) != 0; // auditable flag is the lower 1 bit + uint16_t checksum = auditable_flag_and_checksum >> 1; // checksum -- everything else + constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum + crypto::hash h = crypto::cn_fast_hash(keys_seed_binary.data(), keys_seed_binary.size()); + *reinterpret_cast(&h) = m_creation_timestamp; + h = crypto::cn_fast_hash(&h, sizeof h); + uint64_t h_64 = *reinterpret_cast(&h); + uint16_t checksum_calculated = h_64 % (checksum_max + 1); + CHECK_AND_ASSERT_MES(checksum == checksum_calculated, false, "seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words"); + } bool r = restore_keys(keys_seed_binary); CHECK_AND_ASSERT_MES(r, false, "restore_keys failed"); diff --git a/src/currency_core/account.h b/src/currency_core/account.h index 01134418..c11cb4a2 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -54,7 +54,7 @@ namespace currency std::string get_public_address_str() const; std::string get_restore_braindata() const; - bool restore_keys_from_braindata(const std::string& seed_phrase); + bool restore_from_braindata(const std::string& seed_phrase); uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 8c7c9b2e..9a61c524 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -103,6 +103,11 @@ namespace currency KV_SERIALIZE(flags) END_KV_SERIALIZE_MAP() + bool is_auditable() const + { + return (flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE) != 0; + } + static account_public_address from_old(const account_public_address_old& rhs) { account_public_address result = AUTO_VAL_INIT(result); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 637d0b3a..455c38b9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2018,12 +2018,12 @@ void wallet2::generate(const std::wstring& path, const std::string& pass, bool a store(); } //---------------------------------------------------------------------------------------------------- -void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& restore_key) +void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase) { clear(); prepare_file_names(path); m_password = pass; - bool r = m_account.restore_keys_from_braindata(restore_key); + bool r = m_account.restore_from_braindata(seed_phrase); init_log_prefix(); THROW_IF_TRUE_WALLET_EX(!r, error::wallet_wrong_seed_error, epee::string_encoding::convert_to_ansii(m_wallet_file)); boost::system::error_code ignored_ec; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0f258c03..fa2be59b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -450,7 +450,7 @@ namespace tools }; void assign_account(const currency::account_base& acc); void generate(const std::wstring& path, const std::string& password, bool auditable_wallet); - void restore(const std::wstring& path, const std::string& pass, const std::string& restore_key); + void restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase); void load(const std::wstring& path, const std::string& password); void store(); void store(const std::wstring& path); diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 9b921be8..5b73eaf6 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -886,7 +886,7 @@ std::string wallets_manager::is_pos_allowed() std::string wallets_manager::is_valid_brain_restore_data(const std::string& brain_text) { currency::account_base acc; - if (acc.restore_keys_from_braindata(brain_text)) + if (acc.restore_from_braindata(brain_text)) return API_RETURN_CODE_TRUE; else return API_RETURN_CODE_FALSE; From eb70e67e13d09a23ba2af5202e2a784d8cbbdf78 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 8 May 2020 22:51:19 +0300 Subject: [PATCH 25/70] coretests: hard_fork_2_tx_extra_alias_entry_in_wallet test added --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/hard_fork_2.cpp | 99 ++++++++++++++++++++++++++++++ tests/core_tests/hard_fork_2.h | 7 +++ 3 files changed, 107 insertions(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index c2bb6d96..2d55d0c5 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1002,6 +1002,7 @@ int main(int argc, char* argv[]) // Hardfork 2 tests GENERATE_AND_PLAY(hard_fork_2_tx_payer_in_wallet); GENERATE_AND_PLAY(hard_fork_2_tx_receiver_in_wallet); + GENERATE_AND_PLAY(hard_fork_2_tx_extra_alias_entry_in_wallet); // GENERATE_AND_PLAY(gen_block_reward); diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 48efa133..050b1b1b 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -296,3 +296,102 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c return true; } + +//------------------------------------------------------------------------------ + +hard_fork_2_tx_extra_alias_entry_in_wallet::hard_fork_2_tx_extra_alias_entry_in_wallet() + : hard_fork_2_base_test(22) +{ + REGISTER_CALLBACK_METHOD(hard_fork_2_tx_extra_alias_entry_in_wallet, c1); +} + +bool hard_fork_2_tx_extra_alias_entry_in_wallet::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()); + generator.set_hardfork_height(1, m_hardfork_height); + generator.set_hardfork_height(2, m_hardfork_height); + DO_CALLBACK(events, "configure_core"); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + uint64_t biggest_alias_reward = get_alias_coast_from_fee("a", TESTS_DEFAULT_FEE); + MAKE_TX(events, tx_0, miner_acc, alice_acc, biggest_alias_reward + TESTS_DEFAULT_FEE, blk_0r); + MAKE_TX(events, tx_1, miner_acc, alice_acc, biggest_alias_reward + TESTS_DEFAULT_FEE, blk_0r); + MAKE_TX(events, tx_2, miner_acc, alice_acc, biggest_alias_reward + TESTS_DEFAULT_FEE, blk_0r); + + MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list({ tx_0, tx_1, tx_2 })); + + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); + + DO_CALLBACK(events, "c1"); + + return true; +} + +bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false, stub_bool = false; + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); + + size_t blocks_fetched = 0; + bool received_money; + std::atomic atomic_false = ATOMIC_VAR_INIT(false); + alice_wlt->refresh(blocks_fetched, received_money, atomic_false); + CHECK_AND_ASSERT_MES(blocks_fetched == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE, false, "Incorrect numbers of blocks fetched"); + + extra_alias_entry ai = AUTO_VAL_INIT(ai); + ai.m_alias = "alicealice"; + ai.m_address = m_accounts[ALICE_ACC_IDX].get_public_address(); + uint64_t alias_reward = get_alias_coast_from_fee(ai.m_alias, TESTS_DEFAULT_FEE); + transaction res_tx = AUTO_VAL_INIT(res_tx); + alice_wlt->request_alias_registration(ai, res_tx, TESTS_DEFAULT_FEE, alias_reward); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + + // before the HF2 -- old structure should be present + r = have_type_in_variant_container(res_tx.extra); + CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry_old is not found in extra"); + r = !have_type_in_variant_container(res_tx.extra); + CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry is found in extra"); + + // mine few block to activate HF2 + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 3); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + + CHECK_AND_ASSERT_MES(c.get_current_blockchain_size() == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 4, false, "Incorrect blockchain size"); + + alice_wlt->refresh(blocks_fetched, received_money, atomic_false); + CHECK_AND_ASSERT_MES(blocks_fetched == 3, false, "Incorrect numbers of blocks fetched"); + + // update alias, change comment and address + ai.m_text_comment = "Update!"; + ai.m_address = m_accounts[MINER_ACC_IDX].get_public_address(); + alice_wlt->request_alias_update(ai, res_tx, TESTS_DEFAULT_FEE, 0); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + + // after HF2: extra_alias_entry should be here, not extra_alias_entry_old + r = have_type_in_variant_container(res_tx.extra); + CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry is not found in extra"); + r = !have_type_in_variant_container(res_tx.extra); + CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry_old is found in extra"); + + // make sure alias was updated indeed + extra_alias_entry ai2 = AUTO_VAL_INIT(ai2); + r = c.get_blockchain_storage().get_alias_info(ai.m_alias, ai2); + CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); + CHECK_AND_ASSERT_MES(ai2.m_text_comment == ai.m_text_comment && ai2.m_address == m_accounts[MINER_ACC_IDX].get_public_address(), + false, "Incorrect alias info retunred by get_alias_info"); + + return true; +} diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h index 7e64481f..f5c1e82a 100644 --- a/tests/core_tests/hard_fork_2.h +++ b/tests/core_tests/hard_fork_2.h @@ -29,3 +29,10 @@ struct hard_fork_2_tx_receiver_in_wallet : public wallet_test, public hard_fork_ mutable uint64_t m_alice_start_balance; }; + +struct hard_fork_2_tx_extra_alias_entry_in_wallet : public wallet_test, public hard_fork_2_base_test +{ + hard_fork_2_tx_extra_alias_entry_in_wallet(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; From b56e7311e24b07f9c778b871e47f48ce2f156f2f Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 8 May 2020 22:55:24 +0300 Subject: [PATCH 26/70] coretests: gen_no_attchments_in_coinbase fixed --- tests/core_tests/checkpoints_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core_tests/checkpoints_tests.cpp b/tests/core_tests/checkpoints_tests.cpp index f4767acb..3a72115f 100644 --- a/tests/core_tests/checkpoints_tests.cpp +++ b/tests/core_tests/checkpoints_tests.cpp @@ -612,7 +612,7 @@ gen_no_attchments_in_coinbase::gen_no_attchments_in_coinbase() // NOTE: This test is made deterministic to be able to correctly set up checkpoint. random_state_test_restorer::reset_random(); // random generator's state was previously stored, will be restore on dtor (see also m_random_state_test_restorer) - bool r = m_miner_acc.restore_keys_from_braindata("battle harsh arrow gain best doubt nose raw protect salty apart tell distant final yeah stubborn true stop shoulder breathe throne problem everyone stranger only"); + bool r = m_miner_acc.restore_from_braindata("battle harsh arrow gain best doubt nose raw protect salty apart tell distant final yeah stubborn true stop shoulder breathe throne problem everyone stranger only"); CHECK_AND_ASSERT_THROW_MES(r, "gen_no_attchments_in_coinbase: Can't restore account from braindata"); REGISTER_CALLBACK_METHOD(gen_no_attchments_in_coinbase, c1); From dee448fe5190a05fdb16e98abd535db3081e737f Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 8 May 2020 22:59:51 +0300 Subject: [PATCH 27/70] fixed extra_alias_info handling in tx_extra_handler and rpc_tx_payload_handler (+payer and receiver) --- src/currency_core/currency_format_utils.cpp | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index b3247fce..feae4e80 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -421,13 +421,16 @@ namespace currency rei.m_attachment_info = ai; return true; } - bool operator()(const extra_alias_entry& ae) const { ENSURE_ONETIME(was_alias, "alias"); rei.m_alias = ae; return true; } + bool operator()(const extra_alias_entry_old& ae) const + { + return operator()(static_cast(ae)); + } bool operator()(const extra_user_data& ud) const { ENSURE_ONETIME(was_userdata, "userdata"); @@ -2181,6 +2184,10 @@ namespace currency return true; } + bool operator()(const extra_alias_entry_old& ee) + { + return operator()(static_cast(ee)); + } bool operator()(const extra_user_data& ee) { tv.type = "user_data"; @@ -2214,7 +2221,13 @@ namespace currency return true; } + bool operator()(const tx_payer_old&) + { + tv.type = "payer_old"; + tv.short_view = "(encrypted)"; + return true; + } bool operator()(const tx_receiver& ee) { //const tx_payer& ee = boost::get(extra); @@ -2223,6 +2236,13 @@ namespace currency return true; } + bool operator()(const tx_receiver_old& ee) + { + tv.type = "receiver_old"; + tv.short_view = "(encrypted)"; + + return true; + } bool operator()(const tx_derivation_hint& ee) { tv.type = "derivation_hint"; From 14f4620468947eaac8939e3db0d49f49e4c5a524 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 11 May 2020 15:52:18 +0300 Subject: [PATCH 28/70] simplewallet: debug statement removed --- src/simplewallet/simplewallet.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index e76bad79..58602e52 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1694,8 +1694,6 @@ int main(int argc, char* argv[]) const char* const* argv = argv_vec.data(); #endif - epee::debug::get_set_enable_assert(true, false); - string_tools::set_module_name_and_folder(argv[0]); po::options_description desc_general("General options"); From 9397816f537e309e41706e313eecbe122ba308ef Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 11 May 2020 21:23:00 +0300 Subject: [PATCH 29/70] wallet: handling incoming txs in auditablility mode (WIP) --- src/wallet/wallet2.cpp | 12 ++++++++++-- src/wallet/wallet2.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f894c9b3..899cec63 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -263,10 +263,15 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t { if (in.type() == typeid(currency::txin_to_key)) { - auto it = m_key_images.find(boost::get(in).k_image); + const currency::txin_to_key& intk = boost::get(in); + + // TODO: check for references to our UTXO (auditability) + // intk.key_offsets; + + auto it = m_key_images.find(intk.k_image); if (it != m_key_images.end()) { - tx_money_spent_in_ins += boost::get(in).amount; + tx_money_spent_in_ins += intk.amount; transfer_details& td = m_transfers[it->second]; uint32_t flags_before = td.m_flags; td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; @@ -340,6 +345,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t // obtain key image for this output crypto::key_image ki = currency::null_ki; if (m_watch_only) + { + if (!is_auditable()) { // don't have spend secret key, so we unable to calculate key image for an output // look it up in special container instead @@ -355,6 +362,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t WLT_LOG_L1("can't find pending key image by out pub key: " << otk.key << ", key image temporarily set to null"); } } + } else { // normal wallet, calculate and store key images for own outs diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 7bba0a8b..fe1dd21e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -631,6 +631,7 @@ namespace tools void enumerate_unconfirmed_transfers(callback_t cb) const; bool is_watch_only() const { return m_watch_only; } + bool is_auditable() const { return m_account.get_public_address().is_auditable(); } void sign_transfer(const std::string& tx_sources_blob, std::string& signed_tx_blob, currency::transaction& tx); void sign_transfer_files(const std::string& tx_sources_file, const std::string& signed_tx_file, currency::transaction& tx); void submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx); From d13368dce4e5c3c5e9d6f0050cc24cee9075aa46 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 11 May 2020 21:24:39 +0300 Subject: [PATCH 30/70] handling auditable addresses in construct_tx outputs' generation --- src/currency_core/currency_format_utils.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index feae4e80..d4855cd0 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -592,7 +592,12 @@ namespace currency //out to key txout_to_key tk; tk.key = target_keys.back(); - tk.mix_attr = tx_outs_attr; + + if (de.addr.front().is_auditable()) // check only the first address because there's only one in this branch + tk.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX; // override mix_attr to 1 for auditable target addresses + else + tk.mix_attr = tx_outs_attr; + out.target = tk; } else @@ -1109,7 +1114,7 @@ namespace currency //fill outputs size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1 std::set deriv_cache; - BOOST_FOREACH(const tx_destination_entry& dst_entr, shuffled_dsts) + for(const tx_destination_entry& dst_entr : shuffled_dsts) { CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount); bool r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, tx_outs_attr); From af3dbaa2e78ffe2443a99b9f579803dc424f224f Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 12 May 2020 18:14:53 +0300 Subject: [PATCH 31/70] coretests: hard_fork_2_auditable_addresses_basics added --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/hard_fork_2.cpp | 109 ++++++++++++++++++++++++++++- tests/core_tests/hard_fork_2.h | 7 ++ 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 2d55d0c5..499a78d2 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1003,6 +1003,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(hard_fork_2_tx_payer_in_wallet); GENERATE_AND_PLAY(hard_fork_2_tx_receiver_in_wallet); GENERATE_AND_PLAY(hard_fork_2_tx_extra_alias_entry_in_wallet); + GENERATE_AND_PLAY(hard_fork_2_auditable_addresses_basics); // GENERATE_AND_PLAY(gen_block_reward); diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 050b1b1b..288217f9 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -5,9 +5,6 @@ #include "chaingen.h" #include "hard_fork_2.h" #include "../../src/wallet/wallet_rpc_server.h" -//#include "pos_block_builder.h" -//#include "tx_builder.h" -//#include "random_helper.h" using namespace currency; @@ -395,3 +392,109 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev return true; } + +//------------------------------------------------------------------------------ + +hard_fork_2_auditable_addresses_basics::hard_fork_2_auditable_addresses_basics() + : hard_fork_2_base_test(23) +{ + REGISTER_CALLBACK_METHOD(hard_fork_2_auditable_addresses_basics, c1); +} + +bool hard_fork_2_auditable_addresses_basics::generate(std::vector& events) const +{ + /* + Test idea: make sure that: + (1) before HF2 txs with mix_attr == 1 can be sent and then they are recognized by wallet; + (2) before HF2 txs to an auditable address can't be sent via wallet2::transfer() + (3) after HF2 txs to an auditable address CAN be sent via wallet2::transfer() + */ + + 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(true); // Bob has auditable address + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + generator.set_hardfork_height(1, m_hardfork_height); + generator.set_hardfork_height(2, m_hardfork_height); + 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(11), blk_0r); + + // tx_1 has outputs to an auditable address, it's allowed before HF2 + MAKE_TX(events, tx_1, miner_acc, bob_acc, MK_TEST_COINS(5), blk_0r); + + // make sure all Bob's outputs has mix_attr = 1 + for (auto& out : tx_1.vout) + { + if (out.amount != MK_TEST_COINS(5)) + continue; // skip change + uint8_t mix_attr = boost::get(out.target).mix_attr; + CHECK_AND_ASSERT_MES(mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX, false, "Incorrect mix_attr in tx_1: " << mix_attr); + } + + MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list({ tx_0, tx_1 })); + + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); + + DO_CALLBACK(events, "c1"); + + return true; +} + +bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false, stub_bool = false; + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(11), false, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(5), false, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE), false, ""); + + // sending coins to an auditable address should not be allowed until HF2 + std::vector destination{tx_destination_entry(MK_TEST_COINS(1), bob_wlt->get_account().get_public_address())}; + transaction tx = AUTO_VAL_INIT(tx); + bool exception_caught = false; + try + { + alice_wlt->transfer(destination, 0, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tx); + } + catch (tools::error::wallet_common_error& e) + { + exception_caught = true; + } + CHECK_AND_ASSERT_MES(exception_caught, false, "exception was not cought as expected"); + + // mine few block to activate HF2 + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 3); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(11), false, 3), false, ""); + + // now coins should be normally sent + alice_wlt->transfer(destination, 0, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tx); + + // make sure all Bob's outputs has mix_attr = 1 + for (auto& out : tx.vout) + { + if (out.amount != MK_TEST_COINS(1)) + continue; // skip change + uint8_t mix_attr = boost::get(out.target).mix_attr; + CHECK_AND_ASSERT_MES(mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX, false, "Incorrect mix_attr in tx: " << mix_attr); + } + + // mine a block to confirm the tx + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + + // make sure the funds were received + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(5 + 1), false, 3 + 1), false, ""); + + return true; +} diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h index f5c1e82a..7f6627de 100644 --- a/tests/core_tests/hard_fork_2.h +++ b/tests/core_tests/hard_fork_2.h @@ -36,3 +36,10 @@ struct hard_fork_2_tx_extra_alias_entry_in_wallet : public wallet_test, public h bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +struct hard_fork_2_auditable_addresses_basics : public wallet_test, public hard_fork_2_base_test +{ + hard_fork_2_auditable_addresses_basics(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; From 3c30c655ff4b8900087283eccc4e0b2e12795859 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 12 May 2020 18:16:47 +0300 Subject: [PATCH 32/70] wallet2: disallow auditable addresses as destinations until HF2 in transfer() --- src/wallet/wallet2.cpp | 16 ++++++++++++++++ src/wallet/wallet2.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 899cec63..d77cdc1f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -4472,12 +4472,28 @@ 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_auditable_address_is_targeted_before_hf2(const construct_tx_param& ctp) +{ + if (get_top_block_height() <= m_core_runtime_config.hard_fork_02_starts_after_height) + { + // before HF2 + for (auto& d : ctp.dsts) + { + for (auto& addr : d.addr) + { + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!addr.is_auditable(), "sending fund to an auditable address is not supported until HF2, address = " << get_account_address_as_str(addr)); + } + } + } +} +//---------------------------------------------------------------------------------------------------- void wallet2::transfer(const construct_tx_param& ctp, currency::transaction &tx, bool send_to_network, std::string* p_signed_tx_blob_str) { check_and_throw_if_self_directed_tx_with_payment_id_requested(ctp); + check_and_throw_if_auditable_address_is_targeted_before_hf2(ctp); TIME_MEASURE_START(prepare_transaction_time); finalize_tx_param ftp = AUTO_VAL_INIT(ftp); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index fe1dd21e..7a012351 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -904,6 +904,7 @@ private: bool generate_packing_transaction_if_needed(currency::transaction& tx, uint64_t fake_outputs_number); bool store_unsigned_tx_to_file_and_reserve_transfers(const 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_auditable_address_is_targeted_before_hf2(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); From a2ac9c76402aa53a26434eb0ce0d4e2b1b69ec4a Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 12 May 2020 18:30:28 +0300 Subject: [PATCH 33/70] unnecessary logs removed --- src/wallet/wallet2.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index d77cdc1f..dfee9cdc 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1175,7 +1175,6 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic& stop) bool r = m_core_proxy->call_COMMAND_RPC_GET_BLOCKS_DIRECT(req, res); if (!r) throw error::no_connection_to_daemon(LOCATION_STR, "getblocks.bin"); - WLT_LOG_L0("COMMAND_RPC_GET_BLOCKS_DIRECT: " << epee::serialization::store_t_to_json(req)); if (res.status == API_RETURN_CODE_GENESIS_MISMATCH) { WLT_LOG_MAGENTA("Reseting genesis block...", LOG_LEVEL_0); From ae5269d12c4bb40efa6b55b2017feffdd2c3161c Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 14 May 2020 20:11:21 +0300 Subject: [PATCH 34/70] coretests: hard_fork_2_auditable_addresses_basics changed to reflect updated auditable address rule --- tests/core_tests/hard_fork_2.cpp | 47 ++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 288217f9..a91e691c 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -406,7 +406,7 @@ bool hard_fork_2_auditable_addresses_basics::generate(std::vector({ tx_0, tx_1 })); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list({ tx_0a, tx_0b, tx_1 })); REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); @@ -451,31 +452,37 @@ bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_ind std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]); - CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(11), false, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(22), false, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE), false, ""); CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(5), false, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE), false, ""); // sending coins to an auditable address should not be allowed until HF2 std::vector destination{tx_destination_entry(MK_TEST_COINS(1), bob_wlt->get_account().get_public_address())}; transaction tx = AUTO_VAL_INIT(tx); - bool exception_caught = false; - try - { - alice_wlt->transfer(destination, 0, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tx); - } - catch (tools::error::wallet_common_error& e) - { - exception_caught = true; - } - CHECK_AND_ASSERT_MES(exception_caught, false, "exception was not cought as expected"); + alice_wlt->transfer(destination, 0, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tx); - // mine few block to activate HF2 - r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 3); + // make sure all Bob's outputs has mix_attr = 1 + for (auto& out : tx.vout) + { + if (out.amount != MK_TEST_COINS(1)) + continue; // skip change + uint8_t mix_attr = boost::get(out.target).mix_attr; + CHECK_AND_ASSERT_MES(mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX, false, "Incorrect mix_attr in tx: " << mix_attr); + } + + // mine a block to confirm the tx + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); - CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(11), false, 3), false, ""); + // mine few block to activate HF2 + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 2); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); - // now coins should be normally sent + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(20), false, 3), false, ""); + + // repeat the transfer after HF2 (using the same destinations) alice_wlt->transfer(destination, 0, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment, tx); // make sure all Bob's outputs has mix_attr = 1 @@ -494,7 +501,7 @@ bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_ind CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); // make sure the funds were received - CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(5 + 1), false, 3 + 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(5 + 1 + 1), false, 3 + 1), false, ""); return true; } From a9336724aa7f41be25915d97aa6c07fe4fd4f8e4 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 18 May 2020 17:19:21 +0300 Subject: [PATCH 35/70] back-compatibility for new wallets fixed --- src/currency_core/account.h | 5 ++++- src/currency_core/currency_basic.h | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/currency_core/account.h b/src/currency_core/account.h index c11cb4a2..bcb35961 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -72,10 +72,13 @@ namespace currency a & m_keys_seed_binary; } + static std::string vector_of_chars_to_string(const std::vector& v) { return std::string(v.begin(), v.end()); } + static std::vector string_to_vector_of_chars(const std::string& v) { return std::vector(v.begin(), v.end()); } + BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_keys) KV_SERIALIZE(m_creation_timestamp) - KV_SERIALIZE(m_keys_seed_binary) + KV_SERIALIZE_CUSTOM_N(m_keys_seed_binary, std::string, vector_of_chars_to_string, string_to_vector_of_chars, "m_seed") END_KV_SERIALIZE_MAP() private: diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 0afcc0f6..b51834b5 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -100,8 +100,8 @@ namespace currency END_SERIALIZE() BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(spend_public_key) - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(view_public_key) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(spend_public_key, "m_spend_public_key") + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(view_public_key, "m_view_public_key") KV_SERIALIZE(flags) END_KV_SERIALIZE_MAP() From c1e3b801912e110aef6e96fb504046417016fd1c Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 18 May 2020 17:20:23 +0300 Subject: [PATCH 36/70] coretests: minor refactoring --- tests/core_tests/alias_tests.cpp | 88 ++++++----------------------- tests/core_tests/chaingen.h | 2 +- tests/core_tests/chaingen_helpers.h | 53 +++++++++++++++++ 3 files changed, 72 insertions(+), 71 deletions(-) diff --git a/tests/core_tests/alias_tests.cpp b/tests/core_tests/alias_tests.cpp index 81d9a219..97595c50 100644 --- a/tests/core_tests/alias_tests.cpp +++ b/tests/core_tests/alias_tests.cpp @@ -18,72 +18,20 @@ using namespace currency; #define FIFTH_NAME "fifth--01234567890" #define SIX_NAME "sixsix-double--01234567890" -std::string gen_random_alias(size_t len) -{ - const char allowed_chars[] = "abcdefghijklmnopqrstuvwxyz0123456789"; - char buffer[2048] = ""; - if (len >= sizeof buffer) - return ""; - - crypto::generate_random_bytes(len, buffer); - buffer[len] = 0; - for(size_t i = 0; i < len; ++i) - buffer[i] = allowed_chars[buffer[i] % (sizeof allowed_chars - 1)]; - return buffer; -} - bool put_alias_via_tx_to_list(std::vector& events, - std::list& tx_set, - const block& head_block, - const account_base& miner_acc, - currency::extra_alias_entry ai2, - test_generator& generator) - { - - std::vector ex; - ex.push_back(ai2); - account_base reward_acc; - account_keys& ak = const_cast(reward_acc.get_keys()); - currency::get_aliases_reward_account(ak.account_address, ak.view_secret_key); - - uint64_t fee_median = generator.get_last_n_blocks_fee_median(get_block_hash(head_block)); - uint64_t reward = currency::get_alias_coast_from_fee(ai2.m_alias, fee_median); - - MAKE_TX_MIX_LIST_EXTRA_MIX_ATTR(events, - tx_set, - miner_acc, - reward_acc, - reward, - 0, - head_block, - CURRENCY_TO_KEY_OUT_RELAXED, - ex, - std::vector()); - - - uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx_set.back()); - if (found_alias_reward != reward) - { - LOCAL_ASSERT(false); - CHECK_AND_ASSERT_MES(false, false, "wrong transaction constructed, first input value not match alias amount or account"); - return false; - } - return true; + std::list& tx_set, + const block& head_block, + const std::string& alias_name, + const account_base& miner_acc, + const account_base& alias_acc, + test_generator& generator) +{ + currency::extra_alias_entry ai2 = AUTO_VAL_INIT(ai2); + ai2.m_alias = alias_name; + ai2.m_address = alias_acc.get_keys().account_address; + ai2.m_text_comment = "ssdss"; + return put_alias_via_tx_to_list(events, tx_set, head_block, miner_acc, ai2, generator); } - bool put_alias_via_tx_to_list(std::vector& events, - std::list& tx_set, - const block& head_block, - const std::string& alias_name, - const account_base& miner_acc, - const account_base& alias_acc, - test_generator& generator) - { - currency::extra_alias_entry ai2 = AUTO_VAL_INIT(ai2); - ai2.m_alias = alias_name; - ai2.m_address = alias_acc.get_keys().account_address; - ai2.m_text_comment = "ssdss"; - return put_alias_via_tx_to_list(events, tx_set, head_block, miner_acc, ai2, generator); - } bool put_next_block_with_alias_in_tx(std::vector& events, block& b, @@ -92,13 +40,13 @@ bool put_next_block_with_alias_in_tx(std::vector& events, const currency::extra_alias_entry& ai, test_generator& generator) { - std::list txs_0; - if (!put_alias_via_tx_to_list(events, txs_0, head_block, miner_acc, ai, generator)) - return false; + std::list txs_0; + if (!put_alias_via_tx_to_list(events, txs_0, head_block, miner_acc, ai, generator)) + return false; - MAKE_NEXT_BLOCK_TX_LIST(events, blk, head_block, miner_acc, txs_0); - b = blk; - return true; + MAKE_NEXT_BLOCK_TX_LIST(events, blk, head_block, miner_acc, txs_0); + b = blk; + return true; } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 8351521c..daf36a83 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -15,7 +15,6 @@ #include "currency_core/currency_core.h" #include "wallet/wallet2.h" #include "test_core_time.h" -#include "chaingen_helpers.h" #define TESTS_DEFAULT_FEE ((uint64_t)TX_DEFAULT_FEE) #define MK_TEST_COINS(amount) (static_cast(amount) * TX_DEFAULT_FEE) @@ -1205,3 +1204,4 @@ void append_vector_by_another_vector(U& dst, const V& src) // --- end of gentime wallet helpers ----------------------------------------------------------------------- +#include "chaingen_helpers.h" diff --git a/tests/core_tests/chaingen_helpers.h b/tests/core_tests/chaingen_helpers.h index 31835912..a899693d 100644 --- a/tests/core_tests/chaingen_helpers.h +++ b/tests/core_tests/chaingen_helpers.h @@ -228,3 +228,56 @@ inline bool resign_tx(const currency::account_keys& sender_keys, const std::vect return true; } + +inline std::string gen_random_alias(size_t len) +{ + const char allowed_chars[] = "abcdefghijklmnopqrstuvwxyz0123456789"; + char buffer[2048] = ""; + if (len >= sizeof buffer) + return ""; + + crypto::generate_random_bytes(len, buffer); + buffer[len] = 0; + for(size_t i = 0; i < len; ++i) + buffer[i] = allowed_chars[buffer[i] % (sizeof allowed_chars - 1)]; + return buffer; +} + +inline bool put_alias_via_tx_to_list(std::vector& events, + std::list& tx_set, + const currency::block& head_block, + const currency::account_base& miner_acc, + currency::extra_alias_entry ai2, + test_generator& generator) +{ + std::vector ex; + ex.push_back(ai2); + currency::account_base reward_acc; + currency::account_keys& ak = const_cast(reward_acc.get_keys()); + currency::get_aliases_reward_account(ak.account_address, ak.view_secret_key); + + uint64_t fee_median = generator.get_last_n_blocks_fee_median(get_block_hash(head_block)); + uint64_t reward = currency::get_alias_coast_from_fee(ai2.m_alias, fee_median); + + MAKE_TX_MIX_LIST_EXTRA_MIX_ATTR(events, + tx_set, + miner_acc, + reward_acc, + reward, + 0, + head_block, + CURRENCY_TO_KEY_OUT_RELAXED, + ex, + std::vector()); + + + uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx_set.back()); + if (found_alias_reward != reward) + { + LOCAL_ASSERT(false); + CHECK_AND_ASSERT_MES(false, false, "wrong transaction constructed, first input value not match alias amount or account"); + return false; + } + + return true; +} From 4271875709ad8f0f4181ee84d8f3b80181164eac Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 18 May 2020 17:21:12 +0300 Subject: [PATCH 37/70] coretests: hard_fork_2_no_new_structures_before_hf added --- tests/core_tests/chaingen_main.cpp | 8 ++- tests/core_tests/hard_fork_2.cpp | 86 ++++++++++++++++++++++++++++++ tests/core_tests/hard_fork_2.h | 7 +++ 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 499a78d2..fca861b0 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -712,7 +712,7 @@ int main(int argc, char* argv[]) run_single_test = command_line::get_arg(g_vm, arg_run_single_test); } - if (run_single_test.empty()) + /*if (run_single_test.empty()) { CALL_TEST("Random text test", get_random_text_test); CALL_TEST("Random state manipulation test", random_state_manupulation_test); @@ -721,7 +721,7 @@ int main(int argc, char* argv[]) CALL_TEST("check_allowed_types_in_variant_container() test", check_allowed_types_in_variant_container_test); CALL_TEST("check_u8_str_case_funcs", check_u8_str_case_funcs); CALL_TEST("chec_u8_str_matching", chec_u8_str_matching); - } + }*/ //CALL_TEST("check_hash_and_difficulty_monte_carlo_test", check_hash_and_difficulty_monte_carlo_test); // it's rather an experiment with unclean results than a solid test, for further research... std::set postponed_tests; @@ -741,6 +741,9 @@ int main(int argc, char* argv[]) #undef MARK_TEST_AS_POSTPONED + GENERATE_AND_PLAY(hard_fork_2_no_new_structures_before_hf); + + /* GENERATE_AND_PLAY(pos_minting_tx_packing); GENERATE_AND_PLAY(multisig_wallet_test); @@ -1004,6 +1007,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(hard_fork_2_tx_receiver_in_wallet); GENERATE_AND_PLAY(hard_fork_2_tx_extra_alias_entry_in_wallet); GENERATE_AND_PLAY(hard_fork_2_auditable_addresses_basics); + GENERATE_AND_PLAY(hard_fork_2_no_new_structures_before_hf); // GENERATE_AND_PLAY(gen_block_reward); diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index a91e691c..68904b59 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -505,3 +505,89 @@ bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_ind return true; } + + +//------------------------------------------------------------------------------ + +hard_fork_2_no_new_structures_before_hf::hard_fork_2_no_new_structures_before_hf() + : hard_fork_2_base_test(13) +{ +} + +bool hard_fork_2_no_new_structures_before_hf::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(); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + generator.set_hardfork_height(1, m_hardfork_height); + generator.set_hardfork_height(2, m_hardfork_height); + DO_CALLBACK(events, "configure_core"); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + std::vector extra; + + // extra with tx_payer -- not allowed before HF2 + tx_payer payer = AUTO_VAL_INIT(payer); + payer.acc_addr = miner_acc.get_public_address(); + extra.push_back(payer); + MAKE_TX_MIX_ATTR_EXTRA(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(1), 0, blk_0r, 0, extra, true); + + // blk_1b_1 is invalid as containing tx_0 + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX1(events, blk_1b_1, blk_0r, miner_acc, tx_0); + + + // extra with tx_receiver -- not allowed before HF2 + extra.clear(); + tx_receiver receiver = AUTO_VAL_INIT(receiver); + receiver.acc_addr = miner_acc.get_public_address(); + extra.push_back(receiver); + MAKE_TX_MIX_ATTR_EXTRA(events, tx_1, miner_acc, alice_acc, MK_TEST_COINS(1), 0, blk_0r, 0, extra, true); + + // blk_1b_2 is invalid as containing tx_1 + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX1(events, blk_1b_2, blk_1b_1, miner_acc, tx_1); + + + // extra with tx_receiver -- not allowed before HF2 + extra.clear(); + + extra_alias_entry alias_entry = AUTO_VAL_INIT(alias_entry); + alias_entry.m_address = miner_acc.get_public_address(); + alias_entry.m_alias = "aabbcc"; + extra.push_back(alias_entry); + + std::list tx_set; + bool r = put_alias_via_tx_to_list(events, tx_set, blk_0r, miner_acc, alias_entry, generator); + CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); + transaction tx_2 = tx_set.front(); + + // blk_1b_3 is invalid as containing tx_2 + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX1(events, blk_1b_3, blk_1b_2, miner_acc, tx_2); + + // activate HF2 + MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc); + MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc); + MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); + MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc); + + + // tx_0 with tx_payer should be accepted after HF2 + MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4, miner_acc, tx_0); + + // tx_1 with tx_receiver should be accepted after HF2 + MAKE_NEXT_BLOCK_TX1(events, blk_6, blk_5, miner_acc, tx_1); + + // tx_2 with extra_alias_entry should be accepted after HF2 + MAKE_NEXT_BLOCK_TX1(events, blk_7, blk_6, miner_acc, tx_2); + + return true; +} + +bool hard_fork_2_no_new_structures_before_hf::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + return true; +} diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h index 7f6627de..7641acde 100644 --- a/tests/core_tests/hard_fork_2.h +++ b/tests/core_tests/hard_fork_2.h @@ -43,3 +43,10 @@ struct hard_fork_2_auditable_addresses_basics : public wallet_test, public hard_ bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +struct hard_fork_2_no_new_structures_before_hf : public wallet_test, public hard_fork_2_base_test +{ + hard_fork_2_no_new_structures_before_hf(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; From d9150e592a2d924f8601d0a7e9a8858665087811 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 18 May 2020 17:22:17 +0300 Subject: [PATCH 38/70] coretests: typos fixed --- tests/core_tests/chaingen_main.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index fca861b0..a7ade6de 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -712,7 +712,7 @@ int main(int argc, char* argv[]) run_single_test = command_line::get_arg(g_vm, arg_run_single_test); } - /*if (run_single_test.empty()) + if (run_single_test.empty()) { CALL_TEST("Random text test", get_random_text_test); CALL_TEST("Random state manipulation test", random_state_manupulation_test); @@ -721,7 +721,7 @@ int main(int argc, char* argv[]) CALL_TEST("check_allowed_types_in_variant_container() test", check_allowed_types_in_variant_container_test); CALL_TEST("check_u8_str_case_funcs", check_u8_str_case_funcs); CALL_TEST("chec_u8_str_matching", chec_u8_str_matching); - }*/ + } //CALL_TEST("check_hash_and_difficulty_monte_carlo_test", check_hash_and_difficulty_monte_carlo_test); // it's rather an experiment with unclean results than a solid test, for further research... std::set postponed_tests; @@ -741,9 +741,6 @@ int main(int argc, char* argv[]) #undef MARK_TEST_AS_POSTPONED - GENERATE_AND_PLAY(hard_fork_2_no_new_structures_before_hf); - - /* GENERATE_AND_PLAY(pos_minting_tx_packing); GENERATE_AND_PLAY(multisig_wallet_test); From 4b3e8da6fa77e2a7c02a756d9743110c5109caaf Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 19 May 2020 20:12:43 +0300 Subject: [PATCH 39/70] wallet2: made new format unloadable by old wallets + correct error on file read errors --- src/currency_core/currency_config.h | 3 ++- src/wallet/wallet2.cpp | 35 +++++++++++++++++------------ src/wallet/wallet2.h | 27 ++++++++++++++++++++-- src/wallet/wallets_manager.cpp | 4 ++++ 4 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 760670ea..d6ab7052 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -143,7 +143,8 @@ #define POS_MINIMUM_COINSTAKE_AGE 10 // blocks count -#define WALLET_FILE_SIGNATURE 0x1111012101101011LL //Bender's nightmare +#define WALLET_FILE_SIGNATURE_OLD 0x1111012101101011LL // Bender's nightmare +#define WALLET_FILE_SIGNATURE_V2 0x111101120101011LL // another Bender's nightmare #define WALLET_FILE_MAX_BODY_SIZE 0x88888888L //2GB #define WALLET_FILE_MAX_KEYS_SIZE 10000 // #define WALLET_BRAIN_DATE_OFFSET 1543622400 diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index dfee9cdc..e923e771 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2037,20 +2037,27 @@ bool wallet2::prepare_file_names(const std::wstring& file_path) return true; } //---------------------------------------------------------------------------------------------------- -void wallet2::load_keys(const std::string& buff, const std::string& password) +void wallet2::load_keys(const std::string& buff, const std::string& password, uint64_t file_signature) { - wallet2::keys_file_data keys_file_data; -// std::string buf; -// bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf); -// CHECK_AND_THROW_WALLET_EX(!r, error::file_read_error, keys_file_name); - bool r = ::serialization::parse_binary(buff, keys_file_data); + bool r = false; + wallet2::keys_file_data kf_data = AUTO_VAL_INIT(kf_data); + if (file_signature == WALLET_FILE_SIGNATURE_OLD) + { + wallet2::keys_file_data_old kf_data_old; + r = ::serialization::parse_binary(buff, kf_data_old); + kf_data = wallet2::keys_file_data::from_old(kf_data_old); + } + else if (file_signature == WALLET_FILE_SIGNATURE_V2) + { + r = ::serialization::parse_binary(buff, kf_data); + } THROW_IF_TRUE_WALLET_EX(!r, error::wallet_internal_error, "internal error: failed to deserialize"); crypto::chacha8_key key; crypto::generate_chacha8_key(password, key); std::string account_data; - account_data.resize(keys_file_data.account_data.size()); - crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); + account_data.resize(kf_data.account_data.size()); + crypto::chacha8(kf_data.account_data.data(), kf_data.account_data.size(), key, kf_data.iv, &account_data[0]); const currency::account_keys& keys = m_account.get_keys(); r = epee::serialization::load_t_from_binary(m_account, account_data); @@ -2131,22 +2138,22 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) THROW_IF_TRUE_WALLET_EX(e || !exists, error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file)); boost::filesystem::ifstream data_file; data_file.open(m_wallet_file, std::ios_base::binary | std::ios_base::in); - THROW_IF_TRUE_WALLET_EX(data_file.fail(), error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file)); + THROW_IF_TRUE_WALLET_EX(data_file.fail(), error::file_read_error, epee::string_encoding::convert_to_ansii(m_wallet_file)); wallet_file_binary_header wbh = AUTO_VAL_INIT(wbh); data_file.read((char*)&wbh, sizeof(wbh)); - THROW_IF_TRUE_WALLET_EX(data_file.fail(), error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file)); + THROW_IF_TRUE_WALLET_EX(data_file.fail(), error::file_read_error, epee::string_encoding::convert_to_ansii(m_wallet_file)); - THROW_IF_TRUE_WALLET_EX(wbh.m_signature != WALLET_FILE_SIGNATURE, error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file)); + THROW_IF_TRUE_WALLET_EX(wbh.m_signature != WALLET_FILE_SIGNATURE_OLD && wbh.m_signature != WALLET_FILE_SIGNATURE_V2, error::file_read_error, epee::string_encoding::convert_to_ansii(m_wallet_file)); THROW_IF_TRUE_WALLET_EX(wbh.m_cb_body > WALLET_FILE_MAX_BODY_SIZE || - wbh.m_cb_keys > WALLET_FILE_MAX_KEYS_SIZE, error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file)); + wbh.m_cb_keys > WALLET_FILE_MAX_KEYS_SIZE, error::file_read_error, epee::string_encoding::convert_to_ansii(m_wallet_file)); keys_buff.resize(wbh.m_cb_keys); data_file.read((char*)keys_buff.data(), wbh.m_cb_keys); - load_keys(keys_buff, password); + load_keys(keys_buff, password, wbh.m_signature); bool need_to_resync = !tools::portable_unserialize_obj_from_stream(*this, data_file); @@ -2188,7 +2195,7 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor //store data wallet_file_binary_header wbh = AUTO_VAL_INIT(wbh); - wbh.m_signature = WALLET_FILE_SIGNATURE; + wbh.m_signature = WALLET_FILE_SIGNATURE_V2; wbh.m_cb_keys = keys_buff.size(); //@#@ change it to proper wbh.m_cb_body = 1000; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 7a012351..bd0913fc 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -445,7 +445,7 @@ namespace tools typedef std::map > free_amounts_cache_type; - struct keys_file_data + struct keys_file_data_old { crypto::chacha8_iv iv; std::string account_data; @@ -455,6 +455,29 @@ namespace tools FIELD(account_data) END_SERIALIZE() }; + + struct keys_file_data + { + uint8_t version; + crypto::chacha8_iv iv; + std::string account_data; + + static keys_file_data from_old(const keys_file_data_old& v) + { + keys_file_data result = AUTO_VAL_INIT(result); + result.iv = v.iv; + result.account_data = v.account_data; + return result; + } + + DEFINE_SERIALIZATION_VERSION(1) + BEGIN_SERIALIZE_OBJECT() + VERSION_ENTRY(version) + FIELD(iv) + FIELD(account_data) + END_SERIALIZE() + }; + void assign_account(const currency::account_base& acc); void generate(const std::wstring& path, const std::string& password, bool auditable_wallet); void restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase); @@ -789,7 +812,7 @@ private: void add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id); void remove_transfer_from_expiration_list(uint64_t transfer_index); - void load_keys(const std::string& keys_file_name, const std::string& password); + void load_keys(const std::string& keys_file_name, const std::string& password, uint64_t file_signature); void process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b); void detach_blockchain(uint64_t including_height); bool extract_offers_from_transfer_entry(size_t i, std::unordered_map& offers_local); diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 483d038f..443de3e6 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -769,6 +769,10 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st { return API_RETURN_CODE_FILE_NOT_FOUND; } + catch (const tools::error::file_read_error&) + { + return API_RETURN_CODE_INVALID_FILE; + } catch (const tools::error::wallet_load_notice_wallet_restored& /**/) { return_code = API_RETURN_CODE_FILE_RESTORED; From 2bdf17e7492473a76b950122a6d8d91834c68948 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 19 May 2020 20:17:05 +0300 Subject: [PATCH 40/70] coretests: hard_fork_2_base_test refactored + put_alias_via_tx_to_list made more flexible --- tests/core_tests/chaingen_helpers.h | 7 +++--- tests/core_tests/hard_fork_2.cpp | 35 +++++++++++++++++------------ tests/core_tests/hard_fork_2.h | 8 +++++-- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/tests/core_tests/chaingen_helpers.h b/tests/core_tests/chaingen_helpers.h index a899693d..2e35652e 100644 --- a/tests/core_tests/chaingen_helpers.h +++ b/tests/core_tests/chaingen_helpers.h @@ -243,21 +243,22 @@ inline std::string gen_random_alias(size_t len) return buffer; } +template inline bool put_alias_via_tx_to_list(std::vector& events, std::list& tx_set, const currency::block& head_block, const currency::account_base& miner_acc, - currency::extra_alias_entry ai2, + const alias_entry_t& ae, test_generator& generator) { std::vector ex; - ex.push_back(ai2); + ex.push_back(ae); currency::account_base reward_acc; currency::account_keys& ak = const_cast(reward_acc.get_keys()); currency::get_aliases_reward_account(ak.account_address, ak.view_secret_key); uint64_t fee_median = generator.get_last_n_blocks_fee_median(get_block_hash(head_block)); - uint64_t reward = currency::get_alias_coast_from_fee(ai2.m_alias, fee_median); + uint64_t reward = currency::get_alias_coast_from_fee(ae.m_alias, fee_median); MAKE_TX_MIX_LIST_EXTRA_MIX_ATTR(events, tx_set, diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 68904b59..ebcf0e4f 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -10,8 +10,14 @@ using namespace currency; //------------------------------------------------------------------------------ -hard_fork_2_base_test::hard_fork_2_base_test(size_t hardfork_height) - : m_hardfork_height(hardfork_height) +hard_fork_2_base_test::hard_fork_2_base_test(size_t hardfork_02_height) + : hard_fork_2_base_test(1, hardfork_02_height) +{ +} + +hard_fork_2_base_test::hard_fork_2_base_test(size_t hardfork_01_height, size_t hardfork_02_height) + : m_hardfork_01_height(hardfork_01_height) + , m_hardfork_02_height(hardfork_02_height) { REGISTER_CALLBACK_METHOD(hard_fork_2_base_test, configure_core); } @@ -21,12 +27,18 @@ bool hard_fork_2_base_test::configure_core(currency::core& c, size_t ev_index, c 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.hard_fork_01_starts_after_height = m_hardfork_height; - pc.hard_fork_02_starts_after_height = m_hardfork_height; + pc.hard_fork_01_starts_after_height = m_hardfork_01_height; + pc.hard_fork_02_starts_after_height = m_hardfork_02_height; c.get_blockchain_storage().set_core_runtime_config(pc); return true; } +void hard_fork_2_base_test::set_hard_fork_heights_to_generator(test_generator& generator) const +{ + generator.set_hardfork_height(1, m_hardfork_01_height); + generator.set_hardfork_height(2, m_hardfork_02_height); +} + //------------------------------------------------------------------------------ hard_fork_2_tx_payer_in_wallet::hard_fork_2_tx_payer_in_wallet() @@ -44,8 +56,7 @@ bool hard_fork_2_tx_payer_in_wallet::generate(std::vector& eve account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); - generator.set_hardfork_height(1, m_hardfork_height); - generator.set_hardfork_height(2, m_hardfork_height); + set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); @@ -171,8 +182,7 @@ bool hard_fork_2_tx_receiver_in_wallet::generate(std::vector& 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()); - generator.set_hardfork_height(1, m_hardfork_height); - generator.set_hardfork_height(2, m_hardfork_height); + set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); @@ -310,8 +320,7 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::generate(std::vector& events); - size_t m_hardfork_height; + void set_hard_fork_heights_to_generator(test_generator& generator) const; + + size_t m_hardfork_01_height; + size_t m_hardfork_02_height; }; struct hard_fork_2_tx_payer_in_wallet : public wallet_test, public hard_fork_2_base_test From df8c4b6594c20a83c6b665877e6257a74b36a9ed Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 19 May 2020 20:18:23 +0300 Subject: [PATCH 41/70] coretests: hard_fork_2_no_new_structures_before_hf fixed and greatly improved with positive cases --- tests/core_tests/hard_fork_2.cpp | 74 +++++++++++++++++++++++++------- tests/core_tests/hard_fork_2.h | 2 + 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index ebcf0e4f..8e293353 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -518,12 +518,14 @@ bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_ind //------------------------------------------------------------------------------ hard_fork_2_no_new_structures_before_hf::hard_fork_2_no_new_structures_before_hf() - : hard_fork_2_base_test(13) + : hard_fork_2_base_test(16) { + REGISTER_CALLBACK_METHOD(hard_fork_2_no_new_structures_before_hf, c1); } bool hard_fork_2_no_new_structures_before_hf::generate(std::vector& events) const { + bool r = false; 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(); @@ -535,6 +537,7 @@ bool hard_fork_2_no_new_structures_before_hf::generate(std::vector extra; + // extra with tx_payer -- not allowed before HF2 tx_payer payer = AUTO_VAL_INIT(payer); payer.acc_addr = miner_acc.get_public_address(); @@ -543,7 +546,16 @@ bool hard_fork_2_no_new_structures_before_hf::generate(std::vector tx_set; - bool r = put_alias_via_tx_to_list(events, tx_set, blk_0r, miner_acc, alias_entry, generator); + r = put_alias_via_tx_to_list(events, tx_set, blk_2, miner_acc, alias_entry, generator); CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); transaction tx_2 = tx_set.front(); // blk_1b_3 is invalid as containing tx_2 DO_CALLBACK(events, "mark_invalid_block"); - MAKE_NEXT_BLOCK_TX1(events, blk_1b_3, blk_1b_2, miner_acc, tx_2); + MAKE_NEXT_BLOCK_TX1(events, blk_3b, blk_2, miner_acc, tx_2); + + + // extra with extra_alias_entry_old -- okay + extra_alias_entry_old alias_entry_old = AUTO_VAL_INIT(alias_entry_old); + alias_entry_old.m_address = alice_acc.get_public_address().to_old(); + alias_entry_old.m_alias = "alicealice"; + + tx_set.clear(); + r = put_alias_via_tx_to_list(events, tx_set, blk_2, miner_acc, alias_entry_old, generator); + CHECK_AND_ASSERT_MES(r, false, "put_alias_via_tx_to_list failed"); + transaction tx_2_old = tx_set.front(); + MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_2_old); + // activate HF2 - MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc); - MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc); - MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc); + MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc); + MAKE_NEXT_BLOCK(events, blk_6, blk_5, miner_acc); + MAKE_NEXT_BLOCK(events, blk_7, blk_6, miner_acc); // tx_0 with tx_payer should be accepted after HF2 - MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4, miner_acc, tx_0); + MAKE_NEXT_BLOCK_TX1(events, blk_8, blk_7, miner_acc, tx_0); // tx_1 with tx_receiver should be accepted after HF2 - MAKE_NEXT_BLOCK_TX1(events, blk_6, blk_5, miner_acc, tx_1); + MAKE_NEXT_BLOCK_TX1(events, blk_9, blk_8, miner_acc, tx_1); // tx_2 with extra_alias_entry should be accepted after HF2 - MAKE_NEXT_BLOCK_TX1(events, blk_7, blk_6, miner_acc, tx_2); + MAKE_NEXT_BLOCK_TX1(events, blk_10, blk_9, miner_acc, tx_2); + + // check aliases + DO_CALLBACK(events, "c1"); return true; } bool hard_fork_2_no_new_structures_before_hf::c1(currency::core& c, size_t ev_index, const std::vector& events) { + extra_alias_entry_base ai = AUTO_VAL_INIT(ai); + bool r = c.get_blockchain_storage().get_alias_info("alicealice", ai); + CHECK_AND_ASSERT_MES(r, false, "failed to get alias"); + CHECK_AND_ASSERT_MES(ai.m_address == m_accounts[ALICE_ACC_IDX].get_public_address(), false, "invalid address for alicealice alias"); + + ai = AUTO_VAL_INIT(ai); + r = c.get_blockchain_storage().get_alias_info("minerminer", ai); + CHECK_AND_ASSERT_MES(r, false, "failed to get alias minerminer"); + CHECK_AND_ASSERT_MES(ai.m_address == m_accounts[MINER_ACC_IDX].get_public_address(), false, "invalid address for minerminer alias"); + return true; } diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h index ca11dc17..230a72d0 100644 --- a/tests/core_tests/hard_fork_2.h +++ b/tests/core_tests/hard_fork_2.h @@ -50,6 +50,8 @@ struct hard_fork_2_auditable_addresses_basics : public wallet_test, public hard_ struct hard_fork_2_no_new_structures_before_hf : public wallet_test, public hard_fork_2_base_test { + using hard_fork_2_base_test::check_block_verification_context; // this is necessary for correct work of do_check_block_verification_context, consider rafactoring + hard_fork_2_no_new_structures_before_hf(); bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); From 586561411d00dfa65a58685f954efaffee4bb2be Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 19 May 2020 20:19:54 +0300 Subject: [PATCH 42/70] wallet2: sending to auditable addresses allowed before HF2 as well --- src/wallet/wallet2.cpp | 16 ---------------- src/wallet/wallet2.h | 1 - 2 files changed, 17 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index e923e771..4d264cfb 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -4478,28 +4478,12 @@ 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_auditable_address_is_targeted_before_hf2(const construct_tx_param& ctp) -{ - if (get_top_block_height() <= m_core_runtime_config.hard_fork_02_starts_after_height) - { - // before HF2 - for (auto& d : ctp.dsts) - { - for (auto& addr : d.addr) - { - WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!addr.is_auditable(), "sending fund to an auditable address is not supported until HF2, address = " << get_account_address_as_str(addr)); - } - } - } -} -//---------------------------------------------------------------------------------------------------- void wallet2::transfer(const construct_tx_param& ctp, currency::transaction &tx, bool send_to_network, std::string* p_signed_tx_blob_str) { check_and_throw_if_self_directed_tx_with_payment_id_requested(ctp); - check_and_throw_if_auditable_address_is_targeted_before_hf2(ctp); TIME_MEASURE_START(prepare_transaction_time); finalize_tx_param ftp = AUTO_VAL_INIT(ftp); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index bd0913fc..163b5335 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -927,7 +927,6 @@ private: bool generate_packing_transaction_if_needed(currency::transaction& tx, uint64_t fake_outputs_number); bool store_unsigned_tx_to_file_and_reserve_transfers(const 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_auditable_address_is_targeted_before_hf2(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); From 884d068274e959d95401b884639d5ca1dce6bb32 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 19 May 2020 20:21:31 +0300 Subject: [PATCH 43/70] tx_payer / tx_receiver will not be added to extra for an auditable address before HF2 --- src/currency_core/currency_format_utils.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 26f6554d..c4edefeb 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -602,10 +602,13 @@ namespace currency } else { - // before hardfork 2 - tx_payer_old result = AUTO_VAL_INIT(result); - result.acc_addr = addr.to_old(); - container.push_back(result); + // before hardfork 2 -- add only if addr is not auditable + if (!addr.is_auditable()) + { + tx_payer_old result = AUTO_VAL_INIT(result); + result.acc_addr = addr.to_old(); + container.push_back(result); + } } } //--------------------------------------------------------------- @@ -621,10 +624,13 @@ namespace currency } else { - // before hardfork 2 - tx_receiver_old result = AUTO_VAL_INIT(result); - result.acc_addr = addr.to_old(); - container.push_back(result); + // before hardfork 2 -- add only if addr is not auditable + if (!addr.is_auditable()) + { + tx_receiver_old result = AUTO_VAL_INIT(result); + result.acc_addr = addr.to_old(); + container.push_back(result); + } } } //--------------------------------------------------------------- From cfdd8bdc9c975836002b274412e8f00c70e6108e Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 19 May 2020 20:22:53 +0300 Subject: [PATCH 44/70] new core rule: new format tx_payer, tx_receiver and extra_alias_entry are not allowed before HF2 --- src/currency_core/blockchain_storage.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 89440347..59a0bfef 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -4601,6 +4601,26 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti return true; } + if (block_height <= m_core_runtime_config.hard_fork_02_starts_after_height) + { + // before hardfork 2 + + auto check_lambda = [&](const std::vector& container) -> bool + { + for (const auto& el : container) + { + const auto& type = el.type(); + CHECK_AND_ASSERT_MES(type != typeid(tx_payer), false, "tx " << tx_id << " contains tx_payer which is not allowed on height " << block_height); + CHECK_AND_ASSERT_MES(type != typeid(tx_receiver), false, "tx " << tx_id << " contains tx_receiver which is not allowed on height " << block_height); + CHECK_AND_ASSERT_MES(type != typeid(extra_alias_entry), false, "tx " << tx_id << " contains extra_alias_entry which is not allowed on height " << block_height); + } + return true; + }; + + return check_lambda(tx.extra) && check_lambda(tx.attachment); + } + + return true; } //------------------------------------------------------------------ From c1760eb66022ce210455ea802df12dd6017011bf Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 20 May 2020 16:37:23 +0300 Subject: [PATCH 45/70] wallet file signature fixed to the same length --- src/currency_core/currency_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index d6ab7052..a3e4a65d 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -144,7 +144,7 @@ #define WALLET_FILE_SIGNATURE_OLD 0x1111012101101011LL // Bender's nightmare -#define WALLET_FILE_SIGNATURE_V2 0x111101120101011LL // another Bender's nightmare +#define WALLET_FILE_SIGNATURE_V2 0x1111011201101011LL // another Bender's nightmare #define WALLET_FILE_MAX_BODY_SIZE 0x88888888L //2GB #define WALLET_FILE_MAX_KEYS_SIZE 10000 // #define WALLET_BRAIN_DATE_OFFSET 1543622400 From 6f4ecb9f3d89155fb51b4f25c8426b8df37e6f3a Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 20 May 2020 16:38:03 +0300 Subject: [PATCH 46/70] core: log hardfork passing --- src/currency_core/currency_core.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index 004df00e..05f2eeb9 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -493,7 +493,17 @@ namespace currency //----------------------------------------------------------------------------------------------- bool core::add_new_block(const block& b, block_verification_context& bvc) { - return m_blockchain_storage.add_new_block(b, bvc); + bool r = m_blockchain_storage.add_new_block(b, bvc); + if (r && bvc.m_added_to_main_chain) + { + uint64_t h = get_block_height(b); + auto& crc = m_blockchain_storage.get_core_runtime_config(); + if (h == crc.hard_fork_01_starts_after_height + 1) + { LOG_PRINT_GREEN("Hardfork 1 activated at height " << h, LOG_LEVEL_0); } + else if (h == crc.hard_fork_02_starts_after_height + 1) + { LOG_PRINT_GREEN("Hardfork 2 activated at height " << h, LOG_LEVEL_0); } + } + return r; } //----------------------------------------------------------------------------------------------- bool core::parse_block(const blobdata& block_blob, block& b, block_verification_context& bvc) From a6a8e4b1971d3d169d1ee32dc24ea6d86c91275a Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 20 May 2020 16:41:16 +0300 Subject: [PATCH 47/70] coretests: hard_fork_2_tx_payer_in_wallet and hard_fork_2_tx_receiver_in_wallet improved to cover more cases on tx_payer/tx_receiver rule --- tests/core_tests/hard_fork_2.cpp | 229 ++++++++++++++++++++++++------- 1 file changed, 177 insertions(+), 52 deletions(-) diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 8e293353..e11241a8 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -42,7 +42,7 @@ void hard_fork_2_base_test::set_hard_fork_heights_to_generator(test_generator& g //------------------------------------------------------------------------------ hard_fork_2_tx_payer_in_wallet::hard_fork_2_tx_payer_in_wallet() - : hard_fork_2_base_test(16) + : hard_fork_2_base_test(24) { REGISTER_CALLBACK_METHOD(hard_fork_2_tx_payer_in_wallet, c1); } @@ -54,11 +54,17 @@ bool hard_fork_2_tx_payer_in_wallet::generate(std::vector& eve 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(true); // Bob has auditable address MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); - REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + MAKE_TX(events, tx_0, miner_acc, bob_acc, MK_TEST_COINS(12), 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); DO_CALLBACK(events, "c1"); @@ -71,25 +77,27 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]); miner_wlt->refresh(); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, 0), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(12)), false, ""); // wallet RPC server tools::wallet_rpc_server miner_wlt_rpc(*miner_wlt); epee::json_rpc::error je; tools::wallet_rpc_server::connection_context ctx; - tools::wallet_public::COMMAND_RPC_TRANSFER::request req = AUTO_VAL_INIT(req); - tools::wallet_public::transfer_destination td{ MK_TEST_COINS(1), m_accounts[ALICE_ACC_IDX].get_public_address_str() }; - req.destinations.push_back(td); - req.fee = TESTS_DEFAULT_FEE; - req.push_payer = true; + // Before HF2: Miner -> Alice (normal address) with payer info + tools::wallet_public::COMMAND_RPC_TRANSFER::request req_a = AUTO_VAL_INIT(req_a); + req_a.destinations.push_back(tools::wallet_public::transfer_destination{ MK_TEST_COINS(1), m_accounts[ALICE_ACC_IDX].get_public_address_str() }); + req_a.fee = TESTS_DEFAULT_FEE; + req_a.push_payer = true; tools::wallet_public::COMMAND_RPC_TRANSFER::response res = AUTO_VAL_INIT(res); - r = miner_wlt_rpc.on_transfer(req, res, je, ctx); + r = miner_wlt_rpc.on_transfer(req_a, res, je, ctx); CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); crypto::hash tx_hash = null_hash; @@ -100,7 +108,78 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons r = have_type_in_variant_container(tx.extra); CHECK_AND_ASSERT_MES(r, false, "tx_payer_old is not found in extra"); + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer is found in extra"); + + // Before HF2: Miner -> Bob (auditable address) with payer info + tools::wallet_public::COMMAND_RPC_TRANSFER::request req_b = AUTO_VAL_INIT(req_b); + req_b.destinations.push_back(tools::wallet_public::transfer_destination{ MK_TEST_COINS(1), m_accounts[BOB_ACC_IDX].get_public_address_str() }); + req_b.fee = TESTS_DEFAULT_FEE; + req_b.push_payer = true; + + res = AUTO_VAL_INIT(res); + + r = miner_wlt_rpc.on_transfer(req_b, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + tx_hash = null_hash; + CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); + + tx = AUTO_VAL_INIT(tx); + CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); + + r = have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer_old is not found in extra"); + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer is found in extra"); + + + // mine a block and confirm both transactions + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + size_t callback_counter = 0; + std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( + [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + CHECK_AND_ASSERT_THROW_MES(wti.show_sender, "show_sender is false"); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 1, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); + ++callback_counter; + return true; + } + )); + alice_wlt->callback(l); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(1)), false, ""); + CHECK_AND_ASSERT_MES(callback_counter == 1, false, "callback_counter = " << callback_counter); + + bob_wlt->callback(l); // same callback -- same changes + callback_counter = 0; + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(13)), false, ""); + CHECK_AND_ASSERT_MES(callback_counter == 1, false, "callback_counter = " << callback_counter); + + alice_wlt->callback(std::make_shared()); // clear callback + bob_wlt->callback(std::make_shared()); // clear callback + + // Before HF2: Bob (auditable address) -> Alice with payer info requested (should NOT put tx_payer or tx_payer_old) + tools::wallet_rpc_server bob_wlt_rpc(*bob_wlt); + tools::wallet_public::COMMAND_RPC_TRANSFER::request req_c = AUTO_VAL_INIT(req_c); + req_c.destinations.push_back(tools::wallet_public::transfer_destination{ MK_TEST_COINS(1), m_accounts[ALICE_ACC_IDX].get_public_address_str() }); + req_c.fee = TESTS_DEFAULT_FEE; + req_c.push_payer = true; + res = AUTO_VAL_INIT(res); + r = bob_wlt_rpc.on_transfer(req_c, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + tx_hash = null_hash; + CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); + tx = AUTO_VAL_INIT(tx); + CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer_old is found in extra"); r = !have_type_in_variant_container(tx.extra); CHECK_AND_ASSERT_MES(r, false, "tx_payer is found in extra"); @@ -108,19 +187,12 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { - CHECK_AND_ASSERT_MES(wti.show_sender, false, "show_sender is false"); - CHECK_AND_ASSERT_MES(wti.remote_addresses.size() == 1, false, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); - CHECK_AND_ASSERT_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.front is incorrect"); - return true; - } - )); - alice_wlt->callback(l); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(11)), false, ""); - CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(1)), false, ""); - // mine blocks 15, 16, 17 to activate HF2 + // + // mine blocks 24, 25, 26 to activate HF2 + // r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 3); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -128,9 +200,9 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons miner_wlt->refresh(); alice_wlt->refresh(); - // check again - req.destinations.front().amount = MK_TEST_COINS(2); - r = miner_wlt_rpc.on_transfer(req, res, je, ctx); + // check again (Miner -> Alice), with different amount + req_a.destinations.front().amount = MK_TEST_COINS(2); + r = miner_wlt_rpc.on_transfer(req_a, res, je, ctx); CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -143,22 +215,72 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons r = !have_type_in_variant_container(tx.extra); CHECK_AND_ASSERT_MES(r, false, "tx_payer_old is found in extra"); + + // check again (Miner -> Bob), with different amount + req_b.destinations.front().amount = MK_TEST_COINS(2); + r = miner_wlt_rpc.on_transfer(req_b, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + tx_hash = null_hash; + CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); + CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); + + r = have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer is not found in extra"); + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer_old is found in extra"); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { - CHECK_AND_ASSERT_MES(wti.amount == MK_TEST_COINS(2), false, "incorrect wti.amount = " << print_money_brief(wti.amount)); - CHECK_AND_ASSERT_MES(wti.show_sender, false, "show_sender is false"); - CHECK_AND_ASSERT_MES(wti.remote_addresses.size() == 1, false, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); - CHECK_AND_ASSERT_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.front is incorrect"); + CHECK_AND_ASSERT_THROW_MES(wti.amount == MK_TEST_COINS(2), "incorrect wti.amount = " << print_money_brief(wti.amount)); + CHECK_AND_ASSERT_THROW_MES(wti.show_sender, "show_sender is false"); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 1, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); + ++callback_counter; return true; } )); - alice_wlt->callback(l2); - CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(3)), false, ""); + alice_wlt->callback(l2); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(4)), false, ""); + + bob_wlt->callback(l2); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(13)), false, ""); + + alice_wlt->callback(std::make_shared()); // clear callback + bob_wlt->callback(std::make_shared()); // clear callback + + // After HF2: Bob (auditable address) -> Alice with payer info requested (should put tx_payer) + req_c = AUTO_VAL_INIT(req_c); + req_c.destinations.push_back(tools::wallet_public::transfer_destination{ MK_TEST_COINS(1), m_accounts[ALICE_ACC_IDX].get_public_address_str() }); + req_c.fee = TESTS_DEFAULT_FEE; + req_c.push_payer = true; + res = AUTO_VAL_INIT(res); + r = bob_wlt_rpc.on_transfer(req_c, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "on_transfer failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + tx_hash = null_hash; + CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); + tx = AUTO_VAL_INIT(tx); + CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); + r = !have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer_old is found in extra"); + r = have_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(r, false, "tx_payer is NOT found in extra"); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(5)), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(11)), false, ""); return true; } @@ -179,7 +301,7 @@ bool hard_fork_2_tx_receiver_in_wallet::generate(std::vector& 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(); + account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(true); // Bob has auditable address MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); set_hard_fork_heights_to_generator(generator); @@ -203,9 +325,11 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]); std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]); miner_wlt->refresh(); CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, m_alice_start_balance), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, 0), false, ""); // wallet RPC server tools::wallet_rpc_server alice_wlt_rpc(*alice_wlt); @@ -213,15 +337,14 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c tools::wallet_rpc_server::connection_context ctx; tools::wallet_public::COMMAND_RPC_TRANSFER::request req = AUTO_VAL_INIT(req); - tools::wallet_public::transfer_destination td1{ MK_TEST_COINS(1), m_accounts[MINER_ACC_IDX].get_public_address_str() }; - tools::wallet_public::transfer_destination td2{ MK_TEST_COINS(1), m_accounts[BOB_ACC_IDX].get_public_address_str() }; - req.destinations.push_back(td1); - req.destinations.push_back(td2); + req.destinations.push_back(tools::wallet_public::transfer_destination { MK_TEST_COINS(1), m_accounts[MINER_ACC_IDX].get_public_address_str() }); + req.destinations.push_back(tools::wallet_public::transfer_destination { MK_TEST_COINS(1), m_accounts[BOB_ACC_IDX].get_public_address_str() }); // auditable address req.fee = TESTS_DEFAULT_FEE; - req.hide_receiver = false; // just to emphasize, this is false be default + req.hide_receiver = false; // just to emphasize, this is false by default LOG_PRINT_L0("Miner's address: " << m_accounts[MINER_ACC_IDX].get_public_address_str()); LOG_PRINT_L0("Alice's address: " << m_accounts[ALICE_ACC_IDX].get_public_address_str()); + LOG_PRINT_L0("Bob's address: " << m_accounts[BOB_ACC_IDX].get_public_address_str()); tools::wallet_public::COMMAND_RPC_TRANSFER::response res = AUTO_VAL_INIT(res); @@ -236,11 +359,12 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c transaction tx = AUTO_VAL_INIT(tx); CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); - r = have_type_in_variant_container(tx.extra); - CHECK_AND_ASSERT_MES(r, false, "tx_receiver_old is not found in extra"); + // there should be one tx_receiver_old, as Bob's auditable address should not be supported for tx_receiver + size_t count = count_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(count == 1, false, "tx_receiver_old count: " << count); - r = !have_type_in_variant_container(tx.extra); - CHECK_AND_ASSERT_MES(r, false, "tx_receiver is found in extra"); + count = count_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(count == 0, false, "tx_receiver count: " << count); r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); @@ -248,10 +372,10 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { - CHECK_AND_ASSERT_MES(!wti.is_income, false, "wti.is_income is " << wti.is_income); - CHECK_AND_ASSERT_MES(wti.remote_addresses.size() == 2, false, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); - CHECK_AND_ASSERT_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.front is incorrect"); - CHECK_AND_ASSERT_MES(wti.remote_addresses.back() == m_accounts[BOB_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.back is incorrect"); + CHECK_AND_ASSERT_THROW_MES(!wti.is_income, "wti.is_income is " << wti.is_income); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 2, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.back() == m_accounts[BOB_ACC_IDX].get_public_address_str(), "wti.remote_addresses.back is incorrect"); return true; } )); @@ -278,10 +402,11 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(res.tx_hash, tx_hash), false, ""); CHECK_AND_ASSERT_MES(c.get_transaction(tx_hash, tx), false, ""); - r = have_type_in_variant_container(tx.extra); - CHECK_AND_ASSERT_MES(r, false, "tx_receiver is not found in extra"); - r = !have_type_in_variant_container(tx.extra); - CHECK_AND_ASSERT_MES(r, false, "tx_receiver_old is found in extra"); + // shouold be 2 tx_receiver as we passed HF2 and auditable addresses CAN be used with tx_receiver + count = count_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(count == 2, false, "tx_receiver count = " << count); + count = count_type_in_variant_container(tx.extra); + CHECK_AND_ASSERT_MES(count == 0, false, "tx_receiver_old count = " << count); r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); @@ -289,11 +414,11 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { - CHECK_AND_ASSERT_MES(!wti.is_income, false, "wti.is_income is " << wti.is_income); - CHECK_AND_ASSERT_MES(wti.amount == MK_TEST_COINS(4), false, "incorrect wti.amount = " << print_money_brief(wti.amount)); - CHECK_AND_ASSERT_MES(wti.remote_addresses.size() == 2, false, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); - CHECK_AND_ASSERT_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.front is incorrect"); - CHECK_AND_ASSERT_MES(wti.remote_addresses.back() == m_accounts[BOB_ACC_IDX].get_public_address_str(), false, "wti.remote_addresses.back is incorrect"); + CHECK_AND_ASSERT_THROW_MES(!wti.is_income, "wti.is_income is " << wti.is_income); + CHECK_AND_ASSERT_THROW_MES(wti.amount == MK_TEST_COINS(4), "incorrect wti.amount = " << print_money_brief(wti.amount)); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 2, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); + CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.back() == m_accounts[BOB_ACC_IDX].get_public_address_str(), "wti.remote_addresses.back is incorrect"); return true; } )); From 80d7f4b00331a6adb78a6ff08df9b0bafb25039e Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 20 May 2020 17:39:42 +0300 Subject: [PATCH 48/70] wallet: forbid aliases to auditable addresses reg/update prior to HF2 --- src/wallet/wallet2.cpp | 25 +++++++++++++++++-------- src/wallet/wallet2.h | 2 ++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4d264cfb..3023a1bb 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3121,6 +3121,21 @@ void wallet2::update_offer_by_id(const crypto::hash& tx_id, uint64_t of_ind, con transfer(destinations, 0, 0, od.fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx); } //---------------------------------------------------------------------------------------------------- +void wallet2::push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector& extra) +{ + if (get_top_block_height() > m_core_runtime_config.hard_fork_02_starts_after_height) + { + // after HF2 + extra.push_back(ai); + } + else + { + // before HF2 + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!ai.m_address.is_auditable(), "auditable addresses are not supported in aliases prior to HF2"); + extra.push_back(ai.to_old()); + } +} +//---------------------------------------------------------------------------------------------------- void wallet2::request_alias_registration(const currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward) { if (!validate_alias_name(ai.m_alias)) @@ -3132,10 +3147,7 @@ void wallet2::request_alias_registration(const currency::extra_alias_entry& ai, std::vector extra; std::vector attachments; - if (get_top_block_height() > m_core_runtime_config.hard_fork_02_starts_after_height) - extra.push_back(ai); - else - extra.push_back(ai.to_old()); + push_alias_info_to_extra_according_to_hf_status(ai, extra); currency::tx_destination_entry tx_dest_alias_reward; tx_dest_alias_reward.addr.resize(1); @@ -3166,10 +3178,7 @@ void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::tr std::vector extra; std::vector attachments; - if (get_top_block_height() > m_core_runtime_config.hard_fork_02_starts_after_height) - extra.push_back(ai); - else - extra.push_back(ai.to_old()); + push_alias_info_to_extra_according_to_hf_status(ai, extra); transfer(destinations, 0, 0, fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false); } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 163b5335..b93a8493 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -934,6 +934,8 @@ private: uint64_t detach_from_block_ids(uint64_t height); uint64_t get_wallet_minimum_height(); + void push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector& extra); + currency::account_base m_account; bool m_watch_only; std::string m_log_prefix; // part of pub address, prefix for logging functions From 1815655da758d3eeb91c639c7f2df1b7be42d109 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 20 May 2020 17:41:46 +0300 Subject: [PATCH 49/70] coretests: hard_fork_2_tx_extra_alias_entry_in_wallet greatly improved to check alias reg/update to an auditable address before/after the HF2 --- tests/core_tests/hard_fork_2.cpp | 107 ++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 10 deletions(-) diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index e11241a8..76c70701 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -432,7 +432,7 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c //------------------------------------------------------------------------------ hard_fork_2_tx_extra_alias_entry_in_wallet::hard_fork_2_tx_extra_alias_entry_in_wallet() - : hard_fork_2_base_test(22) + : hard_fork_2_base_test(23) { REGISTER_CALLBACK_METHOD(hard_fork_2_tx_extra_alias_entry_in_wallet, c1); } @@ -442,7 +442,7 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::generate(std::vector(res_tx.extra); CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry is found in extra"); - // mine few block to activate HF2 - r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 3); + // before the HF2 an alias to an auditable address is not supported + extra_alias_entry ai_bob = AUTO_VAL_INIT(ai_bob); + ai_bob.m_alias = "bobbobbob"; + ai_bob.m_address = m_accounts[BOB_ACC_IDX].get_public_address(); + alias_reward = get_alias_coast_from_fee(ai_bob.m_alias, TESTS_DEFAULT_FEE); + res_tx = AUTO_VAL_INIT(res_tx); + r = false; + try + { + alice_wlt->request_alias_registration(ai_bob, res_tx, TESTS_DEFAULT_FEE, alias_reward); + } + catch (...) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "exception was not cought as expected"); + + // should be still one tx in the pool + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); - + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + // try to update Alice's alias to an auditable address + extra_alias_entry ai_alice_update = ai; + ai_alice_update.m_text_comment = "Update to auditable"; + ai_alice_update.m_address = m_accounts[BOB_ACC_IDX].get_public_address(); // auditable + CHECK_AND_ASSERT_MES(ai_alice_update.m_address.is_auditable(), false, "address is not auditable"); + r = false; + try + { + alice_wlt->request_alias_update(ai_alice_update, res_tx, TESTS_DEFAULT_FEE, 0); + } + catch (...) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "exception was not cought as expected"); + + + // mine few blocks to activate HF2 + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 2); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + CHECK_AND_ASSERT_MES(c.get_current_blockchain_size() == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 4, false, "Incorrect blockchain size"); alice_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_ASSERT_MES(blocks_fetched == 3, false, "Incorrect numbers of blocks fetched"); // update alias, change comment and address - ai.m_text_comment = "Update!"; + ai.m_text_comment = "Update to normal"; ai.m_address = m_accounts[MINER_ACC_IDX].get_public_address(); alice_wlt->request_alias_update(ai, res_tx, TESTS_DEFAULT_FEE, 0); @@ -518,10 +559,56 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry_old is found in extra"); // make sure alias was updated indeed - extra_alias_entry ai2 = AUTO_VAL_INIT(ai2); - r = c.get_blockchain_storage().get_alias_info(ai.m_alias, ai2); + extra_alias_entry ai_check = AUTO_VAL_INIT(ai_check); + r = c.get_blockchain_storage().get_alias_info(ai.m_alias, ai_check); CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); - CHECK_AND_ASSERT_MES(ai2.m_text_comment == ai.m_text_comment && ai2.m_address == m_accounts[MINER_ACC_IDX].get_public_address(), + CHECK_AND_ASSERT_MES(ai_check.m_text_comment == ai.m_text_comment && ai_check.m_address == m_accounts[MINER_ACC_IDX].get_public_address(), + false, "Incorrect alias info retunred by get_alias_info"); + + + // make sure an alias to auditable address can be registered now + alice_wlt->request_alias_registration(ai_bob, res_tx, TESTS_DEFAULT_FEE, alias_reward); + // after HF2: extra_alias_entry should be here, not extra_alias_entry_old + r = have_type_in_variant_container(res_tx.extra); + CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry is not found in extra"); + r = !have_type_in_variant_container(res_tx.extra); + CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry_old is found in extra"); + + // miner a block to confirm it + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + + // make sure alias was updated to an auditable address indeed + ai_check = AUTO_VAL_INIT(ai_check); + r = c.get_blockchain_storage().get_alias_info(ai_bob.m_alias, ai_check); + CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); + CHECK_AND_ASSERT_MES(ai_check.m_text_comment == ai_bob.m_text_comment && ai_check.m_address == m_accounts[BOB_ACC_IDX].get_public_address(), + false, "Incorrect alias info retunred by get_alias_info"); + + miner_wlt->refresh(); + + // update alias once again, change comment and address to auditable + // alias updated by miner, as he's the owner now + miner_wlt->request_alias_update(ai_alice_update, res_tx, TESTS_DEFAULT_FEE, 0); + + // after HF2: extra_alias_entry should be here, not extra_alias_entry_old + r = have_type_in_variant_container(res_tx.extra); + CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry is not found in extra"); + r = !have_type_in_variant_container(res_tx.extra); + CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry_old is found in extra"); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + + // make sure alias was updated to an auditable address indeed + ai_check = AUTO_VAL_INIT(ai_check); + r = c.get_blockchain_storage().get_alias_info(ai_alice_update.m_alias, ai_check); + CHECK_AND_ASSERT_MES(r, false, "get_alias_info failed"); + CHECK_AND_ASSERT_MES(ai_check.m_text_comment == ai_alice_update.m_text_comment && ai_check.m_address == m_accounts[BOB_ACC_IDX].get_public_address(), false, "Incorrect alias info retunred by get_alias_info"); return true; From 36326e581fd0614faf20a53009c420039b9ca17c Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 25 May 2020 15:05:25 +0300 Subject: [PATCH 50/70] wallet: handling auditable coins (WIP) --- src/currency_core/currency_config.h | 2 +- src/wallet/wallet2.cpp | 83 ++++++++++++++++++++++------- src/wallet/wallet2.h | 9 +++- 3 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 40c71f7c..b599c604 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -220,7 +220,7 @@ #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" -#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+66) +#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+67) #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1d251ddc..a5023397 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -265,8 +265,35 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t { const currency::txin_to_key& intk = boost::get(in); - // TODO: check for references to our UTXO (auditability) - // intk.key_offsets; + if (is_auditable()) + { + // auditable wallet + // try to find a reference among own UTXOs + std::vector abs_key_offsets = relative_output_offsets_to_absolute(intk.key_offsets); + for(auto v : abs_key_offsets) + { + if (v.type() != typeid(uint64_t)) + continue; + uint64_t gindex = boost::get(v); + auto it = m_amount_gindex_to_transfer_id.find(std::make_pair(intk.amount, gindex)); + if (it != m_amount_gindex_to_transfer_id.end()) + { + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "invalid tid: " << it->second << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex); + auto& td = m_transfers[it->second]; + if (intk.key_offsets.size() != 1) + { + // own output was used in non-direct transaction + // the core should not allow this to happen, the only way it may happen - mixing in own output that was sent without mix_attr == 1 + // log strange situation + LOG_PRINT_YELLOW("own transfer tid=" << it->second << " tx=" << td.tx_hash() << " mix_attr=" << td.mix_attr() << ", is referenced by a transaction with mixins, ref from input with amount: " << intk.amount << ", gindex: " << gindex , LOG_LEVEL_0); + continue; + } + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!td.is_spent(), "transfer is spent, tid: " << it->second << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex); + // own output is spent, handle it + /// + } + } + } auto it = m_key_images.find(intk.k_image); if (it != m_key_images.end()) @@ -347,21 +374,21 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t if (m_watch_only) { if (!is_auditable()) - { - // don't have spend secret key, so we unable to calculate key image for an output - // look it up in special container instead - auto it = m_pending_key_images.find(otk.key); - if (it != m_pending_key_images.end()) { - ki = it->second; - WLT_LOG_L1("pending key image " << ki << " was found by out pub key " << otk.key); + // don't have spend secret key, so we unable to calculate key image for an output + // look it up in special container instead + auto it = m_pending_key_images.find(otk.key); + if (it != m_pending_key_images.end()) + { + ki = it->second; + WLT_LOG_L1("pending key image " << ki << " was found by out pub key " << otk.key); + } + else + { + ki = currency::null_ki; + WLT_LOG_L1("can't find pending key image by out pub key: " << otk.key << ", key image temporarily set to null"); + } } - else - { - ki = currency::null_ki; - WLT_LOG_L1("can't find pending key image by out pub key: " << otk.key << ", key image temporarily set to null"); - } - } } else { @@ -373,6 +400,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t if (ki != currency::null_ki) { + // make sure calculated key image for this own output has not been seen before auto it = m_key_images.find(ki); if (it != m_key_images.end()) { @@ -407,6 +435,10 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t if (td.m_key_image != currency::null_ki) m_key_images[td.m_key_image] = transfer_index; add_transfer_to_transfers_cache(tx.vout[o].amount, transfer_index); + uint64_t amount = tx.vout[o].amount; + + r = m_amount_gindex_to_transfer_id.insert(std::make_pair(std::make_pair(amount, td.m_global_output_index), transfer_index)).second; + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "cannot update m_amount_gindex_to_transfer_id: amount " << amount << ", gindex " << td.m_global_output_index << " already exists"); if (max_out_unlock_time < get_tx_unlock_time(tx, o)) max_out_unlock_time = get_tx_unlock_time(tx, o); @@ -1811,6 +1843,17 @@ uint64_t wallet2::detach_from_block_ids(uint64_t including_height) return blocks_detached; } //---------------------------------------------------------------------------------------------------- +void wallet2::remove_transfer_from_amount_gindex_map(uint64_t tid) +{ + for (auto it = m_amount_gindex_to_transfer_id.begin(); it != m_amount_gindex_to_transfer_id.end(); ) + { + if (it->second == tid) + it = m_amount_gindex_to_transfer_id.erase(it); + else + ++it; + } +} +//---------------------------------------------------------------------------------------------------- void wallet2::detach_blockchain(uint64_t including_height) { WLT_LOG_L0("Detaching blockchain on height " << including_height); @@ -1829,6 +1872,7 @@ void wallet2::detach_blockchain(uint64_t including_height) WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it_ki != m_key_images.end(), "key image " << m_transfers[i].m_key_image << " not found"); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_transfers[i].m_ptx_wallet_info->m_block_height >= including_height, "transfer #" << i << " block height is less than " << including_height); m_key_images.erase(it_ki); + remove_transfer_from_amount_gindex_map(i); ++transfers_detached; } m_transfers.erase(it, m_transfers.end()); @@ -1914,6 +1958,7 @@ bool wallet2::reset_all() //m_blockchain.clear(); m_chain.clear(); m_transfers.clear(); + m_amount_gindex_to_transfer_id.clear(); m_key_images.clear(); // m_pending_key_images is not cleared intentionally m_unconfirmed_in_transfers.clear(); @@ -2170,14 +2215,16 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) if (m_watch_only) load_keys2ki(true, need_to_resync); + WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) << " with public address: " << m_account.get_public_address_str()); + WLT_LOG_L0("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")"); + if (need_to_resync) { reset_history(); + WLT_LOG_L0("Unable to load history data from wallet file, wallet will be resynced!"); } - THROW_IF_TRUE_WALLET_EX(need_to_resync, error::wallet_load_notice_wallet_restored, epee::string_encoding::convert_to_ansii(m_wallet_file)); - WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) << " with public address: " << m_account.get_public_address_str()); - WLT_LOG_L0("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")"); + THROW_IF_TRUE_WALLET_EX(need_to_resync, error::wallet_load_notice_wallet_restored, epee::string_encoding::convert_to_ansii(m_wallet_file)); } //---------------------------------------------------------------------------------------------------- void wallet2::store() diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index b93a8493..595bfe2d 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -380,6 +380,9 @@ namespace tools uint32_t m_flags; uint64_t amount() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index].amount; } + const currency::tx_out& output() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index]; } + uint8_t mix_attr() const { return output().target.type() == typeid(currency::txout_to_key) ? boost::get(output().target).mix_attr : UINT8_MAX; } + crypto::hash tx_hash() const { return get_transaction_hash(m_ptx_wallet_info->m_tx); } bool is_spent() const { return m_flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT; } bool is_spendable() const { return (m_flags & (WALLET_TRANSFER_DETAIL_FLAG_SPENT | WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION | WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION)) == 0; } bool is_reserved_for_escrow() const { return ( (m_flags & WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) != 0 ); } @@ -443,6 +446,7 @@ namespace tools typedef std::unordered_map multisig_transfer_container; typedef std::unordered_map escrow_contracts_container; typedef std::map > free_amounts_cache_type; + typedef std::unordered_map, uint64_t> amount_gindex_to_transfer_id_container; // maps [amount; gindex] -> tid struct keys_file_data_old @@ -503,7 +507,7 @@ namespace tools //i_wallet2_callback* callback() const { return m_wcallback; } //void callback(i_wallet2_callback* callback) { m_callback = callback; } - void callback(std::shared_ptr callback) { m_wcallback = callback; m_do_rise_transfer = true; } + void callback(std::shared_ptr callback) { m_wcallback = callback; m_do_rise_transfer = (callback != nullptr); } void set_do_rise_transfer(bool do_rise) { m_do_rise_transfer = do_rise; } bool has_related_alias_entry_unconfirmed(const currency::transaction& tx); @@ -724,6 +728,7 @@ namespace tools a & m_transfers; a & m_multisig_transfers; + a & m_amount_gindex_to_transfer_id; a & m_key_images; a & m_unconfirmed_txs; a & m_unconfirmed_multisig_transfers; @@ -935,6 +940,7 @@ private: uint64_t get_wallet_minimum_height(); void push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector& extra); + void remove_transfer_from_amount_gindex_map(uint64_t tid); currency::account_base m_account; bool m_watch_only; @@ -950,6 +956,7 @@ private: transfer_container m_transfers; multisig_transfer_container m_multisig_transfers; + amount_gindex_to_transfer_id_container m_amount_gindex_to_transfer_id; payment_container m_payments; std::unordered_map m_key_images; std::unordered_map m_pending_key_images; // (out_pk -> ki) pairs of change outputs to be added in watch-only wallet without spend sec key From 76f3318555377af5709adf95314da9ed9313f067 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 26 May 2020 13:23:26 +0300 Subject: [PATCH 51/70] simplewallet: i_wallet2_callback: added "override", changed on_money_received/on_money_spent to on_transfer2 --- src/simplewallet/simplewallet.cpp | 23 ++++++++--------------- src/simplewallet/simplewallet.h | 5 ++--- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index dcbea8ab..1c847e00 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -593,22 +593,15 @@ void simple_wallet::on_new_block(uint64_t height, const currency::block& block) m_refresh_progress_reporter.update(height, false); } //---------------------------------------------------------------------------------------------------- -void simple_wallet::on_money_received(uint64_t height, const currency::transaction& tx, size_t out_index) +void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) { - message_writer(epee::log_space::console_color_green, false) << - "Height " << height << - ", transaction " << get_transaction_hash(tx) << - ", received " << print_money(tx.vout[out_index].amount); - m_refresh_progress_reporter.update(height, true); -} -//---------------------------------------------------------------------------------------------------- -void simple_wallet::on_money_spent(uint64_t height, const currency::transaction& in_tx, size_t out_index, const currency::transaction& spend_tx) -{ - message_writer(epee::log_space::console_color_magenta, false) << - "Height " << height << - ", transaction " << get_transaction_hash(spend_tx) << - ", spent " << print_money(in_tx.vout[out_index].amount); - m_refresh_progress_reporter.update(height, true); + epee::log_space::console_colors color = wti.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta; + message_writer(color, false) << + "height " << wti.height << + ", tx " << wti.tx_hash << + (wti.is_income ? ", received " : ", spent ") << print_money_brief(wti.amount) << + ", balance: " << print_money_brief(balance); + m_refresh_progress_reporter.update(wti.height, true); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::refresh(const std::vector& args) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index c1ea6d04..d8595c19 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -93,9 +93,8 @@ namespace currency bool try_connect_to_daemon(); //----------------- i_wallet2_callback --------------------- - virtual void on_new_block(uint64_t height, const currency::block& block); - virtual void on_money_received(uint64_t height, const currency::transaction& tx, size_t out_index); - virtual void on_money_spent(uint64_t height, const currency::transaction& in_tx, size_t out_index, const currency::transaction& spend_tx); + virtual void on_new_block(uint64_t height, const currency::block& block) override; + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override; //---------------------------------------------------------- friend class refresh_progress_reporter_t; From c1ba75db3febb2db1f51ec38d07c490ba3826acc Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 26 May 2020 13:25:03 +0300 Subject: [PATCH 52/70] simplewallet: on_message implemented for urgent messages from wallet2 --- src/simplewallet/simplewallet.cpp | 13 ++++++++++++- src/simplewallet/simplewallet.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 1c847e00..f228ad78 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -463,7 +463,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_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str(); + 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(); if (m_print_brain_wallet) std::cout << "Brain wallet: " << m_wallet->get_account().get_restore_braindata() << std::endl << std::flush; @@ -604,6 +604,17 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf m_refresh_progress_reporter.update(wti.height, true); } //---------------------------------------------------------------------------------------------------- +void simple_wallet::on_message(i_wallet2_callback::message_severity severity, const std::string& m) +{ + epee::log_space::console_colors color = epee::log_space::console_color_white; + if (severity == i_wallet2_callback::ms_red) + color = epee::log_space::console_color_red; + else if (severity == i_wallet2_callback::ms_yellow) + color = epee::log_space::console_color_yellow; + + message_writer(color, true, std::string()) << m; +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::refresh(const std::vector& args) { if (m_offline_mode) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index d8595c19..a99f62a5 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -95,6 +95,8 @@ namespace currency //----------------- i_wallet2_callback --------------------- virtual void on_new_block(uint64_t height, const currency::block& block) override; virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override; + virtual void on_message(i_wallet2_callback::message_severity severity, const std::string& m) override; + //---------------------------------------------------------- friend class refresh_progress_reporter_t; From 200494027fecd985e64ca4c30e73e52ff3296ae1 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 26 May 2020 13:28:24 +0300 Subject: [PATCH 53/70] auditability works in simplewallet --- src/wallet/wallet2.cpp | 63 ++++++++++++++++++++++++++++++++---------- src/wallet/wallet2.h | 23 ++++++++++++++- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a5023397..c1e19783 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -264,12 +264,16 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t if (in.type() == typeid(currency::txin_to_key)) { const currency::txin_to_key& intk = boost::get(in); + + // check if this input spends our output + transfer_details* p_td = nullptr; + uint64_t tid = UINT64_MAX; - if (is_auditable()) + if (is_auditable() && is_watch_only()) { // auditable wallet // try to find a reference among own UTXOs - std::vector abs_key_offsets = relative_output_offsets_to_absolute(intk.key_offsets); + std::vector abs_key_offsets = relative_output_offsets_to_absolute(intk.key_offsets); // potential speed-up: don't convert to abs offsets as we interested only in direct spends for auditable wallets. Now it's kind a bit paranoid. for(auto v : abs_key_offsets) { if (v.type() != typeid(uint64_t)) @@ -278,28 +282,41 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t auto it = m_amount_gindex_to_transfer_id.find(std::make_pair(intk.amount, gindex)); if (it != m_amount_gindex_to_transfer_id.end()) { - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "invalid tid: " << it->second << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex); + tid = it->second; + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(tid < m_transfers.size(), "invalid tid: " << tid << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex); auto& td = m_transfers[it->second]; if (intk.key_offsets.size() != 1) { // own output was used in non-direct transaction // the core should not allow this to happen, the only way it may happen - mixing in own output that was sent without mix_attr == 1 // log strange situation - LOG_PRINT_YELLOW("own transfer tid=" << it->second << " tx=" << td.tx_hash() << " mix_attr=" << td.mix_attr() << ", is referenced by a transaction with mixins, ref from input with amount: " << intk.amount << ", gindex: " << gindex , LOG_LEVEL_0); + std::stringstream ss; + ss << "own transfer tid=" << tid << " tx=" << td.tx_hash() << " mix_attr=" << td.mix_attr() << ", is referenced by a transaction with mixins, ref from input with amount: " << intk.amount << ", gindex: " << gindex; + WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0); + if (m_wcallback) + m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); continue; } - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!td.is_spent(), "transfer is spent, tid: " << it->second << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!td.is_spent(), "transfer is spent, tid: " << tid << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex); // own output is spent, handle it - /// + break; } } } + else + { + // wallet with spend secret key -- we can calculate own key images and then search by them + auto it = m_key_images.find(intk.k_image); + if (it != m_key_images.end()) + { + tid = it->second; + } + } - auto it = m_key_images.find(intk.k_image); - if (it != m_key_images.end()) + if (tid != UINT64_MAX) { tx_money_spent_in_ins += intk.amount; - transfer_details& td = m_transfers[it->second]; + transfer_details& td = m_transfers[tid]; uint32_t flags_before = td.m_flags; td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; td.m_spent_height = height; @@ -307,10 +324,10 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t is_derived_from_coinbase = true; else is_derived_from_coinbase = false; - WLT_LOG_L0("Spent key out, transfer #" << it->second << ", amount: " << print_money(m_transfers[it->second].amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height << + WLT_LOG_L0("Spent key out, transfer #" << tid << ", amount: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height << "; flags: " << flags_before << " -> " << td.m_flags); mtd.spent_indices.push_back(i); - remove_transfer_from_expiration_list(it->second); + remove_transfer_from_expiration_list(tid); } } else if (in.type() == typeid(currency::txin_multisig)) @@ -406,15 +423,30 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t { WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "m_key_images entry has wrong m_transfers index, it->second: " << it->second << ", m_transfers.size(): " << m_transfers.size()); const transfer_details& local_td = m_transfers[it->second]; - WLT_LOG_YELLOW("tx " << get_transaction_hash(tx) << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" << + std::stringstream ss; + ss << "tx " << get_transaction_hash(tx) << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" << local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) << " @ block " << local_td.m_spent_height << - ". This output can't ever be spent and will be skipped.", LOG_LEVEL_0); + ". This output can't ever be spent and will be skipped."; + WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0); + if (m_wcallback) + m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(tx_money_got_in_outs >= tx.vout[o].amount, "tx_money_got_in_outs: " << tx_money_got_in_outs << ", tx.vout[o].amount:" << tx.vout[o].amount); tx_money_got_in_outs -= tx.vout[o].amount; continue; // skip the output } } + if (is_auditable() && otk.mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + { + std::stringstream ss; + ss << "output #" << o << " from tx " << get_transaction_hash(tx) << " with amount " << print_money_brief(tx.vout[o].amount) + << " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)otk.mix_attr << ". Output will be IGNORED."; + WLT_LOG_RED(ss.str(), LOG_LEVEL_0); + if (m_wcallback) + m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str()); + continue; // skip the output + } + mtd.receive_indices.push_back(o); m_transfers.push_back(boost::value_initialized()); @@ -437,8 +469,9 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t add_transfer_to_transfers_cache(tx.vout[o].amount, transfer_index); uint64_t amount = tx.vout[o].amount; - r = m_amount_gindex_to_transfer_id.insert(std::make_pair(std::make_pair(amount, td.m_global_output_index), transfer_index)).second; - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "cannot update m_amount_gindex_to_transfer_id: amount " << amount << ", gindex " << td.m_global_output_index << " already exists"); + auto amount_gindex_pair = std::make_pair(amount, td.m_global_output_index); + WLT_CHECK_AND_ASSERT_MES_NO_RET(m_amount_gindex_to_transfer_id.count(amount_gindex_pair) == 0, "update m_amount_gindex_to_transfer_id: amount " << amount << ", gindex " << td.m_global_output_index << " already exists"); + m_amount_gindex_to_transfer_id[amount_gindex_pair] = transfer_index; if (max_out_unlock_time < get_tx_unlock_time(tx, o)) max_out_unlock_time = get_tx_unlock_time(tx, o); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 595bfe2d..f9b3498f 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -72,6 +72,22 @@ const uint64_t WALLET_MINIMUM_HEIGHT_UNSET_CONST = std::numeric_limits class test_generator; +namespace std +{ + + template + struct hash> + { + size_t operator()(const pair& p) const + { + auto hash1 = hash{}(p.first); + auto hash2 = hash{}(p.second); + return hash1 ^ hash2; + } + }; + +} // namespace std + namespace tools { #pragma pack(push, 1) @@ -94,6 +110,8 @@ namespace tools class i_wallet2_callback { public: + enum message_severity { ms_red, ms_yellow, ms_normal }; + virtual ~i_wallet2_callback() = default; virtual void on_new_block(uint64_t /*height*/, const currency::block& /*block*/) {} @@ -101,6 +119,7 @@ namespace tools virtual void on_pos_block_found(const currency::block& /*block*/) {} virtual void on_sync_progress(const uint64_t& /*percents*/) {} virtual void on_transfer_canceled(const wallet_public::wallet_transfer_info& wti) {} + virtual void on_message(message_severity /*severity*/, const std::string& /*m*/) {} }; struct tx_dust_policy @@ -725,10 +744,12 @@ namespace tools a & m_minimum_height; } + // v151: m_amount_gindex_to_transfer_id added + if (ver >= 151) + a & m_amount_gindex_to_transfer_id; a & m_transfers; a & m_multisig_transfers; - a & m_amount_gindex_to_transfer_id; a & m_key_images; a & m_unconfirmed_txs; a & m_unconfirmed_multisig_transfers; From 33cf01ff345fd0993cbbc34ede60c1e0c71e61f2 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 26 May 2020 15:55:58 +0300 Subject: [PATCH 54/70] better transfers logging and code clean-up --- src/common/make_hashable.h | 20 +++++++++++++++++++- src/simplewallet/simplewallet.cpp | 18 ++++++++++++++++-- src/wallet/wallet2.h | 19 ++----------------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/common/make_hashable.h b/src/common/make_hashable.h index af18f478..c22bfa45 100644 --- a/src/common/make_hashable.h +++ b/src/common/make_hashable.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2020 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Copyright (c) 2012-2013 The Boolberry developers @@ -37,3 +37,21 @@ namespace std { \ } \ }; \ } + +namespace std +{ + + // this allows using std::pair<> as a key in unordered std containers + template + struct hash> + { + size_t operator()(const pair& p) const + { + auto hash1 = hash{}(p.first); + auto hash2 = hash{}(p.second); + return hash1 ^ hash2; + } + }; + +} // namespace std + diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index f228ad78..117b1771 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -593,14 +593,28 @@ void simple_wallet::on_new_block(uint64_t height, const currency::block& block) m_refresh_progress_reporter.update(height, false); } //---------------------------------------------------------------------------------------------------- +std::string print_money_trailing_zeros_replaced_with_spaces(uint64_t amount) +{ + std::string s = print_money(amount); + size_t p = s.find_last_not_of('0'); + if (p != std::string::npos) + { + if (s[p] == '.') + ++p; + size_t l = s.length() - p - 1; + return s.replace(p + 1, l, l, ' '); + } + return s; +} +//---------------------------------------------------------------------------------------------------- void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) { epee::log_space::console_colors color = wti.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta; message_writer(color, false) << "height " << wti.height << ", tx " << wti.tx_hash << - (wti.is_income ? ", received " : ", spent ") << print_money_brief(wti.amount) << - ", balance: " << print_money_brief(balance); + " " << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(wti.amount) << (wti.is_income ? " received," : " spent, ") << + " balance: " << print_money_brief(balance); m_refresh_progress_reporter.update(wti.height, true); } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f9b3498f..00f27450 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2020 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 @@ -24,6 +24,7 @@ #include "currency_core/account_boost_serialization.h" #include "currency_core/currency_format_utils.h" +#include "common/make_hashable.h" #include "wallet_public_structs_defs.h" #include "currency_core/currency_format_utils.h" #include "common/unordered_containers_boost_serialization.h" @@ -72,22 +73,6 @@ const uint64_t WALLET_MINIMUM_HEIGHT_UNSET_CONST = std::numeric_limits class test_generator; -namespace std -{ - - template - struct hash> - { - size_t operator()(const pair& p) const - { - auto hash1 = hash{}(p.first); - auto hash2 = hash{}(p.second); - return hash1 ^ hash2; - } - }; - -} // namespace std - namespace tools { #pragma pack(push, 1) From 83ecbf346da95c1f2fd068134944e784cf83d29c Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 26 May 2020 20:41:00 +0300 Subject: [PATCH 55/70] fixed conversion in wallet_error_base --- src/wallet/wallet_errors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index a0b9834e..79b5d06a 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -68,7 +68,7 @@ namespace tools return ss.str(); } - virtual char const* what() const + virtual const char* what() const { m_what = to_string(); return m_what.c_str(); From 01c1339ae6b612129926ed7e60c6082bfeb8657f Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 May 2020 13:09:42 +0300 Subject: [PATCH 56/70] fixed wallet_error_base signature --- src/wallet/wallet_errors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 79b5d06a..fe79adf4 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -68,7 +68,7 @@ namespace tools return ss.str(); } - virtual const char* what() const + virtual const char* what() const noexcept { m_what = to_string(); return m_what.c_str(); From 9ea200e3fa263ebe35584d19873abb6ab14a9a86 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 May 2020 13:12:28 +0300 Subject: [PATCH 57/70] coretests: wallet_test inherits test_chain_unit_enchanced virtually to avoid gcc issues --- tests/core_tests/wallet_tests_basic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core_tests/wallet_tests_basic.h b/tests/core_tests/wallet_tests_basic.h index 1e921b29..b23f19a5 100644 --- a/tests/core_tests/wallet_tests_basic.h +++ b/tests/core_tests/wallet_tests_basic.h @@ -6,7 +6,7 @@ #pragma once #include "chaingen.h" -struct wallet_test : public test_chain_unit_enchanced +struct wallet_test : virtual public test_chain_unit_enchanced { enum { MINER_ACC_IDX = 0, ALICE_ACC_IDX = 1, BOB_ACC_IDX = 2, CAROL_ACC_IDX = 3, DAN_ACC_IDX = 4, TOTAL_ACCS_COUNT = 5 }; // to be used as index for m_accounts From 069cbbf769e29835523c65d3d6c15114b979742b Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 May 2020 13:14:14 +0300 Subject: [PATCH 58/70] wallet: transfer is forbidden for auditable watch-only wallets --- src/wallet/wallet2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index c1e19783..3404cc7a 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -4582,6 +4582,8 @@ void wallet2::transfer(const construct_tx_param& ctp, bool send_to_network, std::string* p_signed_tx_blob_str) { + 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); TIME_MEASURE_START(prepare_transaction_time); From ee9ef363b97774ca4c71a70b25f71412e27d1c78 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 May 2020 17:20:25 +0300 Subject: [PATCH 59/70] auditable watch-only wallet now can be restored from awo-blob (by a third party): --restore-awo-wallet simplewallet new command: awo_blob --- src/currency_core/account.cpp | 9 ++- src/currency_core/account.h | 1 + src/currency_core/currency_format_utils.cpp | 40 +++++++++++++ src/currency_core/currency_format_utils.h | 1 + src/simplewallet/simplewallet.cpp | 66 ++++++++++++++++++--- src/simplewallet/simplewallet.h | 4 +- src/wallet/wallet2.cpp | 13 ++++ src/wallet/wallet2.h | 1 + 8 files changed, 125 insertions(+), 10 deletions(-) diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 1e492975..601b8d5f 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -162,6 +162,13 @@ namespace currency return true; } //----------------------------------------------------------------- + bool account_base::restore_from_awo_blob(const std::string& awo_blob) + { + set_null(); + bool r = parse_awo_blob(awo_blob, m_keys.account_address, m_keys.view_secret_key, m_creation_timestamp); + return r; + } + //----------------------------------------------------------------- std::string account_base::get_public_address_str() const { //TODO: change this code into base 58 @@ -172,7 +179,7 @@ namespace currency { // keep only: // timestamp - // view pub & spend pub (public address) + // view pub & spend pub + flags (public address) // view sec // store to local tmp diff --git a/src/currency_core/account.h b/src/currency_core/account.h index bcb35961..156d058e 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -55,6 +55,7 @@ namespace currency std::string get_restore_braindata() const; bool restore_from_braindata(const std::string& seed_phrase); + bool restore_from_awo_blob(const std::string& awo_blob); uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index d4855cd0..d51b7821 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -313,6 +313,46 @@ namespace currency return string_tools::get_xtype_from_string(amount, str_amount); } //-------------------------------------------------------------------------------- + bool parse_awo_blob(const std::string& awo_blob, account_public_address& address, crypto::secret_key& view_sec_key, uint64_t& creation_timestamp) + { + std::vector parts; + boost::split(parts, awo_blob, [](char x){ return x == ':'; } ); + if (parts.size() != 2 && parts.size() != 3) + return false; + + if (!get_account_address_from_str(address, parts[0])) + return false; + + if (!address.is_auditable()) + return false; + + if (!epee::string_tools::parse_tpod_from_hex_string(parts[1], view_sec_key)) + return false; + + crypto::public_key view_pub_key = AUTO_VAL_INIT(view_pub_key); + if (!crypto::secret_key_to_public_key(view_sec_key, view_pub_key)) + return false; + + if (view_pub_key != address.view_public_key) + return false; + + creation_timestamp = 0; + if (parts.size() == 3) + { + // parse timestamp + int64_t ts = 0; + if (!epee::string_tools::string_to_num_fast(parts[2], ts)) + return false; + + if (ts < WALLET_BRAIN_DATE_OFFSET) + return false; + + creation_timestamp = ts; + } + + return true; + } + //-------------------------------------------------------------------------------- std::string print_stake_kernel_info(const stake_kernel& sk) { std::stringstream ss; diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index c4edefeb..598b2cb3 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -239,6 +239,7 @@ namespace currency bool check_inputs_types_supported(const transaction& tx); bool check_outs_valid(const transaction& tx); bool parse_amount(uint64_t& amount, const std::string& str_amount); + bool parse_awo_blob(const std::string& awo_blob, account_public_address& address, crypto::secret_key& view_sec_key, uint64_t& creation_timestamp); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 117b1771..475dae49 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -52,6 +52,7 @@ namespace const command_line::arg_descriptor arg_do_pos_mining = { "do-pos-mining", "Do PoS mining", false, false }; const command_line::arg_descriptor arg_pos_mining_reward_address = { "pos-mining-reward-address", "Block reward will be sent to the giving address if specified", "" }; const command_line::arg_descriptor arg_restore_wallet = { "restore-wallet", "Restore wallet from the seed phrase and save it to ", "" }; + const command_line::arg_descriptor arg_restore_awo_wallet = { "restore-awo-wallet", "Restore auditable watch-only wallet from address and view key. Use \"address:viewkey\" as argument", "" }; const command_line::arg_descriptor arg_offline_mode = { "offline-mode", "Don't connect to daemon, work offline (for cold-signing process)", false, true }; const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; @@ -220,6 +221,8 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), "Get transaction one-time secret key (r) for a given "); + m_cmd_binder.set_handler("awo_blob", boost::bind(&simple_wallet::awo_blob, this, _1), "For auditable wallets: prints auditable watch-only blob for wallet's audit by a third party"); + m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data"); m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "save_watch_only - save as watch-only wallet file."); @@ -271,9 +274,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } - if (m_wallet_file.empty() && m_generate_new.empty() && m_restore_wallet.empty() && m_generate_new_aw.empty()) + if (m_wallet_file.empty() && m_generate_new.empty() && m_restore_wallet.empty() && m_restore_awo_wallet.empty() && m_generate_new_aw.empty()) { - fail_msg_writer() << "you must specify --wallet-file, --generate-new-wallet, --generate-new-auditable-wallet or --restore-wallet"; + fail_msg_writer() << "you must specify --wallet-file, --generate-new-wallet, --generate-new-auditable-wallet, --restore-wallet or --restore-awo-wallet"; return false; } @@ -335,7 +338,25 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) return false; } - bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password()); + bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password(), false); + CHECK_AND_ASSERT_MES(r, false, "wallet restoring failed"); + } + else if (!m_restore_awo_wallet.empty()) + { + if (boost::filesystem::exists(m_restore_awo_wallet)) + { + fail_msg_writer() << "file " << m_restore_awo_wallet << " already exists"; + return false; + } + + tools::password_container restore_addr_and_viewkey_container; + if (!restore_addr_and_viewkey_container.read_password("please, enter wallet auditable address, viewkey and timestamp, separated by a colon (\"address:viewkey:timestamp\"):\n")) + { + fail_msg_writer() << "failed to read seed phrase"; + return false; + } + + bool r = restore_wallet(m_restore_awo_wallet, restore_addr_and_viewkey_container.password(), pwd_container.password(), true); CHECK_AND_ASSERT_MES(r, false, "wallet restoring failed"); } else @@ -366,6 +387,7 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_ m_do_not_set_date = command_line::get_arg(vm, arg_dont_set_date); m_do_pos_mining = command_line::get_arg(vm, arg_do_pos_mining); m_restore_wallet = command_line::get_arg(vm, arg_restore_wallet); + m_restore_awo_wallet = command_line::get_arg(vm, arg_restore_awo_wallet); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::try_connect_to_daemon() @@ -417,7 +439,7 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::string &restore_seed, const std::string& password) +bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::string &seed_or_awo_blob, const std::string& password, bool auditable_watch_only) { m_wallet_file = wallet_file; @@ -426,15 +448,24 @@ bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::st m_wallet->set_do_rise_transfer(false); try { - m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, restore_seed); - message_writer(epee::log_space::console_color_white, true) << "Wallet restored: " << m_wallet->get_account().get_public_address_str(); - std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush; + if (auditable_watch_only) + { + m_wallet->restore_awo(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob); + message_writer(epee::log_space::console_color_white, true) << "Auditable watch-only wallet restored: " << m_wallet->get_account().get_public_address_str(); + } + else + { + // normal wallet + m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob); + message_writer(epee::log_space::console_color_white, true) << "Wallet restored: " << m_wallet->get_account().get_public_address_str(); + std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush; + } if (m_do_not_set_date) m_wallet->reset_creation_time(0); } catch (const std::exception& e) { - fail_msg_writer() << "failed to restore wallet, check your seed phrase!" << ENDL << e.what(); + fail_msg_writer() << "failed to restore wallet, check your " << (auditable_watch_only ? "awo blob!" : "seed phrase!") << ENDL << e.what(); return false; } @@ -1471,6 +1502,24 @@ bool simple_wallet::get_tx_key(const std::vector &args_) } } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::awo_blob(const std::vector &args_) +{ + if (!m_wallet->is_auditable()) + { + fail_msg_writer() << "this command is allowed for auditable wallets only"; + return true; + } + + const account_base& acc = m_wallet->get_account(); + + success_msg_writer() << "Auditable watch-only blob for this wallet is: "; + std::cout << acc.get_public_address_str() << ":" << epee::string_tools::pod_to_hex(acc.get_keys().view_secret_key); + if (acc.get_createtime()) + std::cout << ":" << acc.get_createtime(); + std::cout << ENDL; + return true; +} +//---------------------------------------------------------------------------------------------------- void simple_wallet::set_offline_mode(bool offline_mode) { if (offline_mode && !m_offline_mode) @@ -1734,6 +1783,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_do_pos_mining); command_line::add_arg(desc_params, arg_pos_mining_reward_address); command_line::add_arg(desc_params, arg_restore_wallet); + command_line::add_arg(desc_params, arg_restore_awo_wallet); command_line::add_arg(desc_params, arg_offline_mode); command_line::add_arg(desc_params, command_line::arg_log_file); command_line::add_arg(desc_params, command_line::arg_log_level); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index a99f62a5..7808333b 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -46,7 +46,7 @@ namespace currency bool new_wallet(const std::string &wallet_file, const std::string& password, bool create_auditable_wallet); bool open_wallet(const std::string &wallet_file, const std::string& password); - bool restore_wallet(const std::string &wallet_file, const std::string &restore_seed, const std::string& password); + bool restore_wallet(const std::string &wallet_file, const std::string &seed_or_awo_blob, const std::string& password, bool auditable_watch_only); bool close_wallet(); bool help(const std::vector &args = std::vector()); @@ -81,6 +81,7 @@ namespace currency bool enable_console_logger(const std::vector &args); bool integrated_address(const std::vector &args); bool get_tx_key(const std::vector &args_); + bool awo_blob(const std::vector &args_); bool save_watch_only(const std::vector &args); bool sign_transfer(const std::vector &args); bool submit_transfer(const std::vector &args); @@ -166,6 +167,7 @@ namespace currency bool m_do_pos_mining; bool m_offline_mode; std::string m_restore_wallet; + std::string m_restore_awo_wallet; epee::console_handlers_binder m_cmd_binder; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3404cc7a..36fa53e5 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2203,6 +2203,19 @@ void wallet2::restore(const std::wstring& path, const std::string& pass, const s store(); } //---------------------------------------------------------------------------------------------------- +void wallet2::restore_awo(const std::wstring& path, const std::string& pass, const std::string& awo_blob) +{ + clear(); + prepare_file_names(path); + m_password = pass; + bool r = m_account.restore_from_awo_blob(awo_blob); + init_log_prefix(); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "Could not load auditable watch-only wallet from a given blob: invalid awo blob"); + boost::system::error_code ignored_ec; + THROW_IF_FALSE_WALLET_EX(!boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file)); + store(); +} +//---------------------------------------------------------------------------------------------------- bool wallet2::check_connection() { return m_core_proxy->check_connection(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 00f27450..5a9f1dd1 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -489,6 +489,7 @@ namespace tools void assign_account(const currency::account_base& acc); void generate(const std::wstring& path, const std::string& password, bool auditable_wallet); void restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase); + void restore_awo(const std::wstring& path, const std::string& pass, const std::string& awo_blob); void load(const std::wstring& path, const std::string& password); void store(); void store(const std::wstring& path); From ecfccc9f5312f7fb11eed26c602008d377f39c39 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 May 2020 23:01:37 +0300 Subject: [PATCH 60/70] wallet2: fixed wrong skipping bad output with mix_attr != 1 in an auditable wallet --- src/wallet/wallet2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 36fa53e5..b36e7b82 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -440,10 +440,11 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t { std::stringstream ss; ss << "output #" << o << " from tx " << get_transaction_hash(tx) << " with amount " << print_money_brief(tx.vout[o].amount) - << " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)otk.mix_attr << ". Output will be IGNORED."; + << " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)otk.mix_attr << ". Output IGNORED."; WLT_LOG_RED(ss.str(), LOG_LEVEL_0); if (m_wcallback) m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str()); + tx_money_got_in_outs -= tx.vout[o].amount; continue; // skip the output } From 6712b548cdbe5b939c493e1d0a1f7fe21fa4732c Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 May 2020 23:04:23 +0300 Subject: [PATCH 61/70] wallet2: made auditable watch-only wallet not using outkey2ki file --- src/wallet/wallet2.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index b36e7b82..eaadde0e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2183,7 +2183,7 @@ void wallet2::generate(const std::wstring& path, const std::string& pass, bool a init_log_prefix(); boost::system::error_code ignored_ec; THROW_IF_TRUE_WALLET_EX(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file)); - if (m_watch_only) + if (m_watch_only && !auditable_wallet) { bool stub; load_keys2ki(true, stub); @@ -2259,7 +2259,7 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) bool need_to_resync = !tools::portable_unserialize_obj_from_stream(*this, data_file); - if (m_watch_only) + if (m_watch_only && !is_auditable()) load_keys2ki(true, need_to_resync); WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) << " with public address: " << m_account.get_public_address_str()); @@ -2385,8 +2385,11 @@ void wallet2::store_watch_only(const std::wstring& path_to_save, const std::stri WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!boost::filesystem::exists(wo.m_pending_ki_file), "file " << epee::string_encoding::convert_to_ansii(wo.m_pending_ki_file) << " already exists"); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(wo.m_pending_key_images.empty(), "pending key images is expected to be empty"); - bool stub = false; - wo.load_keys2ki(true, stub); // to create outkey2ki file + if (!is_auditable()) + { + bool stub = false; + wo.load_keys2ki(true, stub); // to create outkey2ki file + } // populate pending key images for spent outputs (this will help to resync watch-only wallet) for (size_t ti = 0; ti < wo.m_transfers.size(); ++ti) From 5bb8b369ffe078fa8c9bdd1a57c354476a16cc31 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 27 May 2020 23:49:34 +0300 Subject: [PATCH 62/70] restoring AWO wallets enabled for GUI backend + refactoring to made things simpler --- src/gui/qt-daemon/application/mainwindow.cpp | 2 +- src/simplewallet/simplewallet.cpp | 4 +-- src/wallet/plain_wallet_api.cpp | 2 +- src/wallet/view_iface.h | 2 ++ src/wallet/wallet2.cpp | 33 ++++++++++---------- src/wallet/wallet2.h | 3 +- src/wallet/wallets_manager.cpp | 4 +-- src/wallet/wallets_manager.h | 2 +- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 03553604..8e4a5f33 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -1587,7 +1587,7 @@ QString MainWindow::restore_wallet(const QString& param) //return que_call2("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){ PREPARE_ARG_FROM_JSON(view::restore_wallet_request, owd); PREPARE_RESPONSE(view::open_wallet_response, ar); - ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.restore_key, ar.response_data); + ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.restore_key, owd.auditable_watch_only, ar.response_data); return MAKE_RESPONSE(ar); CATCH_ENTRY_FAIL_API_RESPONCE(); } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 475dae49..27eca885 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -450,13 +450,13 @@ bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::st { if (auditable_watch_only) { - m_wallet->restore_awo(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob); + m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob, true); message_writer(epee::log_space::console_color_white, true) << "Auditable watch-only wallet restored: " << m_wallet->get_account().get_public_address_str(); } else { // normal wallet - m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob); + m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob, false); message_writer(epee::log_space::console_color_white, true) << "Wallet restored: " << m_wallet->get_account().get_public_address_str(); std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush; } diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index fbb1c477..ab4c9480 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -356,7 +356,7 @@ namespace plain_wallet std::string full_path = get_wallets_folder() + path; epee::json_rpc::response ok_response = AUTO_VAL_INIT(ok_response); - std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, ok_response.result); + std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, false, ok_response.result); if (rsp == API_RETURN_CODE_OK || rsp == API_RETURN_CODE_FILE_RESTORED) { if (rsp == API_RETURN_CODE_FILE_RESTORED) diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index 35b20d4f..180bd9a8 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -416,11 +416,13 @@ public: std::string pass; std::string path; std::string restore_key; + bool auditable_watch_only; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(pass) KV_SERIALIZE(path) KV_SERIALIZE(restore_key) + KV_SERIALIZE(auditable_watch_only) END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index eaadde0e..e88b79f4 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2191,32 +2191,31 @@ void wallet2::generate(const std::wstring& path, const std::string& pass, bool a store(); } //---------------------------------------------------------------------------------------------------- -void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase) +void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase_or_awo_blob, bool auditable_watch_only) { + bool r = false; clear(); prepare_file_names(path); m_password = pass; - bool r = m_account.restore_from_braindata(seed_phrase); - init_log_prefix(); - THROW_IF_TRUE_WALLET_EX(!r, error::wallet_wrong_seed_error, epee::string_encoding::convert_to_ansii(m_wallet_file)); + + if (auditable_watch_only) + { + r = m_account.restore_from_awo_blob(seed_phrase_or_awo_blob); + init_log_prefix(); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "Could not load auditable watch-only wallet from a given blob: invalid awo blob"); + } + else + { + r = m_account.restore_from_braindata(seed_phrase_or_awo_blob); + init_log_prefix(); + THROW_IF_FALSE_WALLET_EX(r, error::wallet_wrong_seed_error, epee::string_encoding::convert_to_ansii(m_wallet_file)); + } + boost::system::error_code ignored_ec; THROW_IF_TRUE_WALLET_EX(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file)); store(); } //---------------------------------------------------------------------------------------------------- -void wallet2::restore_awo(const std::wstring& path, const std::string& pass, const std::string& awo_blob) -{ - clear(); - prepare_file_names(path); - m_password = pass; - bool r = m_account.restore_from_awo_blob(awo_blob); - init_log_prefix(); - WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "Could not load auditable watch-only wallet from a given blob: invalid awo blob"); - boost::system::error_code ignored_ec; - THROW_IF_FALSE_WALLET_EX(!boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file)); - store(); -} -//---------------------------------------------------------------------------------------------------- bool wallet2::check_connection() { return m_core_proxy->check_connection(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 5a9f1dd1..8a4a7b0f 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -488,8 +488,7 @@ namespace tools void assign_account(const currency::account_base& acc); void generate(const std::wstring& path, const std::string& password, bool auditable_wallet); - void restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase); - void restore_awo(const std::wstring& path, const std::string& pass, const std::string& awo_blob); + void restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase_or_awo_blob, bool auditable_watch_only); void load(const std::wstring& path, const std::string& password); void store(); void store(const std::wstring& path); diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 3eb831db..79c0033f 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -961,7 +961,7 @@ void wallets_manager::get_gui_options(view::gui_options& opt) { opt = m_ui_opt; } -std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr) +std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, bool auditable_watch_only, view::open_wallet_response& owr) { std::shared_ptr w(new tools::wallet2()); owr.wallet_id = m_wallet_id_counter++; @@ -983,7 +983,7 @@ std::string wallets_manager::restore_wallet(const std::wstring& path, const std: currency::account_base acc; try { - w->restore(path, password, restore_key); + w->restore(path, password, restore_key, auditable_watch_only); owr.seed = w->get_account().get_restore_braindata(); } catch (const tools::error::file_exists&) diff --git a/src/wallet/wallets_manager.h b/src/wallet/wallets_manager.h index 5b545f32..e992109b 100644 --- a/src/wallet/wallets_manager.h +++ b/src/wallet/wallets_manager.h @@ -94,7 +94,7 @@ public: bool send_stop_signal(); std::string open_wallet(const std::wstring& path, const std::string& password, uint64_t txs_to_return, view::open_wallet_response& owr); std::string generate_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr); - std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr); + std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, bool auditable_watch_only, view::open_wallet_response& owr); std::string invoke(uint64_t wallet_id, std::string params); std::string get_wallet_status(uint64_t wallet_id); std::string run_wallet(uint64_t wallet_id); From 859291f45eec8d57f85cb476ad723d0c64ef1f19 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 28 May 2020 12:36:51 +0300 Subject: [PATCH 63/70] gui: is_auditable and is_watch_only are now available in wallet_info --- src/wallet/view_iface.h | 4 ++++ src/wallet/wallet_helpers.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index 180bd9a8..3e34c039 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -215,6 +215,8 @@ public: std::string address; std::string tracking_hey; std::string path; + bool is_auditable; + bool is_watch_only; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(unlocked_balance) @@ -223,6 +225,8 @@ public: KV_SERIALIZE(address) KV_SERIALIZE(tracking_hey) KV_SERIALIZE(path) + KV_SERIALIZE(is_auditable); + KV_SERIALIZE(is_watch_only); END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallet_helpers.h b/src/wallet/wallet_helpers.h index be227c62..1d62e1ea 100644 --- a/src/wallet/wallet_helpers.h +++ b/src/wallet/wallet_helpers.h @@ -19,6 +19,8 @@ namespace tools uint64_t fake = 0; wi.balance = w.balance(wi.unlocked_balance, fake, fake, wi.mined_total); wi.path = epee::string_encoding::wstring_to_utf8(w.get_wallet_path()); + wi.is_auditable = w.is_auditable(); + wi.is_watch_only = w.is_watch_only(); return true; } } \ No newline at end of file From aeb23bdd81e88f62f227f1abae4f44b17d33b2c3 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 28 May 2020 14:38:27 +0300 Subject: [PATCH 64/70] GUI: allow auditable watch-only wallets to be opened --- src/wallet/wallets_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 79c0033f..3dc30737 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -805,7 +805,7 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st try { w->load(path, password); - if (w->is_watch_only()) + if (w->is_watch_only() && !w->is_auditable()) return API_RETURN_CODE_WALLET_WATCH_ONLY_NOT_SUPPORTED; w->get_recent_transfers_history(owr.recent_history.history, 0, txs_to_return, owr.recent_history.total_history_items); //w->get_unconfirmed_transfers(owr.recent_history.unconfirmed); From df41672f443760e11edd6070d6bdf7857c65f9b8 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 28 May 2020 19:38:47 +0300 Subject: [PATCH 65/70] unit_tests: few tests adapted to new address format + lmdb fixed --- tests/unit_tests/base58.cpp | 5 +++-- tests/unit_tests/lmdb_tests.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit_tests/base58.cpp b/tests/unit_tests/base58.cpp index 33e209fc..60b70ec2 100644 --- a/tests/unit_tests/base58.cpp +++ b/tests/unit_tests/base58.cpp @@ -439,7 +439,8 @@ namespace "\xf7\x24\xbc\x5c\x6c\xfb\xb9\xd9\x76\x02\xc3\x00\x42\x3a\x2f\x28" "\x64\x18\x74\x51\x3a\x03\x57\x78\xa0\xc1\x77\x8d\x83\x32\x01\xe9" "\x22\x09\x39\x68\x9e\xdf\x1a\xbd\x5b\xc1\xd0\x31\xf7\x3e\xcd\x6c" - "\x99\x3a\xdd\x66\xd6\x80\x88\x70\x45\x6a\xfe\xb8\xe7\xee\xb6\x8d"); + "\x99\x3a\xdd\x66\xd6\x80\x88\x70\x45\x6a\xfe\xb8\xe7\xee\xb6\x8d" + "\x00"); std::string test_keys_addr_str = "ZxDqHy6WnyYY5yQcdApjMb8tVPik5BC3LFdaevfbGq7X1KY5vdsWmUi5UQgse2GBZFbMsb47TFqBmPpdFHDDwDxR2ZuZ6zX4W"; // correct str address depends on CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX value } @@ -499,7 +500,7 @@ TEST(get_account_address_from_str, fails_on_invalid_address_spend_key) TEST(get_account_address_from_str, fails_on_invalid_address_view_key) { std::string serialized_keys_copy = test_serialized_keys; - serialized_keys_copy.back() = '\x01'; + serialized_keys_copy[serialized_keys_copy.size() - 2] = '\x01'; std::string addr_str = base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, serialized_keys_copy); currency::account_public_address addr; diff --git a/tests/unit_tests/lmdb_tests.cpp b/tests/unit_tests/lmdb_tests.cpp index 8b179675..42bccb37 100644 --- a/tests/unit_tests/lmdb_tests.cpp +++ b/tests/unit_tests/lmdb_tests.cpp @@ -903,7 +903,7 @@ namespace lmdb_test static const uint64_t buffer_size = 64 * 1024; // 64 KB static const uint64_t db_total_size = static_cast(2.1 * 1024 * 1024 * 1024); // 2.1 GB -- a bit more than 2GB to test 2GB boundary - static const std::string db_file_path = std::string("2gb_") + typeid(db_backend_t).name() + "_test"; + static const std::string db_file_path = boost::algorithm::replace_all_copy(boost::algorithm::replace_all_copy(std::string("2gb_") + typeid(db_backend_t).name() + "_test", ":", "_"), " ", "_"); std::shared_ptr lmdb_ptr = std::make_shared(); db::basic_db_accessor bdba(lmdb_ptr, rw_lock); From d932f1e98dc8f73f47fd31fdc9d22084497360d0 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 29 May 2020 11:56:36 +0300 Subject: [PATCH 66/70] good-bye "tracking_hey"! --- src/wallet/view_iface.h | 4 ++-- src/wallet/wallet_helpers.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index 3e34c039..835bade9 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -213,7 +213,7 @@ public: uint64_t balance; uint64_t mined_total; std::string address; - std::string tracking_hey; + std::string view_sec_key; std::string path; bool is_auditable; bool is_watch_only; @@ -223,7 +223,7 @@ public: KV_SERIALIZE(balance) KV_SERIALIZE(mined_total) KV_SERIALIZE(address) - KV_SERIALIZE(tracking_hey) + KV_SERIALIZE(view_sec_key) KV_SERIALIZE(path) KV_SERIALIZE(is_auditable); KV_SERIALIZE(is_watch_only); diff --git a/src/wallet/wallet_helpers.h b/src/wallet/wallet_helpers.h index 1d62e1ea..9f415dfb 100644 --- a/src/wallet/wallet_helpers.h +++ b/src/wallet/wallet_helpers.h @@ -15,7 +15,7 @@ namespace tools { wi = AUTO_VAL_INIT_T(view::wallet_info); wi.address = w.get_account().get_public_address_str(); - wi.tracking_hey = epee::string_tools::pod_to_hex(w.get_account().get_keys().view_secret_key); + wi.view_sec_key = epee::string_tools::pod_to_hex(w.get_account().get_keys().view_secret_key); uint64_t fake = 0; wi.balance = w.balance(wi.unlocked_balance, fake, fake, wi.mined_total); wi.path = epee::string_encoding::wstring_to_utf8(w.get_wallet_path()); From 35370ba4853c9ae47c8b6bd3af6d5401f3fdc901 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 1 Jun 2020 15:32:00 +0300 Subject: [PATCH 67/70] account_base::get_awo_blob() --- src/currency_core/account.cpp | 7 +++++++ src/currency_core/account.h | 1 + src/simplewallet/simplewallet.cpp | 9 ++------- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 601b8d5f..ac80a305 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -87,6 +87,13 @@ namespace currency return keys_seed_text + " " + timestamp_word + " " + auditable_flag_and_checksum_word; } //----------------------------------------------------------------- + std::string account_base::get_awo_blob() const + { + return get_public_address_str() + ":" + + epee::string_tools::pod_to_hex(m_keys.view_secret_key) + + (m_creation_timestamp ? ":" : "") + (m_creation_timestamp ? epee::string_tools::num_to_string_fast(m_creation_timestamp) : ""); + } + //----------------------------------------------------------------- bool account_base::restore_keys(const std::vector& keys_seed_binary) { CHECK_AND_ASSERT_MES(keys_seed_binary.size() == BRAINWALLET_DEFAULT_SEED_SIZE, false, "wrong restore data size: " << keys_seed_binary.size()); diff --git a/src/currency_core/account.h b/src/currency_core/account.h index 156d058e..52fec46a 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -54,6 +54,7 @@ namespace currency std::string get_public_address_str() const; std::string get_restore_braindata() const; + std::string get_awo_blob() const; bool restore_from_braindata(const std::string& seed_phrase); bool restore_from_awo_blob(const std::string& awo_blob); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 27eca885..45c1799f 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1510,13 +1510,8 @@ bool simple_wallet::awo_blob(const std::vector &args_) return true; } - const account_base& acc = m_wallet->get_account(); - - success_msg_writer() << "Auditable watch-only blob for this wallet is: "; - std::cout << acc.get_public_address_str() << ":" << epee::string_tools::pod_to_hex(acc.get_keys().view_secret_key); - if (acc.get_createtime()) - std::cout << ":" << acc.get_createtime(); - std::cout << ENDL; + success_msg_writer() << "Auditable watch-only blob for this wallet is:"; + std::cout << m_wallet->get_account().get_awo_blob() << ENDL; return true; } //---------------------------------------------------------------------------------------------------- From 79d86e3f9f6fd7237a2c76d5316186b921d1b68e Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 1 Jun 2020 15:33:16 +0300 Subject: [PATCH 68/70] coretests: hard_fork_2_awo_wallets_basic_test added (exposes a bug) --- tests/core_tests/chaingen_main.cpp | 2 + tests/core_tests/hard_fork_2.cpp | 260 +++++++++++++++++++++++++++++ tests/core_tests/hard_fork_2.h | 10 ++ 3 files changed, 272 insertions(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index a7ade6de..e7a0b10f 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1005,6 +1005,8 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(hard_fork_2_tx_extra_alias_entry_in_wallet); GENERATE_AND_PLAY(hard_fork_2_auditable_addresses_basics); GENERATE_AND_PLAY(hard_fork_2_no_new_structures_before_hf); + GENERATE_AND_PLAY(hard_fork_2_awo_wallets_basic_test); + GENERATE_AND_PLAY(hard_fork_2_awo_wallets_basic_test); // GENERATE_AND_PLAY(gen_block_reward); diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 76c70701..49f487d3 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -854,3 +854,263 @@ bool hard_fork_2_no_new_structures_before_hf::c1(currency::core& c, size_t ev_in return true; } + +//------------------------------------------------------------------------------ + +template +hard_fork_2_awo_wallets_basic_test::hard_fork_2_awo_wallets_basic_test() + : hard_fork_2_base_test(before_hf_2 ? 100 : 3) +{ + REGISTER_CALLBACK_METHOD(hard_fork_2_awo_wallets_basic_test, c1); +} + +template +bool hard_fork_2_awo_wallets_basic_test::generate(std::vector& events) const +{ + bool r = false; + 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(true); // Bob has auditable address + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + set_hard_fork_heights_to_generator(generator); + DO_CALLBACK(events, "configure_core"); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + transaction tx_0 = AUTO_VAL_INIT(tx_0); + r = construct_tx_with_many_outputs(events, blk_0r, miner_acc.get_keys(), alice_acc.get_public_address(), MK_TEST_COINS(110), 10, TESTS_DEFAULT_FEE, tx_0); + CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed"); + events.push_back(tx_0); + + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); + + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE); + + DO_CALLBACK(events, "c1"); + + return true; +} + +template +bool hard_fork_2_awo_wallets_basic_test::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + static const std::wstring bob_wo_filename(L"bob_wo_wallet"); + static const std::wstring bob_wo_restored_filename(L"bob_wo_restored_wallet"); + static const std::wstring bob_non_auditable_filename(L"bob_non_auditable_wallet"); + + bool r = false, stub_bool = false; + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + 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); + std::shared_ptr bob_wlt_awo = std::make_shared(); + + boost::system::error_code ec; + boost::filesystem::remove(bob_wo_filename, ec); + bob_wlt->store_watch_only(bob_wo_filename, ""); + + bob_wlt_awo->load(bob_wo_filename, ""); + bob_wlt_awo->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config()); + bob_wlt_awo->set_core_proxy(m_core_proxy); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(110), false, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, 0, false, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo", bob_wlt_awo, 0, false, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE), false, ""); + + CHECK_AND_ASSERT_MES(bob_wlt->get_account().get_public_address() == bob_wlt_awo->get_account().get_public_address(), false, "Bob addresses do not match"); + + // + // Alice -> Bob, Bob_awo + // + std::vector destinations; + destinations.push_back(tx_destination_entry(MK_TEST_COINS(5), bob_wlt->get_account().get_public_address())); + destinations.push_back(tx_destination_entry(MK_TEST_COINS(5), bob_wlt_awo->get_account().get_public_address())); + alice_wlt->transfer(destinations, 2, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(99), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(10), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo", bob_wlt_awo, MK_TEST_COINS(10), false, 1), false, ""); + + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + + alice_wlt->refresh(); + bob_wlt->refresh(); + bob_wlt_awo->refresh(); + + // + // Bob -> miner + // + r = false; + try + { + // first, try with non-zero mixins first -- should fail + bob_wlt->transfer(std::vector{tx_destination_entry(MK_TEST_COINS(9), m_accounts[MINER_ACC_IDX].get_public_address())}, 1 /*mixins*/, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment); + } + catch (...) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "an exception was not caught as expected"); + + r = false; + try + { + // second, try from bob_wlt_awo -- should fail (watch-only wallet) + bob_wlt_awo->transfer(std::vector{tx_destination_entry(MK_TEST_COINS(9), m_accounts[MINER_ACC_IDX].get_public_address())}, 0 /*mixins*/, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment); + } + catch (...) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "an exception was not caught as expected"); + + + // third, try from bob_wlt with zero mixins first -- should pass + bob_wlt->transfer(std::vector{tx_destination_entry(MK_TEST_COINS(9), m_accounts[MINER_ACC_IDX].get_public_address())}, 0 /*mixins*/, 0, TESTS_DEFAULT_FEE, empty_extra, empty_attachment); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(99), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(0), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo", bob_wlt_awo, MK_TEST_COINS(0), false, 1), false, ""); + + // + // Alice -> Bob as non-auditable (mix_attr != 1) + // this transfer should not be taken into account for Bob and bob_wlt_awo + // + account_public_address bob_addr_non_aud = bob_wlt->get_account().get_public_address(); + bob_addr_non_aud.flags = 0; // clear auditable flag + + alice_wlt->transfer(MK_TEST_COINS(7), bob_addr_non_aud); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + bool callback_called = false; + std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( + [&callback_called](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + callback_called = true; + return true; + } + )); + alice_wlt->callback(l); + bob_wlt->callback(l); + bob_wlt_awo->callback(l); + + callback_called = false; + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(91), false, 1), false, ""); + CHECK_AND_ASSERT_MES(callback_called, false, "callback was not called"); + callback_called = false; + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(0), false, 1), false, ""); + CHECK_AND_ASSERT_MES(!callback_called, false, "callback was called"); + callback_called = false; + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo", bob_wlt_awo, MK_TEST_COINS(0), false, 1), false, ""); + CHECK_AND_ASSERT_MES(!callback_called, false, "callback was called"); + + + // + // Alice -> Bob (normal) + // + alice_wlt->transfer(MK_TEST_COINS(3), m_accounts[BOB_ACC_IDX].get_public_address()); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(87), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(3), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo", bob_wlt_awo, MK_TEST_COINS(3), false, 1), false, ""); + + // + // Make sure a wallet, restored from awo blob will has the very same balance + // + account_base& bob_acc = m_accounts[BOB_ACC_IDX]; + std::string bob_awo_blob = bob_acc.get_awo_blob(); + + std::shared_ptr bob_wlt_awo_restored = std::make_shared(); + + boost::filesystem::remove(bob_wo_restored_filename, ec); + + bob_wlt_awo_restored->restore(bob_wo_restored_filename, "", bob_awo_blob, true); + bob_wlt_awo_restored->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config()); + bob_wlt_awo_restored->set_core_proxy(m_core_proxy); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo_restored", bob_wlt_awo_restored, MK_TEST_COINS(3), false), false, ""); + + + // miner few blocks to unlock coins + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + + bob_wlt->refresh(); + + // + // Bob -> miner, and check again all 3 wallets + // + bob_wlt->transfer(MK_TEST_COINS(1), m_accounts[MINER_ACC_IDX].get_public_address()); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(1), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo", bob_wlt_awo, MK_TEST_COINS(1), false, WALLET_DEFAULT_TX_SPENDABLE_AGE + 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo_restored", bob_wlt_awo_restored, MK_TEST_COINS(1), false, WALLET_DEFAULT_TX_SPENDABLE_AGE + 1), false, ""); + + + // + // Restore Bob wallet as non-auditable and spend mix_attr!=1 output => make sure other auditable Bob's wallets remain intact + // + + std::string bob_seed = bob_wlt->get_account().get_restore_braindata(); + bob_seed.erase(bob_seed.find_last_of(" ")); // remove the last word (with flags and checksum) to make seed old-format 25-words non-auditable with the same keys + + std::shared_ptr bob_wlt_non_auditable = std::make_shared(); + + boost::filesystem::remove(bob_non_auditable_filename, ec); + + bob_wlt_non_auditable->restore(bob_non_auditable_filename, "", bob_seed, false); + bob_wlt_non_auditable->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config()); + bob_wlt_non_auditable->set_core_proxy(m_core_proxy); + + // the balance for non-auditable wallet should be greather by mix_attr!=1 output (7 test coins + 1 left from prev step) + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_non_auditable", bob_wlt_non_auditable, MK_TEST_COINS(8), false), false, ""); + + // spend mix_attr!=1 7-coins output + bob_wlt_non_auditable->transfer(MK_TEST_COINS(6), m_accounts[ALICE_ACC_IDX].get_public_address()); + + // mine a block + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); + + // all auditable wallets should keep the same balance value + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(1), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo", bob_wlt_awo, MK_TEST_COINS(1), false, 1), false, ""); + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_awo_restored", bob_wlt_awo_restored, MK_TEST_COINS(1), false, 1), false, ""); + + // non-auditable should also show the same balance as we've just spent mix_attr!=1 output + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob_non_auditable", bob_wlt_non_auditable, MK_TEST_COINS(1), false, 1), false, ""); + + // make sure Alice received coins + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(93), false, 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 1), false, ""); + + return true; +} + +template hard_fork_2_awo_wallets_basic_test::hard_fork_2_awo_wallets_basic_test(); +template bool hard_fork_2_awo_wallets_basic_test::generate(std::vector& events) const; +template hard_fork_2_awo_wallets_basic_test::hard_fork_2_awo_wallets_basic_test(); +template bool hard_fork_2_awo_wallets_basic_test::generate(std::vector& events) const; diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h index 230a72d0..7b710603 100644 --- a/tests/core_tests/hard_fork_2.h +++ b/tests/core_tests/hard_fork_2.h @@ -56,3 +56,13 @@ struct hard_fork_2_no_new_structures_before_hf : public wallet_test, public hard bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +template +struct hard_fork_2_awo_wallets_basic_test : public wallet_test, public hard_fork_2_base_test +{ + //using hard_fork_2_base_test::check_block_verification_context; // this is necessary for correct work of do_check_block_verification_context, consider rafactoring + + hard_fork_2_awo_wallets_basic_test(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; From a47f9ade78fb33cb3984b551a817d809c9e66782 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 1 Jun 2020 16:08:44 +0300 Subject: [PATCH 69/70] coretests: improved tx counting in a few tests --- tests/core_tests/hard_fork_2.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 49f487d3..20aecd80 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -483,7 +483,7 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev transaction res_tx = AUTO_VAL_INIT(res_tx); alice_wlt->request_alias_registration(ai, res_tx, TESTS_DEFAULT_FEE, alias_reward); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // before the HF2 -- old structure should be present r = have_type_in_variant_container(res_tx.extra); @@ -547,10 +547,10 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev ai.m_address = m_accounts[MINER_ACC_IDX].get_public_address(); alice_wlt->request_alias_update(ai, res_tx, TESTS_DEFAULT_FEE, 0); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // after HF2: extra_alias_entry should be here, not extra_alias_entry_old r = have_type_in_variant_container(res_tx.extra); @@ -575,10 +575,10 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry_old is found in extra"); // miner a block to confirm it - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // make sure alias was updated to an auditable address indeed ai_check = AUTO_VAL_INIT(ai_check); @@ -599,10 +599,10 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev r = !have_type_in_variant_container(res_tx.extra); CHECK_AND_ASSERT_MES(r, false, "extra_alias_entry_old is found in extra"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // make sure alias was updated to an auditable address indeed ai_check = AUTO_VAL_INIT(ai_check); @@ -690,15 +690,15 @@ bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_ind } // mine a block to confirm the tx - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // mine few block to activate HF2 r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 2); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(20), false, 3), false, ""); @@ -715,10 +715,10 @@ bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_ind } // mine a block to confirm the tx - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // make sure the funds were received CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(5 + 1 + 1), false, 3 + 1), false, ""); From 338e22d6123a68dcc84c4dd0ff32d7a67915a390 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 1 Jun 2020 16:09:36 +0300 Subject: [PATCH 70/70] wallet2: fix a bug with awo wallet restoration --- src/wallet/wallet2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index e88b79f4..a211092c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2203,6 +2203,7 @@ void wallet2::restore(const std::wstring& path, const std::string& pass, const s r = m_account.restore_from_awo_blob(seed_phrase_or_awo_blob); init_log_prefix(); WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "Could not load auditable watch-only wallet from a given blob: invalid awo blob"); + m_watch_only = true; } else {