diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/node_rpc_proxy.cpp | 11 | ||||
-rw-r--r-- | src/wallet/node_rpc_proxy.h | 2 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 48 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 20 |
4 files changed, 56 insertions, 25 deletions
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp index 95b8ce8bb..48a602bf3 100644 --- a/src/wallet/node_rpc_proxy.cpp +++ b/src/wallet/node_rpc_proxy.cpp @@ -72,6 +72,7 @@ void NodeRPCProxy::invalidate() m_rpc_version = 0; m_target_height = 0; m_block_weight_limit = 0; + m_adjusted_time = 0; m_get_info_time = 0; m_rpc_payment_info_time = 0; m_rpc_payment_seed_height = 0; @@ -131,6 +132,7 @@ boost::optional<std::string> NodeRPCProxy::get_info() m_height = resp_t.height; m_target_height = resp_t.target_height; m_block_weight_limit = resp_t.block_weight_limit ? resp_t.block_weight_limit : resp_t.block_size_limit; + m_adjusted_time = resp_t.adjusted_time; m_get_info_time = now; m_height_time = now; } @@ -171,6 +173,15 @@ boost::optional<std::string> NodeRPCProxy::get_block_weight_limit(uint64_t &bloc return boost::optional<std::string>(); } +boost::optional<std::string> NodeRPCProxy::get_adjusted_time(uint64_t &adjusted_time) +{ + auto res = get_info(); + if (res) + return res; + adjusted_time = m_adjusted_time; + return boost::optional<std::string>(); +} + boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) { if (m_offline) diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h index 500ba81d4..51b7f01dd 100644 --- a/src/wallet/node_rpc_proxy.h +++ b/src/wallet/node_rpc_proxy.h @@ -52,6 +52,7 @@ public: void set_height(uint64_t h); boost::optional<std::string> get_target_height(uint64_t &height); boost::optional<std::string> get_block_weight_limit(uint64_t &block_weight_limit); + boost::optional<std::string> get_adjusted_time(uint64_t &adjusted_time); boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height); boost::optional<std::string> get_dynamic_base_fee_estimate(uint64_t grace_blocks, uint64_t &fee); boost::optional<std::string> get_fee_quantization_mask(uint64_t &fee_quantization_mask); @@ -84,6 +85,7 @@ private: uint64_t m_dynamic_base_fee_estimate_cached_height; uint64_t m_dynamic_base_fee_estimate_grace_blocks; uint64_t m_fee_quantization_mask; + uint64_t m_adjusted_time; uint32_t m_rpc_version; uint64_t m_target_height; uint64_t m_block_weight_limit; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3e2ccd1ff..063c493ce 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -301,7 +301,7 @@ struct options { const command_line::arg_descriptor<std::string> tx_notify = { "tx-notify" , "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" , "" }; const command_line::arg_descriptor<bool> no_dns = {"no-dns", tools::wallet2::tr("Do not use DNS"), false}; const command_line::arg_descriptor<bool> offline = {"offline", tools::wallet2::tr("Do not connect to a daemon, nor use DNS"), false}; - const command_line::arg_descriptor<std::string> extra_entropy = {"extra-entropy", tools::wallet2::tr("File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, wihch typically means more than 256 bits of data)")}; + const command_line::arg_descriptor<std::string> extra_entropy = {"extra-entropy", tools::wallet2::tr("File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, which typically means more than 256 bits of data)")}; }; void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file) @@ -5969,7 +5969,7 @@ uint64_t wallet2::balance(uint32_t index_major, bool strict) const return amount; } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const +uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) { uint64_t amount = 0; if (blocks_to_unlock) @@ -6021,7 +6021,7 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo return amount_per_subaddr; } //---------------------------------------------------------------------------------------------------- -std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const +std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) { std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> amount_per_subaddr; const uint64_t blockchain_height = get_blockchain_current_height(); @@ -6069,7 +6069,7 @@ uint64_t wallet2::balance_all(bool strict) const return r; } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const +uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) { uint64_t r = 0; if (blocks_to_unlock) @@ -6234,12 +6234,12 @@ void wallet2::rescan_blockchain(bool hard, bool refresh, bool keep_key_images) finish_rescan_bc_keep_key_images(transfers_cnt, transfers_hash); } //---------------------------------------------------------------------------------------------------- -bool wallet2::is_transfer_unlocked(const transfer_details& td) const +bool wallet2::is_transfer_unlocked(const transfer_details& td) { return is_transfer_unlocked(td.m_tx.unlock_time, td.m_block_height); } //---------------------------------------------------------------------------------------------------- -bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) const +bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) { if(!is_tx_spendtime_unlocked(unlock_time, block_height)) return false; @@ -6250,7 +6250,7 @@ bool wallet2::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) const +bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) { if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) { @@ -6262,12 +6262,14 @@ bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_heig }else { //interpret as time - uint64_t current_time = static_cast<uint64_t>(time(NULL)); + uint64_t adjusted_time; + try { adjusted_time = get_daemon_adjusted_time(); } + catch(...) { adjusted_time = time(NULL); } // use local time if no daemon to report blockchain time // XXX: this needs to be fast, so we'd need to get the starting heights // from the daemon to be correct once voting kicks in uint64_t v2height = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827; uint64_t leeway = block_height < v2height ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2; - if(current_time + leeway >= unlock_time) + if(adjusted_time + leeway >= unlock_time) return true; else return false; @@ -8052,13 +8054,16 @@ std::pair<std::set<uint64_t>, size_t> outs_unique(const std::vector<std::vector< return std::make_pair(std::move(unique), total); } -void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count) +void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct) { std::vector<uint64_t> rct_offsets; for (size_t attempts = 3; attempts > 0; --attempts) { get_outs(outs, selected_transfers, fake_outputs_count, rct_offsets); + if (!rct) + return; + const auto unique = outs_unique(outs); if (tx_sanity_check(unique.first, unique.second, rct_offsets.empty() ? 0 : rct_offsets.back())) { @@ -8696,7 +8701,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts"); if (outs.empty()) - get_outs(outs, selected_transfers, fake_outputs_count); // may throw + get_outs(outs, selected_transfers, fake_outputs_count, false); // may throw //prepare inputs LOG_PRINT_L2("preparing outputs"); @@ -8897,10 +8902,12 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry MDEBUG("We will create " << n_multisig_txes << " txes"); } + bool all_rct = true; uint64_t found_money = 0; for(size_t idx: selected_transfers) { found_money += m_transfers[idx].amount(); + all_rct &= m_transfers[idx].is_rct(); } LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee)); @@ -8911,7 +8918,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts"); if (outs.empty()) - get_outs(outs, selected_transfers, fake_outputs_count); // may throw + get_outs(outs, selected_transfers, fake_outputs_count, all_rct); // may throw //prepare inputs LOG_PRINT_L2("preparing outputs"); @@ -9104,7 +9111,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry LOG_PRINT_L2("transfer_selected_rct done"); } -std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const +std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) { std::vector<size_t> picks; float current_output_relatdness = 1.0f; @@ -10352,7 +10359,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring; const uint64_t fractional_threshold = (fee_multiplier * base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024); - THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, false) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet"); + THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, false) == 0, error::wallet_internal_error, "No unlocked balance in the specified account"); std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr; @@ -10682,7 +10689,7 @@ void wallet2::cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_ hw::wallet_shim wallet_shim; setup_shim(&wallet_shim, this); aux_data.tx_recipients = dsts_info; - aux_data.bp_version = use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1; + aux_data.bp_version = (use_fork_rules(HF_VERSION_CLSAG, -10) ? 3 : use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1); aux_data.hard_fork = get_current_hard_fork(); dev_cold->tx_sign(&wallet_shim, txs, exported_txs, aux_data); tx_device_aux = aux_data.tx_device_aux; @@ -10775,7 +10782,7 @@ uint64_t wallet2::get_upper_transaction_weight_limit() return full_reward_zone - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; } //---------------------------------------------------------------------------------------------------- -std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(const transfer_details &td)> &f) const +std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(const transfer_details &td)> &f) { std::vector<size_t> outputs; size_t n = 0; @@ -12080,6 +12087,15 @@ uint64_t wallet2::get_daemon_blockchain_height(string &err) return height; } +uint64_t wallet2::get_daemon_adjusted_time() +{ + uint64_t adjusted_time; + + boost::optional<std::string> result = m_node_rpc_proxy.get_adjusted_time(adjusted_time); + THROW_WALLET_EXCEPTION_IF(result, error::wallet_internal_error, "Invalid adjusted time from daemon"); + return adjusted_time; +} + uint64_t wallet2::get_daemon_blockchain_target_height(string &err) { err = ""; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 62ed111f1..eac99185c 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -939,13 +939,13 @@ private: // locked & unlocked balance of given or current subaddress account uint64_t balance(uint32_t subaddr_index_major, bool strict) const; - uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const; + uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL); // locked & unlocked balance per subaddress of given or current subaddress account std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const; - std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const; + std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict); // all locked & unlocked balances of all subaddress accounts uint64_t balance_all(bool strict) const; - uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const; + uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL); template<typename T> void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, @@ -1003,8 +1003,8 @@ private: uint64_t get_blockchain_current_height() const { return m_light_wallet_blockchain_height ? m_light_wallet_blockchain_height : m_blockchain.size(); } void rescan_spent(); void rescan_blockchain(bool hard, bool refresh = true, bool keep_key_images = false); - bool is_transfer_unlocked(const transfer_details& td) const; - bool is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) const; + bool is_transfer_unlocked(const transfer_details& td); + bool is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height); uint64_t get_last_block_reward() const { return m_last_block_reward; } uint64_t get_device_last_key_image_sync() const { return m_device_last_key_image_sync; } @@ -1301,13 +1301,15 @@ private: const boost::optional<epee::net_utils::http::login>& get_daemon_login() const { return m_daemon_login; } uint64_t get_daemon_blockchain_height(std::string& err); uint64_t get_daemon_blockchain_target_height(std::string& err); + uint64_t get_daemon_adjusted_time(); + /*! * \brief Calculates the approximate blockchain height from current date/time. */ uint64_t get_approximate_blockchain_height() const; uint64_t estimate_blockchain_height(); std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct); - std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f) const; + std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f); std::vector<size_t> select_available_unmixable_outputs(); std::vector<size_t> select_available_mixable_outputs(); @@ -1536,7 +1538,7 @@ private: void set_tx_notify(const std::shared_ptr<tools::Notify> ¬ify) { m_tx_notify = notify; } - bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height) const; + bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height); void hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const; uint64_t hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const; void finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash); @@ -1600,12 +1602,12 @@ private: std::vector<uint64_t> get_unspent_amounts_vector(bool strict); uint64_t get_dynamic_base_fee_estimate(); float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const; - std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const; + std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices); void set_spent(size_t idx, uint64_t height); void set_unspent(size_t idx); bool is_spent(const transfer_details &td, bool strict = true) const; bool is_spent(size_t idx, bool strict = true) const; - void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count); + void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct); void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, std::vector<uint64_t> &rct_offsets); bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const; |