From 8f15d60677c9364c23f2ad4c991f762134fa33b0 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 15 Sep 2022 22:05:10 +0200 Subject: [PATCH 1/2] basic implementations over multi assets in wallet --- src/wallet/wallet2.cpp | 34 ++++++--- src/wallet/wallet2.h | 94 +++++++++++++------------ src/wallet/wallet_public_structs_defs.h | 29 ++++++++ src/wallet/wallet_rpc_server.cpp | 15 ++++ 4 files changed, 120 insertions(+), 52 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index aeaea8cc..70a28a94 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3004,19 +3004,36 @@ uint64_t wallet2::balance(uint64_t& unloked) const //---------------------------------------------------------------------------------------------------- uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined) const { + uint64_t total = 0; unlocked = 0; - uint64_t balance_total = 0; awaiting_in = 0; awaiting_out = 0; mined = 0; + std::unordered_map balances; + balance(balances, mined); + auto it = balances.find(currency::null_hash); + if (it != balances.end()) + { + total = it->second.total; + unlocked = it->second.unlocked; + awaiting_in = it->second.awaiting_in; + awaiting_out = it->second.awaiting_out; + } + return total; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::balance(std::unordered_map& balances, uint64_t& mined) const +{ + mined = 0; for(auto& td : m_transfers) { if (td.is_spendable() || (td.is_reserved_for_escrow() && !td.is_spent())) { - balance_total += td.amount(); + asset_balance_entry_base& e = balances[td.get_asset_id()]; + e.total += td.amount(); if (is_transfer_unlocked(td)) - unlocked += td.amount(); + e.unlocked += td.amount(); if (td.m_flags & WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER) mined += td.amount(); } @@ -3024,22 +3041,23 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a for(auto& utx : m_unconfirmed_txs) { + asset_balance_entry_base& e = balances[utx.asset_id]; if (utx.second.is_income) { - balance_total += utx.second.amount; - awaiting_in += utx.second.amount; + e.total += utx.second.amount; + e.awaiting_in += utx.second.amount; } else { //collect change in unconfirmed outgoing transactions for (auto r : utx.second.td.rcv) - balance_total += r; + e.total += r; - awaiting_out += utx.second.amount; + e.awaiting_out += utx.second.amount; } } - return balance_total; + return true; } //---------------------------------------------------------------------------------------------------- uint64_t wallet2::balance() const diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index d78d092b..78a485bd 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -128,8 +128,8 @@ namespace tools struct tx_dust_policy { - uint64_t dust_threshold; - bool add_to_fee; + uint64_t dust_threshold = 0; + bool add_to_fee = false; currency::account_public_address addr_for_dust; tx_dust_policy(uint64_t a_dust_threshold = DEFAULT_DUST_THRESHOLD, bool an_add_to_fee = true, currency::account_public_address an_addr_for_dust = currency::account_public_address()) @@ -274,25 +274,25 @@ namespace tools { // preparing data for tx std::vector dsts; - size_t fake_outputs_count; - uint64_t fee; + size_t fake_outputs_count = 0; + uint64_t fee = 0; tx_dust_policy dust_policy; - crypto::hash multisig_id; - uint8_t flags; - uint8_t split_strategy_id; - bool mark_tx_as_complete; + crypto::hash multisig_id = currency::null_hash; + uint8_t flags = 0; + uint8_t split_strategy_id = 0; + bool mark_tx_as_complete = false; crypto::hash htlc_tx_id; std::string htlc_origin; // constructing tx - uint64_t unlock_time; + uint64_t unlock_time = 0; std::vector extra; std::vector attachments; currency::account_public_address crypt_address; - uint8_t tx_outs_attr; - bool shuffle; - bool perform_packing; + uint8_t tx_outs_attr = 0; + bool shuffle = false; + bool perform_packing = false; }; // struct currency::finalize_tx_param @@ -357,8 +357,8 @@ namespace tools struct transaction_wallet_info { - uint64_t m_block_height; - uint64_t m_block_timestamp; + uint64_t m_block_height = 0; + uint64_t m_block_timestamp = 0; currency::transaction m_tx; BEGIN_KV_SERIALIZE_MAP() @@ -378,10 +378,10 @@ namespace tools struct transfer_details_base { std::shared_ptr m_ptx_wallet_info; - uint64_t m_internal_output_index; - uint64_t m_spent_height; - uint32_t m_flags; - uint64_t m_amount; + uint64_t m_internal_output_index = 0; + uint64_t m_spent_height = 0; + uint32_t m_flags = 0; + uint64_t m_amount = 0; boost::shared_ptr m_opt_blinding_mask; boost::shared_ptr m_asset_id; @@ -395,6 +395,7 @@ namespace tools 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 ); } bool is_zc() const { return m_opt_blinding_mask.get(); } + const crypto::hash& get_asset_id() const { if (m_asset_id.get()) { return *m_asset_id; } else { return currency::null_hash; } } BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_CUSTOM(m_ptx_wallet_info, const transaction_wallet_info&, tools::wallet2::transform_ptr_to_value, tools::wallet2::transform_value_to_ptr) @@ -414,7 +415,7 @@ namespace tools struct transfer_details_extra_option_htlc_info { std::string origin; //this field filled only if htlc had been redeemed - crypto::hash redeem_tx_id; + crypto::hash redeem_tx_id = currency::null_hash; }; @@ -422,7 +423,7 @@ namespace tools struct transfer_details : public transfer_details_base { - uint64_t m_global_output_index; + uint64_t m_global_output_index = 0; crypto::key_image m_key_image; //TODO: key_image stored twice :( std::vector varian_options; @@ -437,32 +438,32 @@ namespace tools //used in wallet struct htlc_expiration_trigger { - bool is_wallet_owns_redeem; //specify if this HTLC belong to this wallet by pkey_redeem or by pkey_refund - uint64_t transfer_index; + bool is_wallet_owns_redeem = false; //specify if this HTLC belong to this wallet by pkey_redeem or by pkey_refund + uint64_t transfer_index = 0; }; struct payment_details { - crypto::hash m_tx_hash; - uint64_t m_amount; - uint64_t m_block_height; - uint64_t m_unlock_time; + crypto::hash m_tx_hash = currency::null_hash; + uint64_t m_amount = 0; + uint64_t m_block_height = 0; + uint64_t m_unlock_time = 0; }; struct mining_context { std::string status; - bool is_pos_allowed; - bool zarcanum; + bool is_pos_allowed = false;; + bool zarcanum = false; - uint64_t index; // index in m_transfers - uint64_t stake_unlock_time; + uint64_t index = 0; // index in m_transfers + uint64_t stake_unlock_time = 0; //uint64_t block_timestamp; - uint64_t height; - uint64_t starter_timestamp; - crypto::hash last_block_hash; + uint64_t height = 0; + uint64_t starter_timestamp = 0; + crypto::hash last_block_hash = currency::null_hash; crypto::scalar_t last_pow_block_id_hashed; // Zarcanum notation: f' crypto::scalar_t secret_q; // Zarcanum notation: q @@ -480,9 +481,9 @@ namespace tools struct expiration_entry_info { std::vector selected_transfers; - uint64_t change_amount; - uint64_t expiration_time; - crypto::hash related_tx_id; // tx id which caused money lock, if any (ex: escrow proposal transport tx) + uint64_t change_amount = 0; + uint64_t expiration_time = 0; + crypto::hash related_tx_id = currency::null_hash; // tx id which caused money lock, if any (ex: escrow proposal transport tx) }; @@ -531,16 +532,16 @@ namespace tools struct process_transaction_context { - uint64_t tx_money_spent_in_ins; + uint64_t tx_money_spent_in_ins = 0; // check all outputs for spending (compare key images) money_transfer2_details mtd; - bool is_pos_coinbase; - bool coin_base_tx; + bool is_pos_coinbase = false; + bool coin_base_tx = false; //PoW block don't have change, so all outs supposed to be marked as "mined" - bool is_derived_from_coinbase; - size_t i; - size_t sub_i; - uint64_t height; + bool is_derived_from_coinbase = false; + size_t i = 0; + size_t sub_i = 0; + uint64_t height = 0; }; @@ -597,7 +598,9 @@ namespace tools std::shared_ptr get_core_proxy(); uint64_t balance() const; uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined) const; + bool balance(std::unordered_map& balances, uint64_t& mined) const; uint64_t balance(uint64_t& unloked) const; + uint64_t unlocked_balance() const; void transfer(uint64_t amount, const currency::account_public_address& acc); @@ -1143,7 +1146,7 @@ private: } // namespace tools BOOST_CLASS_VERSION(tools::wallet2, WALLET_FILE_SERIALIZATION_VERSION) -BOOST_CLASS_VERSION(tools::wallet_public::wallet_transfer_info, 10) +BOOST_CLASS_VERSION(tools::wallet_public::wallet_transfer_info, 11) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 3) BOOST_CLASS_VERSION(tools::wallet2::transfer_details_base, 2) @@ -1241,6 +1244,9 @@ namespace boost if (ver < 10) return; a & x.service_entries; + if (ver < 11) + return; + a & x.asset_id; } template diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 37fa3957..f207fcd6 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -114,6 +114,7 @@ namespace wallet_public std::vector contract; uint16_t extra_flags; uint64_t transfer_internal_index; + crypto::hash asset_id; //not included in kv serialization map @@ -143,6 +144,33 @@ namespace wallet_public KV_SERIALIZE(contract) KV_SERIALIZE(service_entries) KV_SERIALIZE(transfer_internal_index) + KV_SERIALIZE(asset_id) + END_KV_SERIALIZE_MAP() + }; + + struct asset_balance_entry_base + { + uint64_t total = 0; + uint64_t unlocked = 0; + uint64_t awaiting_in = 0; + uint64_t awaiting_out = 0; + + //v2 + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(total) + KV_SERIALIZE(unlocked) + KV_SERIALIZE(awaiting_in) + KV_SERIALIZE(awaiting_out) + END_KV_SERIALIZE_MAP() + }; + + struct asset_balance_entry : public asset_balance_entry_base + { + crypto::hash asset_id = currency::null_hash; + //v2 + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(asset_id) + KV_CHAIN_BASE(asset_balance_entry_base) END_KV_SERIALIZE_MAP() }; @@ -217,6 +245,7 @@ namespace wallet_public { uint64_t balance; uint64_t unlocked_balance; + std::list balances; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(balance) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 7f352048..20f6bcc8 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -188,6 +188,21 @@ namespace tools { res.balance = m_wallet.balance(); res.unlocked_balance = m_wallet.unlocked_balance(); + uint64_t mined = 0; + std::unordered_map balances; + m_wallet.balance(balances, mined); + auto it = balances.find(currency::null_hash); + if (it != balances.end()) + { + res.balance = it->second.total; + res.unlocked_balance = it->second.unlocked; + } + for (auto el : balances) + { + res.balances.push_back(wallet_public::asset_balance_entry()); + res.balances.back() = el.second; + res.balances.back().asset_id = el.first; + } } catch (std::exception& e) { From 1c76d0d325fd60f4824205352cff3d0dd0bbff10 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 16 Sep 2022 18:35:36 +0200 Subject: [PATCH 2/2] added balance() and rpc api implementations for multi_assets versions --- src/wallet/wallet2.cpp | 8 ++++---- src/wallet/wallet2.h | 2 +- src/wallet/wallet_rpc_server.cpp | 4 ++-- tests/core_tests/chaingen_main.cpp | 11 ++++++++--- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 386d2dfc..83e62a3d 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3009,7 +3009,7 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a awaiting_in = 0; awaiting_out = 0; mined = 0; - std::unordered_map balances; + std::unordered_map balances; balance(balances, mined); auto it = balances.find(currency::null_hash); if (it != balances.end()) @@ -3022,7 +3022,7 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a return total; } //---------------------------------------------------------------------------------------------------- -bool wallet2::balance(std::unordered_map& balances, uint64_t& mined) const +bool wallet2::balance(std::unordered_map& balances, uint64_t& mined) const { mined = 0; @@ -3030,7 +3030,7 @@ bool wallet2::balance(std::unordered_map { if (td.is_spendable() || (td.is_reserved_for_escrow() && !td.is_spent())) { - asset_balance_entry_base& e = balances[td.get_asset_id()]; + wallet_public::asset_balance_entry_base& e = balances[td.get_asset_id()]; e.total += td.amount(); if (is_transfer_unlocked(td)) e.unlocked += td.amount(); @@ -3041,7 +3041,7 @@ bool wallet2::balance(std::unordered_map for(auto& utx : m_unconfirmed_txs) { - asset_balance_entry_base& e = balances[utx.asset_id]; + wallet_public::asset_balance_entry_base& e = balances[utx.second.asset_id]; if (utx.second.is_income) { e.total += utx.second.amount; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index ccfc636a..277336a2 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -597,7 +597,7 @@ namespace tools std::shared_ptr get_core_proxy(); uint64_t balance() const; uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined) const; - bool balance(std::unordered_map& balances, uint64_t& mined) const; + bool balance(std::unordered_map& balances, uint64_t& mined) const; uint64_t balance(uint64_t& unloked) const; uint64_t unlocked_balance() const; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 20f6bcc8..9ecf1008 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -189,7 +189,7 @@ namespace tools res.balance = m_wallet.balance(); res.unlocked_balance = m_wallet.unlocked_balance(); uint64_t mined = 0; - std::unordered_map balances; + std::unordered_map balances; m_wallet.balance(balances, mined); auto it = balances.find(currency::null_hash); if (it != balances.end()) @@ -200,7 +200,7 @@ namespace tools for (auto el : balances) { res.balances.push_back(wallet_public::asset_balance_entry()); - res.balances.back() = el.second; + static_cast(res.balances.back()) = el.second; res.balances.back().asset_id = el.first; } } diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 8c3dc903..f5feb5c9 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -28,6 +28,7 @@ namespace const command_line::arg_descriptor arg_test_transactions ("test-transactions", ""); const command_line::arg_descriptor arg_run_single_test ("run-single-test", "" ); const command_line::arg_descriptor arg_enable_debug_asserts ("enable-debug-asserts", "" ); + const command_line::arg_descriptor arg_stop_on_fail ("stop-on-fail", ""); boost::program_options::variables_map g_vm; } @@ -671,13 +672,14 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_options, arg_test_transactions); command_line::add_arg(desc_options, arg_run_single_test); command_line::add_arg(desc_options, arg_enable_debug_asserts); + command_line::add_arg(desc_options, arg_stop_on_fail); command_line::add_arg(desc_options, command_line::arg_data_dir, std::string(".")); command_line::add_arg(desc_options, command_line::arg_stop_after_height); command_line::add_arg(desc_options, command_line::arg_disable_ntp); currency::core::init_options(desc_options); tools::db::db_backend_selector::init_options(desc_options); - + bool stop_on_first_fail = false; bool r = command_line::handle_error_helper(desc_options, [&]() { po::store(po::parse_command_line(argc, argv, desc_options), g_vm); @@ -693,6 +695,11 @@ int main(int argc, char* argv[]) return 0; } + if (command_line::has_arg(g_vm, arg_stop_on_fail)) + { + stop_on_first_fail = command_line::get_arg(g_vm, arg_stop_on_fail); + } + size_t tests_count = 0; size_t serious_failures_count = 0; std::set failed_tests; @@ -756,8 +763,6 @@ int main(int argc, char* argv[]) #undef MARK_TEST_AS_POSTPONED - bool stop_on_first_fail = false; - // TODO // GENERATE_AND_PLAY(wallet_spend_form_auditable_and_track);