From 113cdc10a25870d68fbadbe06a964b260a1da6ca Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 2 Apr 2016 11:17:49 +0100 Subject: [PATCH 01/14] core: keep the acc loop for the genesis block For unknown reasons, it was generated with a block reward consisting of a single large dusty output. --- src/cryptonote_core/cryptonote_format_utils.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 94f3d51d..3b9dcc8a 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -145,7 +145,19 @@ namespace cryptonote [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); - CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded"); + if (height == 0) + { + // the genesis block was not decomposed, for unknown reasons + while (max_outs < out_amounts.size()) + { + out_amounts[out_amounts.size() - 2] += out_amounts.back(); + out_amounts.resize(out_amounts.size() - 1); + } + } + else + { + CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded"); + } uint64_t summary_amounts = 0; for (size_t no = 0; no < out_amounts.size(); no++) From 48d0747d005c80fde3837fc4bcdb3eff26907d74 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 2 Apr 2016 13:06:39 +0100 Subject: [PATCH 02/14] wallet: better output selection for transfer/transfer_new This now requests the set of outputs that can be mixed first, to avoid trying non dust but unmixable outputs, which we know will fail. --- src/simplewallet/simplewallet.cpp | 4 +- src/wallet/wallet2.cpp | 89 ++++++++----------- src/wallet/wallet2.h | 30 +++---- src/wallet/wallet_rpc_server.cpp | 6 +- src/wallet/wallet_rpc_server_commands_defs.h | 4 + .../transactions_flow_test.cpp | 2 +- 6 files changed, 61 insertions(+), 74 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index aa571755..f4293760 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2133,9 +2133,9 @@ bool simple_wallet::transfer_main(bool new_algorithm, const std::vector ptx_vector; if (new_algorithm) - ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); + ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trusted_daemon); else - ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); + ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trusted_daemon); // if more than one tx necessary, prompt user to confirm if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a9a65535..547336cb 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1749,47 +1749,12 @@ namespace // returns: // direct return: amount of money found // modified reference: selected_transfers, a list of iterators/indices of input sources -uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, bool hf2_rules, std::list& selected_transfers) +uint64_t wallet2::select_transfers(uint64_t needed_money, std::vector unused_transfers_indices, std::list& selected_transfers, bool trusted_daemon) { - std::vector unused_transfers_indices; - std::vector unused_dust_indices; - - // aggregate sources available for transfers - // if dust needed, take dust from only one source (so require source has at least dust amount) - for (size_t i = 0; i < m_transfers.size(); ++i) - { - const transfer_details& td = m_transfers[i]; - if (!td.m_spent && is_transfer_unlocked(td)) - { - if (dust < td.amount() && is_valid_decomposed_amount(td.amount())) - unused_transfers_indices.push_back(i); - else - { - // for hf2 rules, we disregard dust, which will be spendable only - // via sweep_dust. If we're asked to add dust, though, we still - // consider them, as this will be a mixin 0 tx (and thus we may - // end up with a tx with one mixable output and N dusty ones). - // This should be made better at some point... - if (!hf2_rules || add_dust) - unused_dust_indices.push_back(i); - } - } - } - - bool select_one_dust = add_dust && !unused_dust_indices.empty(); uint64_t found_money = 0; - while (found_money < needed_money && (!unused_transfers_indices.empty() || !unused_dust_indices.empty())) + while (found_money < needed_money && !unused_transfers_indices.empty()) { - size_t idx; - if (select_one_dust) - { - idx = pop_random_value(unused_dust_indices); - select_one_dust = false; - } - else - { - idx = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices); - } + size_t idx = pop_random_value(unused_transfers_indices); transfer_container::iterator it = m_transfers.begin() + idx; selected_transfers.push_back(it); @@ -1811,18 +1776,18 @@ void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, const std::v } //---------------------------------------------------------------------------------------------------- -void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, - uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx& ptx) +void wallet2::transfer(const std::vector& dsts, const size_t fake_outs_count, const std::vector &unused_transfers_indices, + uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon) { - transfer(dsts, fake_outputs_count, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), tx, ptx); + transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), tx, ptx, trusted_daemon); } //---------------------------------------------------------------------------------------------------- -void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, - uint64_t unlock_time, uint64_t fee, const std::vector& extra) +void wallet2::transfer(const std::vector& dsts, const size_t fake_outs_count, const std::vector &unused_transfers_indices, + uint64_t unlock_time, uint64_t fee, const std::vector& extra, bool trusted_daemon) { cryptonote::transaction tx; pending_tx ptx; - transfer(dsts, fake_outputs_count, unlock_time, fee, extra, tx, ptx); + transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, tx, ptx, trusted_daemon); } namespace { @@ -2019,8 +1984,9 @@ void wallet2::commit_tx(std::vector& ptx_vector) // // this function will make multiple calls to wallet2::transfer if multiple // transactions will be required -std::vector wallet2::create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra) +std::vector wallet2::create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra, bool trusted_daemon) { + const std::vector unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, trusted_daemon); // failsafe split attempt counter size_t attempt_count = 0; @@ -2050,7 +2016,7 @@ std::vector wallet2::create_transactions(std::vector wallet2::create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra) +std::vector wallet2::create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra, bool trusted_daemon) { std::vector unused_transfers_indices; std::vector unused_dust_indices; @@ -2703,9 +2669,8 @@ std::vector wallet2::get_unspent_amounts_vector() return vector; } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::select_available_unmixable_outputs(bool trusted_daemon) +std::vector wallet2::select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon) { - // request all outputs with at least 3 instances, so we can use mixin 2 with epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); epee::json_rpc::response resp_t = AUTO_VAL_INIT(resp_t); m_daemon_rpc_mutex.lock(); @@ -2714,7 +2679,7 @@ std::vector wallet2::select_available_unmixable_outputs(bool trusted_dae req_t.method = "get_output_histogram"; if (trusted_daemon) req_t.params.amounts = get_unspent_amounts_vector(); - req_t.params.min_count = 3; + req_t.params.min_count = count; req_t.params.max_count = 0; bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); @@ -2728,14 +2693,32 @@ std::vector wallet2::select_available_unmixable_outputs(bool trusted_dae mixable.insert(i.amount); } - return select_available_outputs([mixable](const transfer_details &td) { + return select_available_outputs([mixable, atleast](const transfer_details &td) { const uint64_t amount = td.amount(); - if (mixable.find(amount) == mixable.end()) - return true; + if (atleast) { + if (mixable.find(amount) != mixable.end()) + return true; + } + else { + if (mixable.find(amount) == mixable.end()) + return true; + } return false; }); } //---------------------------------------------------------------------------------------------------- +std::vector wallet2::select_available_unmixable_outputs(bool trusted_daemon) +{ + // request all outputs with less than 3 instances + return select_available_outputs_from_histogram(3, false, trusted_daemon); +} +//---------------------------------------------------------------------------------------------------- +std::vector wallet2::select_available_mixable_outputs(bool trusted_daemon) +{ + // request all outputs with at least 3 instances, so we can use mixin 2 with + return select_available_outputs_from_histogram(3, true, trusted_daemon); +} +//---------------------------------------------------------------------------------------------------- std::vector wallet2::create_unmixable_sweep_transactions(bool trusted_daemon) { // From hard fork 1, we don't consider small amounts to be dust anymore diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index b6466d3f..179d1553 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -274,11 +274,11 @@ namespace tools uint64_t unlocked_balance() const; uint64_t unlocked_dust_balance(const tx_dust_policy &dust_policy) const; template - void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy); + void transfer(const std::vector& dsts, const size_t fake_outputs_count, const std::vector &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, bool trusted_daemon); template - void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx& ptx); - void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra); - void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx& ptx); + void transfer(const std::vector& dsts, const size_t fake_outputs_count, const std::vector &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon); + void transfer(const std::vector& dsts, const size_t fake_outputs_count, const std::vector &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector& extra, bool trusted_daemon); + void transfer(const std::vector& dsts, const size_t fake_outputs_count, const std::vector &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon); template void transfer_from(const std::vector &outs, size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx); template @@ -287,8 +287,8 @@ namespace tools void commit_tx(pending_tx& ptx_vector); void commit_tx(std::vector& ptx_vector); - std::vector create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector extra); - std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra); + std::vector create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector extra, bool trusted_daemon); + std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra, bool trusted_daemon); std::vector create_unmixable_sweep_transactions(bool trusted_daemon); bool check_connection(); void get_transfers(wallet2::transfer_container& incoming_transfers) const; @@ -389,7 +389,7 @@ namespace tools void pull_blocks(uint64_t start_height, uint64_t& blocks_start_height, const std::list &short_chain_history, std::list &blocks); void pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list &short_chain_history, const std::list &prev_blocks, std::list &blocks, bool &error); void process_blocks(uint64_t start_height, const std::list &blocks, uint64_t& blocks_added); - uint64_t select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, bool hf2_rules, std::list& selected_transfers); + uint64_t select_transfers(uint64_t needed_money, std::vector unused_transfers_indices, std::list& selected_transfers, bool trusted_daemon); bool prepare_file_names(const std::string& file_path); void process_unconfirmed(const cryptonote::transaction& tx, uint64_t height); void process_outgoing(const cryptonote::transaction& tx, uint64_t height, uint64_t spent, uint64_t received); @@ -403,8 +403,10 @@ namespace tools uint64_t get_upper_tranaction_size_limit(); void check_pending_txes(); std::vector get_unspent_amounts_vector(); + std::vector select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon); std::vector select_available_outputs(const std::function &f); std::vector select_available_unmixable_outputs(bool trusted_daemon); + std::vector select_available_mixable_outputs(bool trusted_daemon); cryptonote::account_base m_account; std::string m_daemon_address; @@ -562,17 +564,17 @@ namespace tools } //---------------------------------------------------------------------------------------------------- template - void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, - uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy) + void wallet2::transfer(const std::vector& dsts, const size_t fake_outs_count, const std::vector &unused_transfers_indices, + uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, bool trusted_daemon) { pending_tx ptx; cryptonote::transaction tx; - transfer(dsts, fake_outputs_count, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx, ptx); + transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx, ptx, trusted_daemon); } template - void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, - uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx) + void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, const std::vector &unused_transfers_indices, + uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx, bool trusted_daemon) { using namespace cryptonote; // throw if attempting a transaction with no destinations @@ -593,9 +595,7 @@ namespace tools // randomly select inputs for transaction // throw if requested send amount is greater than amount available to send std::list selected_transfers; - bool hf2_rules = use_fork_rules(2); // first fork has version 2 - const bool add_dust = (0 == fake_outputs_count) && hf2_rules; - uint64_t found_money = select_transfers(needed_money, add_dust, dust_policy.dust_threshold, hf2_rules, selected_transfers); + uint64_t found_money = select_transfers(needed_money, unused_transfers_indices, selected_transfers, trusted_daemon); THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee); typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index d7d99c2a..6897c3d4 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -232,7 +232,7 @@ namespace tools LOG_PRINT_L1("Requested mixin " << req.mixin << " too low for hard fork 2, using 2"); mixin = 2; } - std::vector ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra); + std::vector ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon); // reject proposed transactions if there are more than one. see on_transfer_split below. if (ptx_vector.size() != 1) @@ -299,9 +299,9 @@ namespace tools } std::vector ptx_vector; if (req.new_algorithm) - ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.fee, extra); + ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon); else - ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra); + ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon); m_wallet.commit_tx(ptx_vector); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 2c4e2640..2d90bf62 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -115,6 +115,7 @@ namespace wallet_rpc uint64_t unlock_time; std::string payment_id; bool get_tx_key; + bool trusted_daemon; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(destinations) @@ -123,6 +124,7 @@ namespace wallet_rpc KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) KV_SERIALIZE(get_tx_key) + KV_SERIALIZE(trusted_daemon) END_KV_SERIALIZE_MAP() }; @@ -149,6 +151,7 @@ namespace wallet_rpc std::string payment_id; bool new_algorithm; bool get_tx_keys; + bool trusted_daemon; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(destinations) @@ -158,6 +161,7 @@ namespace wallet_rpc KV_SERIALIZE(payment_id) KV_SERIALIZE(new_algorithm) KV_SERIALIZE(get_tx_keys) + KV_SERIALIZE(trusted_daemon) END_KV_SERIALIZE_MAP() }; diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 3c3cf3a9..159ccfd8 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -85,7 +85,7 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor, try { tools::wallet2::pending_tx ptx; - w1.transfer(dsts, mix_in_factor, 0, TEST_FEE, std::vector(), tools::detail::null_split_strategy, tools::tx_dust_policy(TEST_DUST_THRESHOLD), tx, ptx); + w1.transfer(dsts, mix_in_factor, 0, TEST_FEE, std::vector(), tools::detail::null_split_strategy, tools::tx_dust_policy(TEST_DUST_THRESHOLD), tx, ptx, true); w1.commit_tx(ptx); return true; } From 087373eccff1d651165baeae6ac1b0049faff53f Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 2 Apr 2016 14:20:51 +0100 Subject: [PATCH 03/14] Fix potential race with parallel processing of txes/signatures/blocks --- src/cryptonote_core/blockchain.cpp | 1 + src/wallet/wallet2.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 34810d98..dd4e9d14 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2159,6 +2159,7 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context if(ioservice_active) \ { \ work.reset(); \ + while (!ioservice.stopped()) ioservice.poll(); \ threadpool.join_all(); \ ioservice.stop(); \ ioservice_active = false; \ diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a9a65535..34bbd9fd 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -73,6 +73,7 @@ using namespace cryptonote; #define KILL_IOSERVICE() \ do { \ work.reset(); \ + while (!ioservice.stopped()) ioservice.poll(); \ threadpool.join_all(); \ ioservice.stop(); \ } while(0) From 1a58d202b2334617e3b877c9471cbbd4ca03a508 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 2 Apr 2016 15:22:59 +0100 Subject: [PATCH 04/14] simplewallet: optional address in --generate-from-json When present, it can be used to validate the keys, as well as deduce the spend key, if it is absent (watch wallet). --- src/simplewallet/simplewallet.cpp | 71 ++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index aa571755..6c0e7425 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -829,6 +829,8 @@ static bool get_password(const boost::program_options::variables_map& vm, bool a //---------------------------------------------------------------------------------------------------- bool simple_wallet::generate_from_json(const boost::program_options::variables_map& vm, std::string &wallet_file, std::string &password) { + bool testnet = command_line::get_arg(vm, arg_testnet); + std::string buf; bool r = epee::file_io_utils::load_file_to_string(m_generate_from_json, buf); if (!r) { @@ -868,6 +870,11 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m return false; } viewkey = *reinterpret_cast(viewkey_data.data()); + crypto::public_key pkey; + if (!crypto::secret_key_to_public_key(viewkey, pkey)) { + fail_msg_writer() << tr("failed to verify view key secret key"); + return false; + } } GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, spendkey, std::string, String, false); @@ -881,6 +888,11 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m return false; } spendkey = *reinterpret_cast(spendkey_data.data()); + crypto::public_key pkey; + if (!crypto::secret_key_to_public_key(spendkey, pkey)) { + fail_msg_writer() << tr("failed to verify spend key secret key"); + return false; + } } GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, seed, std::string, String, false); @@ -896,6 +908,8 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m m_restore_deterministic_wallet = true; } + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, address, std::string, String, false); + // compatibility checks if (!field_seed_found && !field_viewkey_found) { @@ -908,6 +922,44 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m return false; } + // if an address was given, we check keys against it, and deduce the spend + // public key if it was not given + if (field_address_found) + { + cryptonote::account_public_address address; + bool has_payment_id; + crypto::hash8 new_payment_id; + if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, field_address)) + { + fail_msg_writer() << tr("invalid address"); + return false; + } + if (field_viewkey_found) + { + crypto::public_key pkey; + if (!crypto::secret_key_to_public_key(viewkey, pkey)) { + fail_msg_writer() << tr("failed to verify view key secret key"); + return false; + } + if (address.m_view_public_key != pkey) { + fail_msg_writer() << tr("view key does not match standard address"); + return false; + } + } + if (field_spendkey_found) + { + crypto::public_key pkey; + if (!crypto::secret_key_to_public_key(spendkey, pkey)) { + fail_msg_writer() << tr("failed to verify spend key secret key"); + return false; + } + if (address.m_spend_public_key != pkey) { + fail_msg_writer() << tr("spend key does not match standard address"); + return false; + } + } + } + m_wallet_file = field_filename; bool was_deprecated_wallet = m_restore_deterministic_wallet && ((old_language == crypto::ElectrumWords::old_language_name) || @@ -917,7 +969,6 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m return false; } - bool testnet = command_line::get_arg(vm, arg_testnet); m_wallet.reset(new tools::wallet2(testnet)); m_wallet->callback(this); @@ -934,17 +985,27 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m fail_msg_writer() << tr("failed to verify view key secret key"); return false; } - if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) { - fail_msg_writer() << tr("failed to verify spend key secret key"); - return false; - } if (field_spendkey.empty()) { + // if we have an addres but no spend key, we can deduce the spend public key + // from the address + if (field_address_found) + { + cryptonote::account_public_address address2; + bool has_payment_id; + crypto::hash8 new_payment_id; + get_account_integrated_address_from_str(address2, has_payment_id, new_payment_id, testnet, field_address); + address.m_spend_public_key = address2.m_spend_public_key; + } m_wallet->generate(m_wallet_file, password, address, viewkey); } else { + if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) { + fail_msg_writer() << tr("failed to verify spend key secret key"); + return false; + } m_wallet->generate(m_wallet_file, password, address, spendkey, viewkey); } } From 5092e45e3fbfd614743e675c216c4ab0214073bb Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 2 Apr 2016 16:02:18 +0100 Subject: [PATCH 05/14] tests: unbound API is only accessible in static builds --- tests/unit_tests/unbound.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit_tests/unbound.cpp b/tests/unit_tests/unbound.cpp index 25026ec5..666f6812 100644 --- a/tests/unit_tests/unbound.cpp +++ b/tests/unit_tests/unbound.cpp @@ -30,6 +30,8 @@ #include "gtest/gtest.h" +#ifdef STATICLIB + extern "C" int dnskey_algo_id_is_supported(int); TEST(unbound, supported_algorithms) @@ -47,3 +49,5 @@ TEST(unbound, supported_algorithms) ASSERT_TRUE(dnskey_algo_id_is_supported(13)); } +#endif + From 17cac419688a4418c5c38bf87fffbb52d60855a0 Mon Sep 17 00:00:00 2001 From: Javier Smooth Date: Sat, 2 Apr 2016 22:00:55 +0100 Subject: [PATCH 06/14] tests: fix build with older GCC --- tests/core_tests/chaingen.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 44170d11..652413b8 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -470,13 +470,15 @@ inline bool replay_events_through_core(cryptonote::core& cr, const std::vector +template struct get_test_options { - const std::pair hard_forks[1] = {std::make_pair((uint8_t)1, (uint64_t)0)}; + const std::pair hard_forks[1]; const cryptonote::test_options test_options = { hard_forks }; + get_test_options():hard_forks{std::make_pair((uint8_t)1, (uint64_t)0)}{} }; + //-------------------------------------------------------------------------- template inline bool do_replay_events(std::vector& events) From d817aeca80a959d02516b2355b7bdc64f45e7153 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 5 Apr 2016 13:06:29 +0100 Subject: [PATCH 07/14] tx_pool: ensure no txes that fail check_inputs get in the block template --- src/cryptonote_core/tx_pool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index a0682616..3d5ab86e 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -512,7 +512,7 @@ namespace cryptonote { if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_height()) return false; - if(m_blockchain.get_block_id_by_height(txd.max_used_block_height) != txd.max_used_block_id) + if(true) { //if we already failed on this height and id, skip actual ring signature check if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) From 5c9dd23b1cc8d61beceaf51588bbf08936d25711 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 5 Apr 2016 19:13:24 +0100 Subject: [PATCH 08/14] rpc: add a do_not_relay boolean to tx submission Just to make it easier --- src/rpc/core_rpc_server.cpp | 2 +- src/rpc/core_rpc_server_commands_defs.h | 2 ++ src/wallet/wallet2.cpp | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 165a24c2..988ee554 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -383,7 +383,7 @@ namespace cryptonote return true; } - if(!tvc.m_should_be_relayed) + if(!tvc.m_should_be_relayed || req.do_not_relay) { LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed"); res.reason = "Not relayed"; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 91f5e2c9..4ef3fc17 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -221,12 +221,14 @@ namespace cryptonote struct request { std::string tx_as_hex; + bool do_not_relay; request() {} explicit request(const transaction &); BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_as_hex) + KV_SERIALIZE(do_not_relay) END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a9a65535..cdd47252 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1974,6 +1974,7 @@ void wallet2::commit_tx(pending_tx& ptx) COMMAND_RPC_SEND_RAW_TX::request req; req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)); + req.do_not_relay = false; COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp; m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000); From d662ab5cec0b72780d0c24a2ba299237780d2369 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 5 Apr 2016 19:26:37 +0100 Subject: [PATCH 09/14] rpc: print human readable time since received when printing pool --- src/daemon/rpc_command_executor.cpp | 44 +++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 933c93ed..630f2098 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -70,6 +70,23 @@ namespace { << "difficulty: " << boost::lexical_cast(header.difficulty) << std::endl << "reward: " << boost::lexical_cast(header.reward); } + + std::string get_human_time_ago(time_t t, time_t now) + { + if (t == now) + return "now"; + time_t dt = t > now ? t - now : now - t; + std::string s; + if (dt < 90) + s = boost::lexical_cast(dt) + " seconds"; + else if (dt < 90 * 60) + s = boost::lexical_cast(dt/60) + " minutes"; + else if (dt < 36 * 3600) + s = boost::lexical_cast(dt/3600) + " hours"; + else + s = boost::lexical_cast(dt/(3600*24)) + " days"; + return s + " " + (t > now ? "in the future" : "ago"); + } } t_rpc_command_executor::t_rpc_command_executor( @@ -669,6 +686,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() { } if (! res.transactions.empty()) { + const time_t now = time(NULL); tools::msg_writer() << "Transactions: "; for (auto & tx_info : res.transactions) { @@ -676,7 +694,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() { << tx_info.tx_json << std::endl << "blob_size: " << tx_info.blob_size << std::endl << "fee: " << cryptonote::print_money(tx_info.fee) << std::endl - << "receive_time: " << tx_info.receive_time << std::endl + << "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl << "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl << "max_used_block_height: " << tx_info.max_used_block_height << std::endl << "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl @@ -747,17 +765,21 @@ bool t_rpc_command_executor::print_transaction_pool_short() { { tools::msg_writer() << "Pool is empty" << std::endl; } - for (auto & tx_info : res.transactions) + else { - tools::msg_writer() << "id: " << tx_info.id_hash << std::endl - << "blob_size: " << tx_info.blob_size << std::endl - << "fee: " << cryptonote::print_money(tx_info.fee) << std::endl - << "receive_time: " << tx_info.receive_time << std::endl - << "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl - << "max_used_block_height: " << tx_info.max_used_block_height << std::endl - << "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl - << "last_failed_height: " << tx_info.last_failed_height << std::endl - << "last_failed_id: " << tx_info.last_failed_id_hash << std::endl; + const time_t now = time(NULL); + for (auto & tx_info : res.transactions) + { + tools::msg_writer() << "id: " << tx_info.id_hash << std::endl + << "blob_size: " << tx_info.blob_size << std::endl + << "fee: " << cryptonote::print_money(tx_info.fee) << std::endl + << "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl + << "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl + << "max_used_block_height: " << tx_info.max_used_block_height << std::endl + << "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl + << "last_failed_height: " << tx_info.last_failed_height << std::endl + << "last_failed_id: " << tx_info.last_failed_id_hash << std::endl; + } } return true; From 4cfb4dff3e8ae213cc87b2d0234a519d2e8674b7 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 6 Apr 2016 18:56:33 +0100 Subject: [PATCH 10/14] blockchain: remove the tx validation result cache As pointed out by smooth, a transaction's validity may change over time as the blockchain changes. --- src/cryptonote_core/blockchain.cpp | 18 ------------------ src/cryptonote_core/blockchain.h | 1 - 2 files changed, 19 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 34810d98..c1923017 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2015,18 +2015,12 @@ bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t& max_used_block TIME_MEASURE_START(a); bool res = check_tx_inputs(tx, tvc, &max_used_block_height); TIME_MEASURE_FINISH(a); - crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); if(m_show_time_stats) LOG_PRINT_L0("HASH: " << "+" << " VIN/VOUT: " << tx.vin.size() << "/" << tx.vout.size() << " H: " << max_used_block_height << " chcktx: " << a + m_fake_scan_time); if (!res) return false; - // ND: Speedup: - // 1. keep a list of verified transactions, when the Blockchain tries to check a tx again, - // verify against list and skip if already verified to be correct. - m_check_tx_inputs_table.emplace(tx_prefix_hash, std::make_pair(res, max_used_block_height)); - CHECK_AND_ASSERT_MES(max_used_block_height < m_db->height(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db->height()); max_used_block_id = m_db->get_block_hash_from_height(max_used_block_height); return true; @@ -2076,16 +2070,6 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); - auto its = m_check_tx_inputs_table.find(tx_prefix_hash); - if (its != m_check_tx_inputs_table.end()) - { - if (!its->second.first) - return false; - if (pmax_used_block_height) - *pmax_used_block_height = its->second.second; - return true; - } - // from hard fork 2, we require mixin at least 2 unless one output cannot mix with 2 others // if one output cannot mix with 2 others, we accept at most 1 output that can mix if (m_hardfork->get_current_version() >= 2) @@ -2967,7 +2951,6 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) TIME_MEASURE_FINISH(t1); m_blocks_longhash_table.clear(); m_scan_table.clear(); - m_check_tx_inputs_table.clear(); m_blocks_txs_check.clear(); m_check_txin_table.clear(); @@ -3115,7 +3098,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list>> m_scan_table; - std::unordered_map> m_check_tx_inputs_table; std::unordered_map m_blocks_longhash_table; std::unordered_map> m_check_txin_table; From 7385c036bdd2e9254be99024ddcec639b668f68a Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 6 Apr 2016 19:59:34 +0100 Subject: [PATCH 11/14] util: add a function to set umask to 077 Useful to ensure files are written without group/other read rights. --- src/common/util.cpp | 9 +++++++++ src/common/util.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/common/util.cpp b/src/common/util.cpp index 6f75e5ba..2337f576 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -413,4 +413,13 @@ std::string get_nix_version_display_string() } return false; } + void set_strict_default_file_permissions(bool strict) + { +#if defined(__MINGW32__) || defined(__MINGW__) + // no clue about the odd one out +#else + mode_t mode = strict ? 077 : 0; + umask(mode); +#endif + } } diff --git a/src/common/util.h b/src/common/util.h index 7554b1df..ed1c16cb 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -158,4 +158,6 @@ namespace tools /*! \brief where the installed handler is stored */ static std::function m_handler; }; + + void set_strict_default_file_permissions(bool strict); } From ed61a2ccc1bc38a8e58ecef17e5831d1e406cd0b Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 6 Apr 2016 20:00:25 +0100 Subject: [PATCH 12/14] simplewallet: set strict umask at start --- src/simplewallet/simplewallet.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index aa571755..3d1410f4 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2807,6 +2807,7 @@ int main(int argc, char* argv[]) std::string lang = i18n_get_language(); tools::sanitize_locale(); + tools::set_strict_default_file_permissions(true); string_tools::set_module_name_and_folder(argv[0]); From f17b2f42b28844657624e8ea41172b34f17fb2e3 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 3 Apr 2016 12:51:28 +0100 Subject: [PATCH 13/14] rpc: add pool/blockchain and block height results to gettransactions --- src/daemon/rpc_command_executor.cpp | 16 ++++++++++--- src/rpc/core_rpc_server.cpp | 32 +++++++++++++++++++++---- src/rpc/core_rpc_server_commands_defs.h | 29 +++++++++++++++++++--- src/simplewallet/simplewallet.cpp | 9 +++++-- 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 933c93ed..ced24330 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -575,16 +575,26 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { } } - if (1 == res.txs_as_hex.size()) + if (1 == res.txs.size() || 1 == res.txs_as_hex.size()) { + if (1 == res.txs.size()) + { + // only available for new style answers + if (res.txs.front().in_pool) + tools::success_msg_writer() << "Found in pool"; + else + tools::success_msg_writer() << "Found in blockchain at height " << res.txs.front().block_height; + } + // first as hex - tools::success_msg_writer() << res.txs_as_hex.front(); + const std::string &as_hex = (1 == res.txs.size()) ? res.txs.front().as_hex : res.txs_as_hex.front(); + tools::success_msg_writer() << as_hex; // then as json crypto::hash tx_hash, tx_prefix_hash; cryptonote::transaction tx; cryptonote::blobdata blob; - if (!string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), blob)) + if (!string_tools::parse_hexstr_to_binbuff(as_hex, blob)) { tools::fail_msg_writer() << "Failed to parse tx"; } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 165a24c2..f3745e62 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -240,6 +240,7 @@ namespace cryptonote // try the pool for any missing txes size_t found_in_pool = 0; + std::unordered_set pool_tx_hashes; if (!missed_txs.empty()) { std::list pool_txs; @@ -248,9 +249,11 @@ namespace cryptonote { for (std::list::const_iterator i = pool_txs.begin(); i != pool_txs.end(); ++i) { - std::list::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), get_transaction_hash(*i)); + crypto::hash tx_hash = get_transaction_hash(*i); + std::list::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), tx_hash); if (mi != missed_txs.end()) { + pool_tx_hashes.insert(tx_hash); missed_txs.erase(mi); txs.push_back(*i); ++found_in_pool; @@ -260,12 +263,33 @@ namespace cryptonote LOG_PRINT_L2("Found " << found_in_pool << "/" << vh.size() << " transactions in the pool"); } + std::list::const_iterator txhi = req.txs_hashes.begin(); + std::vector::const_iterator vhi = vh.begin(); BOOST_FOREACH(auto& tx, txs) { + res.txs.push_back(COMMAND_RPC_GET_TRANSACTIONS::entry()); + COMMAND_RPC_GET_TRANSACTIONS::entry &e = res.txs.back(); + + crypto::hash tx_hash = *vhi++; + e.tx_hash = *txhi++; blobdata blob = t_serializable_object_to_blob(tx); - res.txs_as_hex.push_back(string_tools::buff_to_hex_nodelimer(blob)); + e.as_hex = string_tools::buff_to_hex_nodelimer(blob); if (req.decode_as_json) - res.txs_as_json.push_back(obj_to_json_str(tx)); + e.as_json = obj_to_json_str(tx); + e.in_pool = pool_tx_hashes.find(tx_hash) != pool_tx_hashes.end(); + if (e.in_pool) + { + e.block_height = std::numeric_limits::max(); + } + else + { + e.block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash); + } + + // fill up old style responses too, in case an old wallet asks + res.txs_as_hex.push_back(e.as_hex); + if (req.decode_as_json) + res.txs_as_json.push_back(e.as_json); } BOOST_FOREACH(const auto& miss_tx, missed_txs) @@ -273,7 +297,7 @@ namespace cryptonote res.missed_tx.push_back(string_tools::pod_to_hex(miss_tx)); } - LOG_PRINT_L2(res.txs_as_hex.size() << " transactions found, " << res.missed_tx.size() << " not found"); + LOG_PRINT_L2(res.txs.size() << " transactions found, " << res.missed_tx.size() << " not found"); res.status = CORE_RPC_STATUS_OK; return true; } diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 91f5e2c9..e712c27c 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -103,18 +103,41 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; + struct entry + { + std::string tx_hash; + std::string as_hex; + std::string as_json; + bool in_pool; + uint64_t block_height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(as_hex) + KV_SERIALIZE(as_json) + KV_SERIALIZE(in_pool) + KV_SERIALIZE(block_height) + END_KV_SERIALIZE_MAP() + }; struct response { - std::list txs_as_hex; //transactions blobs as hex + // older compatibility stuff + std::list txs_as_hex; //transactions blobs as hex (old compat) + std::list txs_as_json; //transactions decoded as json (old compat) + + // in both old and new std::list missed_tx; //not found transactions - std::list txs_as_json; //transactions decoded as json + + // new style + std::vector txs; std::string status; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(txs_as_hex) - KV_SERIALIZE(missed_tx) KV_SERIALIZE(txs_as_json) + KV_SERIALIZE(txs) + KV_SERIALIZE(missed_tx) KV_SERIALIZE(status) END_KV_SERIALIZE_MAP() }; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index aa571755..30c95838 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2497,13 +2497,18 @@ bool simple_wallet::check_tx_key(const std::vector &args_) COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); if (!net_utils::invoke_http_json_remote_command2(m_daemon_address + "/gettransactions", req, res, m_http_client) || - res.txs_as_hex.empty()) + (res.txs.empty() && res.txs_as_hex.empty())) { fail_msg_writer() << tr("failed to get transaction from daemon"); return true; } cryptonote::blobdata tx_data; - if (!string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data)) + bool ok; + if (!res.txs.empty()) + ok = string_tools::parse_hexstr_to_binbuff(res.txs.front().as_hex, tx_data); + else + ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data); + if (!ok) { fail_msg_writer() << tr("failed to parse transaction from daemon"); return true; From c33ffc8e9420e1f530f84d44af611cd21e954e30 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 10 Apr 2016 16:56:12 +0100 Subject: [PATCH 14/14] simplewallet: save fixes in RPC mode ^C when in RPC mode would not save the wallet while it was still refreshing after starting up. Also, save the wallet out of the signal handler. We don't want to call complex stuff in a signal handler. --- src/simplewallet/simplewallet.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index aa571755..8c445dc2 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2963,12 +2963,25 @@ int main(int argc, char* argv[]) } tools::wallet2 wal(testnet,restricted); + bool quit = false; + tools::signal_handler::install([&wal, &quit](int) { + quit = true; + wal.stop(); + }); try { LOG_PRINT_L0(sw::tr("Loading wallet...")); wal.load(wallet_file, password); wal.init(daemon_address); wal.refresh(); + // if we ^C during potentially length load/refresh, there's no server loop yet + if (quit) + { + LOG_PRINT_L0(sw::tr("Storing wallet...")); + wal.store(); + LOG_PRINT_GREEN(sw::tr("Stored ok"), LOG_LEVEL_0); + return 1; + } LOG_PRINT_GREEN(sw::tr("Loaded ok"), LOG_LEVEL_0); } catch (const std::exception& e) @@ -2979,10 +2992,8 @@ int main(int argc, char* argv[]) tools::wallet_rpc_server wrpc(wal); bool r = wrpc.init(vm); CHECK_AND_ASSERT_MES(r, 1, sw::tr("Failed to initialize wallet rpc server")); - tools::signal_handler::install([&wrpc, &wal](int) { wrpc.send_stop_signal(); - wal.store(); }); LOG_PRINT_L0(sw::tr("Starting wallet rpc server")); wrpc.run();