diff options
author | stoffu <stoffu@protonmail.ch> | 2017-10-11 10:32:06 +0900 |
---|---|---|
committer | stoffu <stoffu@protonmail.ch> | 2017-11-15 17:51:54 +0900 |
commit | b738f4b59d448eae8eb8f8f31fd589bfa9b93d46 (patch) | |
tree | 3cc6d109bdaaa11163b9ccea1e5a844e6d1cb03e /src/wallet | |
parent | Merge pull request #2816 (diff) | |
download | monero-b738f4b59d448eae8eb8f8f31fd589bfa9b93d46.tar.xz |
wallet: add sweep_single command
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/wallet2.cpp | 21 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 1 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 96 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.h | 2 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_commands_defs.h | 47 |
5 files changed, 167 insertions, 0 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 59c184b51..3b04e4e36 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -5886,6 +5886,27 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, trusted_daemon); } +std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon) +{ + std::vector<size_t> unused_transfers_indices; + std::vector<size_t> unused_dust_indices; + const bool use_rct = use_fork_rules(4, 0); + // find output with the given key image + for (size_t i = 0; i < m_transfers.size(); ++i) + { + const transfer_details& td = m_transfers[i]; + if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td)) + { + if (td.is_rct() || is_valid_decomposed_amount(td.amount())) + unused_transfers_indices.push_back(i); + else + unused_dust_indices.push_back(i); + break; + } + } + return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, trusted_daemon); +} + std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon) { uint64_t accumulated_fee, accumulated_outputs, accumulated_change; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 38898930d..6e01d4e28 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -524,6 +524,7 @@ namespace tools std::vector<pending_tx> create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon); std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, bool trusted_daemon); // pass subaddr_indices by value on purpose std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, bool trusted_daemon); + std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon); std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon); std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon); bool check_connection(uint32_t *version = NULL, uint32_t timeout = 200000); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 90acb44d8..09ed205c6 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -812,6 +812,101 @@ namespace tools } return true; } +//------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_sweep_single(const wallet_rpc::COMMAND_RPC_SWEEP_SINGLE::request& req, wallet_rpc::COMMAND_RPC_SWEEP_SINGLE::response& res, epee::json_rpc::error& er) + { + std::vector<cryptonote::tx_destination_entry> dsts; + std::vector<uint8_t> extra; + + if (!m_wallet) return not_open(er); + if (m_wallet->restricted()) + { + er.code = WALLET_RPC_ERROR_CODE_DENIED; + er.message = "Command unavailable in restricted mode."; + return false; + } + + // validate the transfer requested and populate dsts & extra + std::list<wallet_rpc::transfer_destination> destination; + 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)) + { + return false; + } + + crypto::key_image ki; + if (!epee::string_tools::hex_to_pod(req.key_image, ki)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE; + er.message = "failed to parse key image"; + return false; + } + + try + { + uint64_t mixin = adjust_mixin(req.mixin); + std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, req.priority, extra, m_trusted_daemon); + + if (ptx_vector.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "No outputs found"; + return false; + } + if (ptx_vector.size() > 1) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "Multiple transactions are created, which is not supposed to happen"; + return false; + } + if (ptx_vector[0].selected_transfers.size() > 1) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "The transaction uses multiple inputs, which is not supposed to happen"; + return false; + } + + if (!req.do_not_relay) + m_wallet->commit_tx(ptx_vector); + + // populate response with tx hashes + const wallet2::pending_tx &ptx = ptx_vector[0]; + res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)); + if (req.get_tx_key) + { + res.tx_key = epee::string_tools::pod_to_hex(ptx.tx_key); + } + if (req.get_tx_hex) + { + cryptonote::blobdata blob; + tx_to_blob(ptx.tx, blob); + res.tx_blob = epee::string_tools::buff_to_hex_nodelimer(blob); + } + + return true; + } + catch (const tools::error::daemon_busy& e) + { + er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY; + er.message = e.what(); + return false; + } + catch (const std::exception& e) + { + er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; + er.message = e.what(); + return false; + } + catch (...) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR"; + return false; + } + return true; + } //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_make_integrated_address(const wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er) { @@ -1068,6 +1163,7 @@ namespace tools rpc_transfers.tx_hash = epee::string_tools::pod_to_hex(td.m_txid); rpc_transfers.tx_size = txBlob.size(); rpc_transfers.subaddr_index = td.m_subaddr_index.minor; + rpc_transfers.key_image = req.verbose && td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : ""; res.transfers.push_back(rpc_transfers); } } diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index a2677ef1b..2a51ddf46 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -79,6 +79,7 @@ namespace tools MAP_JON_RPC_WE("transfer_split", on_transfer_split, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT) MAP_JON_RPC_WE("sweep_dust", on_sweep_dust, wallet_rpc::COMMAND_RPC_SWEEP_DUST) MAP_JON_RPC_WE("sweep_all", on_sweep_all, wallet_rpc::COMMAND_RPC_SWEEP_ALL) + MAP_JON_RPC_WE("sweep_single", on_sweep_single, wallet_rpc::COMMAND_RPC_SWEEP_SINGLE) MAP_JON_RPC_WE("store", on_store, wallet_rpc::COMMAND_RPC_STORE) MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_rpc::COMMAND_RPC_GET_PAYMENTS) MAP_JON_RPC_WE("get_bulk_payments", on_get_bulk_payments, wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS) @@ -126,6 +127,7 @@ namespace tools 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); bool on_sweep_all(const wallet_rpc::COMMAND_RPC_SWEEP_ALL::request& req, wallet_rpc::COMMAND_RPC_SWEEP_ALL::response& res, epee::json_rpc::error& er); + bool on_sweep_single(const wallet_rpc::COMMAND_RPC_SWEEP_SINGLE::request& req, wallet_rpc::COMMAND_RPC_SWEEP_SINGLE::response& res, epee::json_rpc::error& er); bool on_make_integrated_address(const wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er); bool on_split_integrated_address(const wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er); bool on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 06f2456c3..9bcc5138a 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -476,6 +476,49 @@ namespace wallet_rpc }; }; + struct COMMAND_RPC_SWEEP_SINGLE + { + struct request + { + std::string address; + uint32_t priority; + uint64_t mixin; + uint64_t unlock_time; + std::string payment_id; + bool get_tx_key; + std::string key_image; + bool do_not_relay; + bool get_tx_hex; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(address) + KV_SERIALIZE(priority) + KV_SERIALIZE(mixin) + KV_SERIALIZE(unlock_time) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(get_tx_key) + KV_SERIALIZE(key_image) + KV_SERIALIZE_OPT(do_not_relay, false) + KV_SERIALIZE_OPT(get_tx_hex, false) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string tx_hash; + std::string tx_key; + uint64_t fee; + std::string tx_blob; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(tx_key) + KV_SERIALIZE(fee) + KV_SERIALIZE(tx_blob) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_STORE { struct request @@ -562,6 +605,7 @@ namespace wallet_rpc std::string tx_hash; uint64_t tx_size; uint32_t subaddr_index; + std::string key_image; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) @@ -570,6 +614,7 @@ namespace wallet_rpc KV_SERIALIZE(tx_hash) KV_SERIALIZE(tx_size) KV_SERIALIZE(subaddr_index) + KV_SERIALIZE(key_image) END_KV_SERIALIZE_MAP() }; @@ -580,11 +625,13 @@ namespace wallet_rpc std::string transfer_type; uint32_t account_index; std::set<uint32_t> subaddr_indices; + bool verbose; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(transfer_type) KV_SERIALIZE(account_index) KV_SERIALIZE(subaddr_indices) + KV_SERIALIZE(verbose) END_KV_SERIALIZE_MAP() }; |