diff options
author | Riccardo Spagni <ric@spagni.net> | 2017-12-25 21:17:52 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2017-12-25 21:17:52 +0200 |
commit | 2b00899bb28e09f0c44813689acc0add73832215 (patch) | |
tree | 7db8c261c5b1014f5451f157f29b37f58409bc89 /src/wallet | |
parent | Merge pull request #2918 (diff) | |
parent | network_throttle: fix ineffective locking (diff) | |
download | monero-2b00899bb28e09f0c44813689acc0add73832215.tar.xz |
Merge pull request #2920
bd5cce07 network_throttle: fix ineffective locking (moneromooo-monero)
e0a61299 network_throttle: remove unused xxx static member (moneromooo-monero)
24f584d9 cryptonote_core: remove unused functions with off by one bugs (moneromooo-monero)
b1634aa3 blockchain: don't leave dangling pointers in this (moneromooo-monero)
8e60b81c cryptonote_core: fix db leak on error (moneromooo-monero)
213e326c abstract_tcp_server2: log init_server errors as fatal (moneromooo-monero)
b51dc566 use const refs in for loops for non tiny types (moneromooo-monero)
f0568ca6 net_parse_helpers: fix regex error checking (moneromooo-monero)
b49ddc76 check accessing an element past the end of a container (moneromooo-monero)
2305bf26 check return value for generate_key_derivation and derive_public_key (moneromooo-monero)
a4240d9f catch const exceptions (moneromooo-monero)
45a1c4c0 add empty container sanity checks when using front() and back() (moneromooo-monero)
56fa6ce1 tests: fix a buffer overread in a unit test (moneromooo-monero)
b4524892 rpc: guard against json parsing a non object (moneromooo-monero)
c2ed8618 easylogging++: avoid buffer underflow (moneromooo-monero)
187a6ab2 epee: trap failure to parse URI from request (moneromooo-monero)
061789b5 checkpoints: trap failure to load JSON checkpoints (moneromooo-monero)
ba2fefb9 checkpoints: pass std::string by const ref, not const value (moneromooo-monero)
38c8f4e0 mlog: terminate a string at last char, just in case (moneromooo-monero)
d753d716 fix a few leaks by throwing objects, not newed pointers to objects (moneromooo-monero)
fe568db8 p2p: use size_t for arbitrary counters instead of uint8_t (moneromooo-monero)
46d6fa35 cryptonote_protocol: sanity check chain hashes from peer (moneromooo-monero)
25584f86 cryptonote_protocol: print peer versions when unexpected (moneromooo-monero)
490a5d41 rpc: do not try to use an invalid txid in relay_tx (moneromooo-monero)
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/api/unsigned_transaction.cpp | 4 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 38 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 24 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.h | 2 |
4 files changed, 53 insertions, 15 deletions
diff --git a/src/wallet/api/unsigned_transaction.cpp b/src/wallet/api/unsigned_transaction.cpp index 4c8c5ade2..d22719189 100644 --- a/src/wallet/api/unsigned_transaction.cpp +++ b/src/wallet/api/unsigned_transaction.cpp @@ -293,6 +293,10 @@ std::vector<std::string> UnsignedTransactionImpl::recipientAddress() const // TODO: return integrated address if short payment ID exists std::vector<string> result; for (const auto &utx: m_unsigned_tx_set.txes) { + if (utx.dests.empty()) { + MERROR("empty destinations, skipped"); + continue; + } result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->testnet(), utx.dests[0].is_subaddress, utx.dests[0].addr)); } return result; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 96fcf33f2..7dabee14c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -540,6 +540,11 @@ crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx) { if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) { + if (ptx.dests.empty()) + { + MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt"); + return crypto::null_hash8; + } decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key); } } @@ -4050,6 +4055,11 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const crypto::hash8 payment_id8 = null_hash8; if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) { + if (ptx.dests.empty()) + { + MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt"); + return crypto::null_hash; + } if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key)) { memcpy(payment_id.data, payment_id8.data, 8); @@ -4274,6 +4284,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f for (size_t n = 0; n < exported_txs.txes.size(); ++n) { tools::wallet2::tx_construction_data &sd = exported_txs.txes[n]; + THROW_WALLET_EXCEPTION_IF(sd.sources.empty(), error::wallet_internal_error, "Empty sources"); LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size()); signed_txes.ptx.push_back(pending_tx()); tools::wallet2::pending_tx &ptx = signed_txes.ptx.back(); @@ -4950,6 +4961,7 @@ bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_out if (global_index == real_index) // don't re-add real one return false; auto item = std::make_tuple(global_index, tx_public_key, mask); + CHECK_AND_ASSERT_MES(!outs.empty(), false, "internal error: outs is empty"); if (std::find(outs.back().begin(), outs.back().end(), item) != outs.back().end()) // don't add duplicates return false; outs.back().push_back(item); @@ -5114,7 +5126,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> // if there are just enough outputs to mix with, use all of them. // Eventually this should become impossible. uint64_t num_outs = 0, num_recent_outs = 0; - for (auto he: resp_t.result.histogram) + for (const auto &he: resp_t.result.histogram) { if (he.amount == amount) { @@ -6223,7 +6235,8 @@ bool wallet2::light_wallet_parse_rct_str(const std::string& rct_string, const cr if (decrypt) { // Decrypt the mask crypto::key_derivation derivation; - generate_key_derivation(tx_pub_key, get_account().get_keys().m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, get_account().get_keys().m_view_secret_key, derivation); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); crypto::secret_key scalar; crypto::derivation_to_scalar(derivation, internal_output_index, scalar); sc_sub(decrypted_mask.bytes,encrypted_mask.bytes,rct::hash_to_scalar(rct::sk2rct(scalar)).bytes); @@ -6635,7 +6648,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp LOG_PRINT_L2("Made a " << ((txBlob.size() + 1023) / 1024) << " kB tx, with " << print_money(available_for_fee) << " available for fee (" << print_money(needed_fee) << " needed)"); - if (needed_fee > available_for_fee && dsts[0].amount > 0) + if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0) { // we don't have enough for the fee, but we've only partially paid the current address, // so we can take the fee from the paid amount, since we'll have to make another tx anyway @@ -7413,12 +7426,14 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de continue; crypto::public_key derived_out_key; - derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key); + bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key"); bool found = out_key->key == derived_out_key; crypto::key_derivation found_derivation = derivation; if (!found && !additional_derivations.empty()) { - derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key); + r = derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key"); found = out_key->key == derived_out_key; found_derivation = additional_derivations[n]; } @@ -7883,13 +7898,15 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + bool r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); } while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++)) { const crypto::public_key tx_pub_key = pub_key_field.pub_key; crypto::key_derivation derivation; - generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); for (size_t i = 0; i < td.m_tx.vout.size(); ++i) { @@ -8176,13 +8193,15 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag const cryptonote::account_keys& keys = m_account.get_keys(); const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(spent_tx); crypto::key_derivation derivation; - generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(spent_tx); std::vector<crypto::key_derivation> additional_derivations; for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); } size_t output_index = 0; for (const cryptonote::tx_out& out : spent_tx.vout) @@ -8904,6 +8923,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui throw std::runtime_error(oss.str()); } cryptonote::block blk_min, blk_mid, blk_max; + if (res.blocks.size() < 3) throw std::runtime_error("Not enough blocks returned from daemon"); if (!parse_and_validate_block_from_blob(res.blocks[0].block, blk_min)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_min)); if (!parse_and_validate_block_from_blob(res.blocks[1].block, blk_mid)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_mid)); if (!parse_and_validate_block_from_blob(res.blocks[2].block, blk_max)) throw std::runtime_error("failed to parse blob at height " + std::to_string(height_max)); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 935802ab7..732cefbe8 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -497,7 +497,7 @@ namespace tools return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er) + bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er) { crypto::hash8 integrated_payment_id = crypto::null_hash8; std::string extra_nonce; @@ -552,6 +552,13 @@ namespace tools } } + if (at_least_one_destination && dsts.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_ZERO_DESTINATION; + er.message = "No destinations for this transfer"; + return false; + } + if (!payment_id.empty()) { @@ -603,7 +610,7 @@ namespace tools } // validate the transfer requested and populate dsts & extra - if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er)) + if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er)) { return false; } @@ -613,6 +620,13 @@ namespace tools uint64_t mixin = m_wallet->adjust_mixin(req.mixin); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); + if (ptx_vector.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = "No transaction created"; + return false; + } + // reject proposed transactions if there are more than one. see on_transfer_split below. if (ptx_vector.size() != 1) { @@ -694,7 +708,7 @@ namespace tools } // validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types. - if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er)) + if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, true, er)) { return false; } @@ -891,7 +905,7 @@ namespace tools destination.push_back(wallet_rpc::transfer_destination()); destination.back().amount = 0; destination.back().address = req.address; - if (!validate_transfer(destination, req.payment_id, dsts, extra, er)) + if (!validate_transfer(destination, req.payment_id, dsts, extra, true, er)) { return false; } @@ -990,7 +1004,7 @@ namespace tools destination.push_back(wallet_rpc::transfer_destination()); destination.back().amount = 0; destination.back().address = req.address; - if (!validate_transfer(destination, req.payment_id, dsts, extra, er)) + if (!validate_transfer(destination, req.payment_id, dsts, extra, true, er)) { return false; } diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 79f589623..b2061fa35 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -137,7 +137,7 @@ namespace tools bool on_create_account(const wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_CREATE_ACCOUNT::response& res, epee::json_rpc::error& er); bool on_label_account(const wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::request& req, wallet_rpc::COMMAND_RPC_LABEL_ACCOUNT::response& res, epee::json_rpc::error& er); bool on_getheight(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res, epee::json_rpc::error& er); - bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er); + bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er); bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er); bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er); bool on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er); |