diff options
Diffstat (limited to 'src')
28 files changed, 210 insertions, 135 deletions
diff --git a/src/crypto/CryptonightR_JIT.c b/src/crypto/CryptonightR_JIT.c index ee8f3f36f..ffe7820a2 100644 --- a/src/crypto/CryptonightR_JIT.c +++ b/src/crypto/CryptonightR_JIT.c @@ -63,7 +63,7 @@ int v4_generate_JIT_code(const struct V4_Instruction* code, v4_random_math_JIT_f #if !(defined(_MSC_VER) || defined(__MINGW32__)) if (mprotect((void*)buf, buf_size, PROT_READ | PROT_WRITE)) - return 1; + return -1; #endif APPEND_CODE(prologue, sizeof(prologue)); @@ -111,13 +111,13 @@ int v4_generate_JIT_code(const struct V4_Instruction* code, v4_random_math_JIT_f #if !(defined(_MSC_VER) || defined(__MINGW32__)) if (mprotect((void*)buf, buf_size, PROT_READ | PROT_EXEC)) - return 1; + return -1; #endif __builtin___clear_cache((char*)buf, (char*)JIT_code); return 0; #else - return 1; + return -1; #endif } diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index 3f06c4f3f..d4b2a22bc 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -275,8 +275,6 @@ namespace crypto { buf.key = pub; try_again: random_scalar(k); - if (((const uint32_t*)(&k))[7] == 0) // we don't want tiny numbers here - goto try_again; ge_scalarmult_base(&tmp3, &k); ge_p3_tobytes(&buf.comm, &tmp3); hash_to_scalar(&buf, sizeof(s_comm), sig.c); diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index e594eb049..2dad2795e 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -91,7 +91,7 @@ namespace cryptonote const command_line::arg_descriptor<std::string> arg_extra_messages = {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true}; const command_line::arg_descriptor<std::string> arg_start_mining = {"start-mining", "Specify wallet address to mining for", "", true}; const command_line::arg_descriptor<uint32_t> arg_mining_threads = {"mining-threads", "Specify mining threads count", 0, true}; - const command_line::arg_descriptor<bool> arg_bg_mining_enable = {"bg-mining-enable", "enable/disable background mining", true, true}; + const command_line::arg_descriptor<bool> arg_bg_mining_enable = {"bg-mining-enable", "enable background mining", true, true}; const command_line::arg_descriptor<bool> arg_bg_mining_ignore_battery = {"bg-mining-ignore-battery", "if true, assumes plugged in when unable to query system power status", false, true}; const command_line::arg_descriptor<uint64_t> arg_bg_mining_min_idle_interval_seconds = {"bg-mining-min-idle-interval", "Specify min lookback interval in seconds for determining idle state", miner::BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS, true}; const command_line::arg_descriptor<uint16_t> arg_bg_mining_idle_threshold_percentage = {"bg-mining-idle-threshold", "Specify minimum avg idle percentage over lookback interval", miner::BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE, true}; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 0ea81f19a..dab1a0a96 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -715,7 +715,6 @@ block Blockchain::pop_block_from_blockchain() m_blocks_longhash_table.clear(); m_scan_table.clear(); m_blocks_txs_check.clear(); - m_check_txin_table.clear(); CHECK_AND_ASSERT_THROW_MES(update_next_cumulative_weight_limit(), "Error updating next cumulative weight limit"); uint64_t top_block_height; @@ -2612,7 +2611,7 @@ void Blockchain::on_new_tx_from_block(const cryptonote::transaction &tx) // This function overloads its sister function with // an extra value (hash of highest block that holds an output used as input) // as a return-by-reference. -bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block) +bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block) const { LOG_PRINT_L3("Blockchain::" << __func__); CRITICAL_REGION_LOCAL(m_blockchain_lock); @@ -2643,7 +2642,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_heigh return true; } //------------------------------------------------------------------ -bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context &tvc) +bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context &tvc) const { LOG_PRINT_L3("Blockchain::" << __func__); CRITICAL_REGION_LOCAL(m_blockchain_lock); @@ -2752,7 +2751,7 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const } return false; } -bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys) +bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys) const { PERF_TIMER(expand_transaction_2); CHECK_AND_ASSERT_MES(tx.version == 2, false, "Transaction version is not 2"); @@ -2828,7 +2827,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr // check_tx_input() rather than here, and use this function simply // to iterate the inputs as necessary (splitting the task // using threads, etc.) -bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, uint64_t* pmax_used_block_height) +bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, uint64_t* pmax_used_block_height) const { PERF_TIMER(check_tx_inputs); LOG_PRINT_L3("Blockchain::" << __func__); @@ -2947,13 +2946,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, } } } - auto it = m_check_txin_table.find(tx_prefix_hash); - if(it == m_check_txin_table.end()) - { - m_check_txin_table.emplace(tx_prefix_hash, std::unordered_map<crypto::key_image, bool>()); - it = m_check_txin_table.find(tx_prefix_hash); - assert(it != m_check_txin_table.end()); - } std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size()); std::vector < uint64_t > results; @@ -2985,29 +2977,12 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, { // basically, make sure number of inputs == number of signatures CHECK_AND_ASSERT_MES(sig_index < tx.signatures.size(), false, "wrong transaction: not signature entry for input with index= " << sig_index); - -#if defined(CACHE_VIN_RESULTS) - auto itk = it->second.find(in_to_key.k_image); - if(itk != it->second.end()) - { - if(!itk->second) - { - MERROR_VER("Failed ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index); - return false; - } - - // txin has been verified already, skip - sig_index++; - continue; - } -#endif } // make sure that output being spent matches up correctly with the // signature spending it. if (!check_tx_input(tx.version, in_to_key, tx_prefix_hash, tx.version == 1 ? tx.signatures[sig_index] : std::vector<crypto::signature>(), tx.rct_signatures, pubkeys[sig_index], pmax_used_block_height)) { - it->second[in_to_key.k_image] = false; MERROR_VER("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index); if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain() { @@ -3030,7 +3005,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, check_ring_signature(tx_prefix_hash, in_to_key.k_image, pubkeys[sig_index], tx.signatures[sig_index], results[sig_index]); if (!results[sig_index]) { - it->second[in_to_key.k_image] = false; MERROR_VER("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index); if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain() @@ -3040,7 +3014,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, return false; } - it->second[in_to_key.k_image] = true; } } @@ -3058,7 +3031,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, for (size_t i = 0; i < tx.vin.size(); i++) { const txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin[i]); - it->second[in_to_key.k_image] = results[i]; if(!failed && !results[i]) failed = true; } @@ -3232,7 +3204,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, } //------------------------------------------------------------------ -void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector<rct::ctkey> &pubkeys, const std::vector<crypto::signature>& sig, uint64_t &result) +void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector<rct::ctkey> &pubkeys, const std::vector<crypto::signature>& sig, uint64_t &result) const { std::vector<const crypto::public_key *> p_output_keys; p_output_keys.reserve(pubkeys.size()); @@ -3418,7 +3390,7 @@ bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const // This function locates all outputs associated with a given input (mixins) // and validates that they exist and are usable. It also checks the ring // signature for each input. -bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height) +bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height) const { LOG_PRINT_L3("Blockchain::" << __func__); @@ -4255,7 +4227,6 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) m_blocks_longhash_table.clear(); m_scan_table.clear(); m_blocks_txs_check.clear(); - m_check_txin_table.clear(); // when we're well clear of the precomputed hashes, free the memory if (!m_blocks_hash_check.empty() && m_db->height() > m_blocks_hash_check.size() + 4096) @@ -4544,7 +4515,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete m_fake_pow_calc_time = 0; m_scan_table.clear(); - m_check_txin_table.clear(); TIME_MEASURE_FINISH(prepare); m_fake_pow_calc_time = prepare / blocks_entry.size(); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index d95f2dceb..f58059a6d 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -548,7 +548,7 @@ namespace cryptonote * * @return false if any input is invalid, otherwise true */ - bool check_tx_inputs(transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false); + bool check_tx_inputs(transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false) const; /** * @brief get fee quantization mask @@ -615,7 +615,7 @@ namespace cryptonote * * @return false if any outputs do not conform, otherwise true */ - bool check_tx_outputs(const transaction& tx, tx_verification_context &tvc); + bool check_tx_outputs(const transaction& tx, tx_verification_context &tvc) const; /** * @brief gets the block weight limit based on recent blocks @@ -1020,7 +1020,6 @@ namespace cryptonote // metadata containers std::unordered_map<crypto::hash, std::unordered_map<crypto::key_image, std::vector<output_data_t>>> m_scan_table; std::unordered_map<crypto::hash, crypto::hash> m_blocks_longhash_table; - std::unordered_map<crypto::hash, std::unordered_map<crypto::key_image, bool>> m_check_txin_table; // SHA-3 hashes for each block and for fast pow checking std::vector<crypto::hash> m_blocks_hash_of_hashes; @@ -1127,7 +1126,7 @@ namespace cryptonote * * @return false if any output is not yet unlocked, or is missing, otherwise true */ - bool check_tx_input(size_t tx_version,const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height); + bool check_tx_input(size_t tx_version,const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const rct::rctSig &rct_signatures, std::vector<rct::ctkey> &output_keys, uint64_t* pmax_related_block_height) const; /** * @brief validate a transaction's inputs and their keys @@ -1149,7 +1148,7 @@ namespace cryptonote * * @return false if any validation step fails, otherwise true */ - bool check_tx_inputs(transaction& tx, tx_verification_context &tvc, uint64_t* pmax_used_block_height = NULL); + bool check_tx_inputs(transaction& tx, tx_verification_context &tvc, uint64_t* pmax_used_block_height = NULL) const; /** * @brief performs a blockchain reorganization according to the longest chain rule @@ -1429,7 +1428,7 @@ namespace cryptonote * @param result false if the ring signature is invalid, otherwise true */ void check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, - const std::vector<rct::ctkey> &pubkeys, const std::vector<crypto::signature> &sig, uint64_t &result); + const std::vector<rct::ctkey> &pubkeys, const std::vector<crypto::signature> &sig, uint64_t &result) const; /** * @brief loads block hashes from compiled-in data set @@ -1449,7 +1448,7 @@ namespace cryptonote * can be reconstituted by the receiver. This function expands * that implicit data. */ - bool expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys); + bool expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys) const; /** * @brief invalidates any cached block template diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 854f3d1c5..4cf71e558 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -354,7 +354,7 @@ namespace cryptonote if (shuffle_outs) { - std::shuffle(destinations.begin(), destinations.end(), std::default_random_engine(crypto::rand<unsigned int>())); + std::shuffle(destinations.begin(), destinations.end(), crypto::random_device{}); } // sort ins by their key image diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index d38aa7474..b03eb6e70 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -83,6 +83,21 @@ namespace cryptonote tx_destination_entry(uint64_t a, const account_public_address &ad, bool is_subaddress) : amount(a), addr(ad), is_subaddress(is_subaddress), is_integrated(false) { } tx_destination_entry(const std::string &o, uint64_t a, const account_public_address &ad, bool is_subaddress) : original(o), amount(a), addr(ad), is_subaddress(is_subaddress), is_integrated(false) { } + std::string address(network_type nettype, const crypto::hash &payment_id) const + { + if (!original.empty()) + { + return original; + } + + if (is_integrated) + { + return get_account_integrated_address_as_str(nettype, addr, reinterpret_cast<const crypto::hash8 &>(payment_id)); + } + + return get_account_address_as_str(nettype, is_subaddress, addr); + } + BEGIN_SERIALIZE_OBJECT() FIELD(original) VARINT_FIELD(amount) diff --git a/src/cryptonote_core/tx_sanity_check.cpp b/src/cryptonote_core/tx_sanity_check.cpp index e95350f76..03cbb5c26 100644 --- a/src/cryptonote_core/tx_sanity_check.cpp +++ b/src/cryptonote_core/tx_sanity_check.cpp @@ -82,7 +82,7 @@ bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob if (rct_indices.size() < n_indices * 8 / 10) { - MERROR("unique indices is only " << rct_indices.size() << "/" << n_indices); + MERROR("amount of unique indices is too low (amount of rct indices is " << rct_indices.size() << ", out of total " << n_indices << "indices."); return false; } @@ -90,7 +90,7 @@ bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob uint64_t median = epee::misc_utils::median(offsets); if (median < n_available * 6 / 10) { - MERROR("median is " << median << "/" << n_available); + MERROR("median offset index is too low (median is " << median << " out of total " << n_available << "offsets). Transactions should contain a higher fraction of recent outputs."); return false; } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index a1fa9484c..2ff7b5938 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -342,7 +342,7 @@ namespace cryptonote if(m_core.have_block(hshd.top_id)) { - if (target > hshd.current_height) + if (target > m_core.get_current_blockchain_height()) { MINFO(context << "peer is not ahead of us and we're syncing, disconnecting"); return false; diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index dbf0409e5..4d3debed6 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -66,15 +66,11 @@ namespace { time(&now); time_t last_seen = static_cast<time_t>(peer.last_seen); - std::string id_str; + std::string elapsed = epee::misc_utils::get_time_interval_string(now - last_seen); + std::string id_str = epee::string_tools::pad_string(epee::string_tools::to_string_hex(peer.id), 16, '0', true); std::string port_str; - std::string elapsed = peer.last_seen == 0 ? "never" : epee::misc_utils::get_time_interval_string(now - last_seen); - std::string ip_str = peer.ip != 0 ? epee::string_tools::get_ip_string_from_int32(peer.ip) : std::string("[") + peer.host + "]"; - std::stringstream peer_id_str; - peer_id_str << std::hex << std::setw(16) << peer.id; - peer_id_str >> id_str; epee::string_tools::xtype_to_string(peer.port, port_str); - std::string addr_str = ip_str + ":" + port_str; + std::string addr_str = peer.host + ":" + port_str; std::string rpc_port = peer.rpc_port ? std::to_string(peer.rpc_port) : "-"; std::string pruning_seed = epee::string_tools::to_string_hex(peer.pruning_seed); tools::msg_writer() << boost::format("%-10s %-25s %-25s %-5s %-4s %s") % prefix % id_str % addr_str % rpc_port % pruning_seed % elapsed; @@ -222,6 +218,9 @@ bool t_rpc_command_executor::print_peer_list_stats() { cryptonote::COMMAND_RPC_GET_PEER_LIST::response res; std::string failure_message = "Couldn't retrieve peer list"; + + req.public_only = false; + if (m_is_rpc) { if (!m_rpc_client->rpc_request(req, res, "/get_peer_list", failure_message.c_str())) diff --git a/src/device/device_io_hid.cpp b/src/device/device_io_hid.cpp index 721bed9ca..72f4c3bdb 100644 --- a/src/device/device_io_hid.cpp +++ b/src/device/device_io_hid.cpp @@ -44,7 +44,8 @@ namespace hw { static std::string safe_hid_error(hid_device *hwdev) { if (hwdev) { - return std::string((char*)hid_error(hwdev)); + const char* error_str = (const char*)hid_error(hwdev); + return std::string(error_str == nullptr ? "Unknown error" : error_str); } return std::string("NULL device"); } diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index cf6b2c67b..6d2ae878f 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -254,6 +254,7 @@ namespace nodetool size_t get_public_white_peers_count(); size_t get_public_gray_peers_count(); void get_public_peerlist(std::vector<peerlist_entry>& gray, std::vector<peerlist_entry>& white); + void get_peerlist(std::vector<peerlist_entry>& gray, std::vector<peerlist_entry>& white); size_t get_zone_count() const { return m_network_zones.size(); } void change_max_out_public_peers(size_t count); diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 00467132a..8c0cff7e2 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1739,6 +1739,15 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::get_peerlist(std::vector<peerlist_entry>& gray, std::vector<peerlist_entry>& white) + { + for (auto &zone: m_network_zones) + { + zone.second.m_peerlist.get_peerlist(gray, white); // appends + } + } + //----------------------------------------------------------------------------------- + template<class t_payload_net_handler> bool node_server<t_payload_net_handler>::idle_worker() { m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::peer_sync_idle_maker, this)); diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index 68627375a..c65b9dd82 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -293,7 +293,7 @@ namespace nodetool if (anonymize) { - std::random_shuffle(bs_head.begin(), bs_head.end()); + std::shuffle(bs_head.begin(), bs_head.end(), crypto::random_device{}); if (bs_head.size() > depth) bs_head.resize(depth); for (auto &e: bs_head) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 9aaaa026d..73138686d 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1044,31 +1044,35 @@ namespace cryptonote PERF_TIMER(on_get_peer_list); std::vector<nodetool::peerlist_entry> white_list; std::vector<nodetool::peerlist_entry> gray_list; - m_p2p.get_public_peerlist(gray_list, white_list); - res.white_list.reserve(white_list.size()); + if (req.public_only) + { + m_p2p.get_public_peerlist(gray_list, white_list); + } + else + { + m_p2p.get_peerlist(gray_list, white_list); + } + for (auto & entry : white_list) { if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id()) res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(), entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port); else if (entry.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) - { res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv6_network_address>().host_str(), entry.adr.as<epee::net_utils::ipv6_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port); - } else res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port); } - res.gray_list.reserve(gray_list.size()); for (auto & entry : gray_list) { if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id()) res.gray_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(), entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port); else if (entry.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) - res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv6_network_address>().host_str(), + res.gray_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv6_network_address>().host_str(), entry.adr.as<epee::net_utils::ipv6_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port); else res.gray_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen, entry.pruning_seed, entry.rpc_port); @@ -1329,6 +1333,20 @@ namespace cryptonote return false; } + if(req.reserve_size && !req.extra_nonce.empty()) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Cannot specify both a reserve_size and an extra_nonce"; + return false; + } + + if(req.extra_nonce.size() > 510) + { + error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE; + error_resp.message = "Too big extra_nonce size, maximum 510 hex chars"; + return false; + } + cryptonote::address_parse_info info; if(!req.wallet_address.size() || !cryptonote::get_account_address_from_str(info, nettype(), req.wallet_address)) @@ -1346,7 +1364,17 @@ namespace cryptonote block b; cryptonote::blobdata blob_reserve; - blob_reserve.resize(req.reserve_size, 0); + if(!req.extra_nonce.empty()) + { + if(!string_tools::parse_hexstr_to_binbuff(req.extra_nonce, blob_reserve)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Parameter extra_nonce should be a hex string"; + return false; + } + } + else + blob_reserve.resize(req.reserve_size, 0); cryptonote::difficulty_type wdiff; crypto::hash prev_block; if (!req.prev_block.empty()) diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 7ae0c77b2..aed967efb 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -87,7 +87,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 2 -#define CORE_RPC_VERSION_MINOR 8 +#define CORE_RPC_VERSION_MINOR 9 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -924,11 +924,13 @@ namespace cryptonote uint64_t reserve_size; //max 255 bytes std::string wallet_address; std::string prev_block; + std::string extra_nonce; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(reserve_size) KV_SERIALIZE(wallet_address) KV_SERIALIZE(prev_block) + KV_SERIALIZE(extra_nonce) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1228,7 +1230,10 @@ namespace cryptonote { struct request_t { + bool public_only; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_OPT(public_only, true) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; diff --git a/src/rpc/rpc_handler.cpp b/src/rpc/rpc_handler.cpp index af5cb98a3..d528ffef3 100644 --- a/src/rpc/rpc_handler.cpp +++ b/src/rpc/rpc_handler.cpp @@ -63,7 +63,9 @@ namespace rpc d.cached_to -= 10; d.cached_top_hash = hash10; d.cached_m10_hash = crypto::null_hash; - d.cached_distribution.resize(d.cached_distribution.size() - 10); + CHECK_AND_ASSERT_MES(d.cached_distribution.size() >= 10, boost::none, "Cached distribution size does not match cached bounds"); + for (int p = 0; p < 10; ++p) + d.cached_distribution.pop_back(); can_extend = true; } } diff --git a/src/rpc/zmq_server.cpp b/src/rpc/zmq_server.cpp index ae748e052..668a2e5cd 100644 --- a/src/rpc/zmq_server.cpp +++ b/src/rpc/zmq_server.cpp @@ -59,7 +59,7 @@ void ZmqServer::serve() { throw std::runtime_error("ZMQ RPC server reply socket is null"); } - while (rep_socket->recv(&message)) + while (rep_socket->recv(&message, 0)) { std::string message_string(reinterpret_cast<const char *>(message.data()), message.size()); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 9bae6c028..5d7321e48 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -201,11 +201,11 @@ namespace const char* USAGE_SET_DESCRIPTION("set_description [free text note]"); const char* USAGE_SIGN("sign <filename>"); const char* USAGE_VERIFY("verify <filename> <address> <signature>"); - const char* USAGE_EXPORT_KEY_IMAGES("export_key_images <filename>"); + const char* USAGE_EXPORT_KEY_IMAGES("export_key_images [all] <filename>"); const char* USAGE_IMPORT_KEY_IMAGES("import_key_images <filename>"); const char* USAGE_HW_KEY_IMAGES_SYNC("hw_key_images_sync"); const char* USAGE_HW_RECONNECT("hw_reconnect"); - const char* USAGE_EXPORT_OUTPUTS("export_outputs <filename>"); + const char* USAGE_EXPORT_OUTPUTS("export_outputs [all] <filename>"); const char* USAGE_IMPORT_OUTPUTS("import_outputs <filename>"); const char* USAGE_SHOW_TRANSFER("show_transfer <txid>"); const char* USAGE_MAKE_MULTISIG("make_multisig <threshold> <string1> [<string>...]"); @@ -803,6 +803,12 @@ bool simple_wallet::encrypted_seed(const std::vector<std::string> &args/* = std: return print_seed(true); } +bool simple_wallet::restore_height(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +{ + success_msg_writer() << m_wallet->get_refresh_from_block_height(); + return true; +} + bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { if (m_wallet->key_on_device()) @@ -2689,7 +2695,7 @@ bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std return true; } - m_wallet->device_name(args[0]); + m_wallet->device_name(args[1]); bool r = false; try { r = m_wallet->reconnect_device(); @@ -2845,6 +2851,9 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), tr("Display the Electrum-style mnemonic seed")); + m_cmd_binder.set_handler("restore_height", + boost::bind(&simple_wallet::restore_height, this, _1), + tr("Display the restore height")); m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr(USAGE_SET_VARIABLE), @@ -2881,6 +2890,8 @@ simple_wallet::simple_wallet() " Whether to warn if there is transaction backlog.\n " "confirm-backlog-threshold [n]\n " " Set a threshold for confirm-backlog to only warn if the transaction backlog is greater than n blocks.\n " + "confirm-export-overwrite <1|0>\n " + " Whether to warn if the file to be exported already exists.\n " "refresh-from-block-height [n]\n " " Set the height before which to ignore blocks.\n " "auto-low-priority <1|0>\n " @@ -2888,12 +2899,20 @@ simple_wallet::simple_wallet() "segregate-pre-fork-outputs <1|0>\n " " Set this if you intend to spend outputs on both Monero AND a key reusing fork.\n " "key-reuse-mitigation2 <1|0>\n " - " Set this if you are not sure whether you will spend on a key reusing Monero fork later.\n" + " Set this if you are not sure whether you will spend on a key reusing Monero fork later.\n " "subaddress-lookahead <major>:<minor>\n " " Set the lookahead sizes for the subaddress hash table.\n " " Set this if you are not sure whether you will spend on a key reusing Monero fork later.\n " "segregation-height <n>\n " - " Set to the height of a key reusing fork you want to use, 0 to use default.")); + " Set to the height of a key reusing fork you want to use, 0 to use default.\n " + "ignore-fractional-outputs <1|0>\n " + " Whether to ignore fractional outputs that result in net loss when spending due to fee.\n " + "track-uses <1|0>\n " + " Whether to keep track of owned outputs uses.\n " + "setup-background-mining <1|0>\n " + " Whether to enable background mining. Set this to support the network and to get a chance to receive new monero.\n " + "device-name <device_name[:device_spec]>\n " + " Device name for hardware wallet.")); m_cmd_binder.set_handler("encrypted_seed", boost::bind(&simple_wallet::encrypted_seed, this, _1), tr("Display the encrypted Electrum-style mnemonic seed.")); @@ -3130,7 +3149,7 @@ simple_wallet::simple_wallet() tr("Available options:\n " "auto-send <1|0>\n " " Whether to automatically send newly generated messages right away.\n ")); - m_cmd_binder.set_handler("mms send_message_config", + m_cmd_binder.set_handler("mms send_signer_config", boost::bind(&simple_wallet::mms, this, _1), tr(USAGE_MMS_SEND_SIGNER_CONFIG), tr("Send completed signer config to all other authorized signers")); @@ -3257,8 +3276,8 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) success_msg_writer() << "segregation-height = " << m_wallet->segregation_height(); success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs(); success_msg_writer() << "track-uses = " << m_wallet->track_uses(); - success_msg_writer() << "setup-background-mining = " << setup_background_mining_string + tr(" (set this to support the network and to get a chance to receive new monero)"); - success_msg_writer() << "device_name = " << m_wallet->device_name(); + success_msg_writer() << "setup-background-mining = " << setup_background_mining_string; + success_msg_writer() << "device-name = " << m_wallet->device_name(); return true; } else @@ -7811,7 +7830,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec uint64_t fee = pd.m_amount_in - pd.m_amount_out; std::vector<std::pair<std::string, uint64_t>> destinations; for (const auto &d: pd.m_dests) { - destinations.push_back({get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr), d.amount}); + destinations.push_back({d.address(m_wallet->nettype(), pd.m_payment_id), d.amount}); } std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) @@ -7887,7 +7906,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec uint64_t fee = amount - pd.m_amount_out; std::vector<std::pair<std::string, uint64_t>> destinations; for (const auto &d: pd.m_dests) { - destinations.push_back({get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr), d.amount}); + destinations.push_back({d.address(m_wallet->nettype(), pd.m_payment_id), d.amount}); } std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) @@ -9044,21 +9063,31 @@ bool simple_wallet::verify(const std::vector<std::string> &args) return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::export_key_images(const std::vector<std::string> &args) +bool simple_wallet::export_key_images(const std::vector<std::string> &args_) { if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if (args.size() != 1) + auto args = args_; + + if (m_wallet->watch_only()) { - PRINT_USAGE(USAGE_EXPORT_KEY_IMAGES); + fail_msg_writer() << tr("wallet is watch-only and cannot export key images"); return true; } - if (m_wallet->watch_only()) + + bool all = false; + if (args.size() >= 2 && args[0] == "all") { - fail_msg_writer() << tr("wallet is watch-only and cannot export key images"); + all = true; + args.erase(args.begin()); + } + + if (args.size() != 1) + { + PRINT_USAGE(USAGE_EXPORT_KEY_IMAGES); return true; } @@ -9070,7 +9099,7 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args) try { - if (!m_wallet->export_key_images(filename)) + if (!m_wallet->export_key_images(filename, all)) { fail_msg_writer() << tr("failed to save file ") << filename; return true; @@ -9195,13 +9224,22 @@ bool simple_wallet::hw_reconnect(const std::vector<std::string> &args) return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::export_outputs(const std::vector<std::string> &args) +bool simple_wallet::export_outputs(const std::vector<std::string> &args_) { if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return true; } + auto args = args_; + + bool all = false; + if (args.size() >= 2 && args[0] == "all") + { + all = true; + args.erase(args.begin()); + } + if (args.size() != 1) { PRINT_USAGE(USAGE_EXPORT_OUTPUTS); @@ -9216,7 +9254,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args) try { - std::string data = m_wallet->export_outputs_to_str(); + std::string data = m_wallet->export_outputs_to_str(all); bool r = epee::file_io_utils::save_string_to_file(filename, data); if (!r) { @@ -9343,7 +9381,7 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args) for (const auto &d: pd.m_dests) { if (!dests.empty()) dests += ", "; - dests += get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr) + ": " + print_money(d.amount); + dests += d.address(m_wallet->nettype(), pd.m_payment_id) + ": " + print_money(d.amount); } std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 4bf7fa334..2de390666 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -109,6 +109,7 @@ namespace cryptonote bool spendkey(const std::vector<std::string> &args = std::vector<std::string>()); bool seed(const std::vector<std::string> &args = std::vector<std::string>()); bool encrypted_seed(const std::vector<std::string> &args = std::vector<std::string>()); + bool restore_height(const std::vector<std::string> &args = std::vector<std::string>()); /*! * \brief Sets seed language. diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index f4ad8b1f6..ad7029a3c 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -181,7 +181,7 @@ void TransactionHistoryImpl::refresh() // single output transaction might contain multiple transfers for (const auto &d: pd.m_dests) { - ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->nettype(), d.is_subaddress, d.addr)}); + ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)}); } m_history.push_back(ti); } diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp index 7381005c1..96d4ef3ce 100644 --- a/src/wallet/message_store.cpp +++ b/src/wallet/message_store.cpp @@ -397,10 +397,9 @@ void message_store::stop_auto_config() for (uint32_t i = 0; i < m_num_authorized_signers; ++i) { authorized_signer &m = m_signers[i]; - if (!m.me && !m.auto_config_transport_address.empty()) + if (!m.auto_config_transport_address.empty()) { - // Try to delete those "unused API" addresses in PyBitmessage, especially since - // it seems it's not possible to delete them interactively, only to "disable" them + // Try to delete the chan that was used for auto-config m_transporter.delete_transport_address(m.auto_config_transport_address); } m.auto_config_token.clear(); @@ -429,14 +428,7 @@ void message_store::setup_signer_for_auto_config(uint32_t index, const std::stri m.auto_config_token = token; crypto::hash_to_scalar(token.data(), token.size(), m.auto_config_secret_key); crypto::secret_key_to_public_key(m.auto_config_secret_key, m.auto_config_public_key); - if (receiving) - { - m.auto_config_transport_address = m_transporter.derive_and_receive_transport_address(m.auto_config_token); - } - else - { - m.auto_config_transport_address = m_transporter.derive_transport_address(m.auto_config_token); - } + m.auto_config_transport_address = m_transporter.derive_transport_address(m.auto_config_token); } bool message_store::get_signer_index_by_monero_address(const cryptonote::account_public_address &monero_address, uint32_t &index) const diff --git a/src/wallet/message_transporter.cpp b/src/wallet/message_transporter.cpp index 2f8188a3c..cf9b45b37 100644 --- a/src/wallet/message_transporter.cpp +++ b/src/wallet/message_transporter.cpp @@ -192,47 +192,47 @@ bool message_transporter::delete_message(const std::string &transport_id) return true; } -// Deterministically derive a transport / Bitmessage address from 'seed' (the 10-hex-digits -// auto-config token will be used), but do not set it up for receiving in PyBitmessage as -// well, because it's possible the address will only ever be used to SEND auto-config data +// Deterministically derive a new transport address from 'seed' (the 10-hex-digits auto-config +// token will be used) and set it up for sending and receiving +// In a first attempt a normal Bitmessage address was used here, but it turned out the +// key exchange necessary to put it into service could take a long time or even did not +// work out at all sometimes. Also there were problems when deleting those temporary +// addresses again after auto-config. Now a chan is used which avoids all these drawbacks +// quite nicely. std::string message_transporter::derive_transport_address(const std::string &seed) { + // Don't use the seed directly as chan name; that would be too dangerous, e.g. in the + // case of a PyBitmessage instance used by multiple unrelated people + // If an auto-config token gets hashed in another context use different salt instead of "chan" + std::string salted_seed = seed + "chan"; + std::string chan_name = epee::string_tools::pod_to_hex(crypto::cn_fast_hash(salted_seed.data(), salted_seed.size())); + + // Calculate the Bitmessage address that the chan will get for being able to + // use 'joinChain', as 'createChan' will fail and not tell the address if the chan + // already exists (which it can if all auto-config participants share a PyBitmessage + // instance). 'joinChan' will also fail in that case, but that won't matter. std::string request; start_xml_rpc_cmd(request, "getDeterministicAddress"); - add_xml_rpc_base64_param(request, seed); + add_xml_rpc_base64_param(request, chan_name); add_xml_rpc_integer_param(request, 4); // addressVersionNumber add_xml_rpc_integer_param(request, 1); // streamNumber end_xml_rpc_cmd(request); std::string answer; post_request(request, answer); std::string address = get_str_between_tags(answer, "<string>", "</string>"); - return address; -} - -// Derive a transport address and configure it for receiving in PyBitmessage, typically -// for receiving auto-config messages by the wallet of the auto-config organizer -std::string message_transporter::derive_and_receive_transport_address(const std::string &seed) -{ - // We need to call both "get_deterministic_address" AND "createDeterministicAddresses" - // because we won't get back the address from the latter call if it exists already - std::string address = derive_transport_address(seed); - std::string request; - start_xml_rpc_cmd(request, "createDeterministicAddresses"); - add_xml_rpc_base64_param(request, seed); - add_xml_rpc_integer_param(request, 1); // numberOfAddresses - add_xml_rpc_integer_param(request, 4); // addressVersionNumber + start_xml_rpc_cmd(request, "joinChan"); + add_xml_rpc_base64_param(request, chan_name); + add_xml_rpc_string_param(request, address); end_xml_rpc_cmd(request); - std::string answer; post_request(request, answer); - return address; } bool message_transporter::delete_transport_address(const std::string &transport_address) { std::string request; - start_xml_rpc_cmd(request, "deleteAddress"); + start_xml_rpc_cmd(request, "leaveChan"); add_xml_rpc_string_param(request, transport_address); end_xml_rpc_cmd(request); std::string answer; @@ -270,7 +270,22 @@ bool message_transporter::post_request(const std::string &request, std::string & std::string string_value = get_str_between_tags(answer, "<string>", "</string>"); if ((string_value.find("API Error") == 0) || (string_value.find("RPC ") == 0)) { - THROW_WALLET_EXCEPTION(tools::error::bitmessage_api_error, string_value); + if ((string_value.find("API Error 0021") == 0) && (request.find("joinChan") != std::string::npos)) + { + // Error that occurs if one tries to join an already joined chan, which can happen + // if several auto-config participants share one PyBitmessage instance: As a little + // hack simply ignore the error. (A clean solution would be to check for the chan + // with 'listAddresses2', but parsing the returned array is much more complicated.) + } + else if ((string_value.find("API Error 0013") == 0) && (request.find("leaveChan") != std::string::npos)) + { + // Error that occurs if one tries to leave an already left / deleted chan, which can happen + // if several auto-config participants share one PyBitmessage instance: Also ignore. + } + else + { + THROW_WALLET_EXCEPTION(tools::error::bitmessage_api_error, string_value); + } } return r; diff --git a/src/wallet/message_transporter.h b/src/wallet/message_transporter.h index 736fc9b63..28c099d87 100644 --- a/src/wallet/message_transporter.h +++ b/src/wallet/message_transporter.h @@ -91,7 +91,6 @@ public: bool delete_message(const std::string &transport_id); void stop() { m_run.store(false, std::memory_order_relaxed); } std::string derive_transport_address(const std::string &seed); - std::string derive_and_receive_transport_address(const std::string &seed); bool delete_transport_address(const std::string &transport_address); private: diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 23c375924..9782e4b1e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -7450,7 +7450,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_ order.resize(light_wallet_requested_outputs_count); for (size_t n = 0; n < order.size(); ++n) order[n] = n; - std::shuffle(order.begin(), order.end(), std::default_random_engine(crypto::rand<unsigned>())); + std::shuffle(order.begin(), order.end(), crypto::random_device{}); LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs with amounts " << print_money(td.is_rct() ? 0 : td.amount())); @@ -8025,7 +8025,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> order.resize(requested_outputs_count); for (size_t n = 0; n < order.size(); ++n) order[n] = n; - std::shuffle(order.begin(), order.end(), std::default_random_engine(crypto::rand<unsigned>())); + std::shuffle(order.begin(), order.end(), crypto::random_device{}); LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs of size " << print_money(td.is_rct() ? 0 : td.amount())); for (size_t o = 0; o < requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o) @@ -11607,10 +11607,10 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle return tx_pub_key; } -bool wallet2::export_key_images(const std::string &filename) const +bool wallet2::export_key_images(const std::string &filename, bool all) const { PERF_TIMER(export_key_images); - std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(); + std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(all); std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC)); const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; const uint32_t offset = ski.first; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index a6d042297..c2e34dd76 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1175,7 +1175,7 @@ private: void import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments); std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const; void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc); - bool export_key_images(const std::string &filename) const; + bool export_key_images(const std::string &filename, bool all = false) const; std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const; uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true); uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent); diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp index a4bb342ca..9da9d109c 100644 --- a/src/wallet/wallet_args.cpp +++ b/src/wallet/wallet_args.cpp @@ -206,7 +206,10 @@ namespace wallet_args if (!command_line::is_arg_defaulted(vm, arg_log_level)) MINFO("Setting log level = " << command_line::get_arg(vm, arg_log_level)); else - MINFO("Setting log levels = " << getenv("MONERO_LOGS")); + { + const char *logs = getenv("MONERO_LOGS"); + MINFO("Setting log levels = " << (logs ? logs : "<default>")); + } MINFO(wallet_args::tr("Logging to: ") << log_path); Print(print) << boost::format(wallet_args::tr("Logging to %s")) % log_path; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 844ecf90c..c64b662f3 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -352,7 +352,7 @@ namespace tools entry.destinations.push_back(wallet_rpc::transfer_destination()); wallet_rpc::transfer_destination &td = entry.destinations.back(); td.amount = d.amount; - td.address = d.original.empty() ? get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr) : d.original; + td.address = d.address(m_wallet->nettype(), pd.m_payment_id); } entry.type = "out"; @@ -382,7 +382,7 @@ namespace tools entry.destinations.push_back(wallet_rpc::transfer_destination()); wallet_rpc::transfer_destination &td = entry.destinations.back(); td.amount = d.amount; - td.address = d.original.empty() ? get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr) : d.original; + td.address = d.address(m_wallet->nettype(), pd.m_payment_id); } entry.type = is_failed ? "failed" : "pending"; |