diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/wallet2.cpp | 185 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 10 | ||||
-rw-r--r-- | src/wallet/wallet_errors.h | 11 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 404 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.h | 5 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_commands_defs.h | 12 |
6 files changed, 315 insertions, 312 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 309e928d9..a66a33c22 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -144,6 +144,16 @@ uint64_t calculate_fee(uint64_t fee_per_kb, const cryptonote::blobdata &blob, ui return calculate_fee(fee_per_kb, blob.size(), fee_multiplier); } +std::string get_size_string(size_t sz) +{ + return std::to_string(sz) + " bytes (" + std::to_string((sz + 1023) / 1024) + " kB)"; +} + +std::string get_size_string(const cryptonote::blobdata &tx) +{ + return get_size_string(tx.size()); +} + std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); @@ -600,6 +610,7 @@ wallet2::wallet2(bool testnet, bool restricted): m_min_output_value(0), m_merge_destinations(false), m_confirm_backlog(true), + m_confirm_backlog_threshold(0), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), @@ -723,6 +734,70 @@ bool wallet2::get_seed(std::string& electrum_words, const epee::wipeable_string return true; } +//---------------------------------------------------------------------------------------------------- +bool wallet2::get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase, bool raw) const +{ + bool ready; + uint32_t threshold, total; + if (!multisig(&ready, &threshold, &total)) + { + std::cout << "This is not a multisig wallet" << std::endl; + return false; + } + if (!ready) + { + std::cout << "This multisig wallet is not yet finalized" << std::endl; + return false; + } + if (!raw && seed_language.empty()) + { + std::cout << "seed_language not set" << std::endl; + return false; + } + + crypto::secret_key skey; + crypto::public_key pkey; + const account_keys &keys = get_account().get_keys(); + std::string data; + data.append((const char*)&threshold, sizeof(uint32_t)); + data.append((const char*)&total, sizeof(uint32_t)); + skey = keys.m_spend_secret_key; + data.append((const char*)&skey, sizeof(skey)); + pkey = keys.m_account_address.m_spend_public_key; + data.append((const char*)&pkey, sizeof(pkey)); + skey = keys.m_view_secret_key; + data.append((const char*)&skey, sizeof(skey)); + pkey = keys.m_account_address.m_view_public_key; + data.append((const char*)&pkey, sizeof(pkey)); + for (const auto &skey: keys.m_multisig_keys) + data.append((const char*)&skey, sizeof(skey)); + for (const auto &signer: m_multisig_signers) + data.append((const char*)&signer, sizeof(signer)); + + if (!passphrase.empty()) + { + crypto::secret_key key; + crypto::cn_slow_hash(passphrase.data(), passphrase.size(), (crypto::hash&)key); + sc_reduce32((unsigned char*)key.data); + data = encrypt(data, key, true); + } + + if (raw) + { + seed = epee::string_tools::buff_to_hex_nodelimer(data); + } + else + { + if (!crypto::ElectrumWords::bytes_to_words(data.data(), data.size(), seed, seed_language)) + { + std::cout << "Failed to encode seed"; + return false; + } + } + + return true; +} +//---------------------------------------------------------------------------------------------------- /*! * \brief Gets the seed language */ @@ -2636,6 +2711,97 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip * \brief Generates a wallet or restores one. * \param wallet_ Name of wallet file * \param password Password of wallet file + * \param multisig_data The multisig restore info and keys + */ +void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password, + const std::string& multisig_data) +{ + clear(); + prepare_file_names(wallet_); + + if (!wallet_.empty()) + { + boost::system::error_code ignored_ec; + THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file); + THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file); + } + + m_account.generate(rct::rct2sk(rct::zero()), true, false); + + THROW_WALLET_EXCEPTION_IF(multisig_data.size() < 32, error::invalid_multisig_seed); + size_t offset = 0; + uint32_t threshold = *(uint32_t*)(multisig_data.data() + offset); + offset += sizeof(uint32_t); + uint32_t total = *(uint32_t*)(multisig_data.data() + offset); + offset += sizeof(uint32_t); + THROW_WALLET_EXCEPTION_IF(threshold < 2, error::invalid_multisig_seed); + THROW_WALLET_EXCEPTION_IF(total != threshold && total != threshold + 1, error::invalid_multisig_seed); + const size_t n_multisig_keys = total == threshold ? 1 : threshold; + THROW_WALLET_EXCEPTION_IF(multisig_data.size() != 8 + 32 * (4 + n_multisig_keys + total), error::invalid_multisig_seed); + + std::vector<crypto::secret_key> multisig_keys; + std::vector<crypto::public_key> multisig_signers; + crypto::secret_key spend_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset); + offset += sizeof(crypto::secret_key); + crypto::public_key spend_public_key = *(crypto::public_key*)(multisig_data.data() + offset); + offset += sizeof(crypto::public_key); + crypto::secret_key view_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset); + offset += sizeof(crypto::secret_key); + crypto::public_key view_public_key = *(crypto::public_key*)(multisig_data.data() + offset); + offset += sizeof(crypto::public_key); + for (size_t n = 0; n < n_multisig_keys; ++n) + { + multisig_keys.push_back(*(crypto::secret_key*)(multisig_data.data() + offset)); + offset += sizeof(crypto::secret_key); + } + for (size_t n = 0; n < total; ++n) + { + multisig_signers.push_back(*(crypto::public_key*)(multisig_data.data() + offset)); + offset += sizeof(crypto::public_key); + } + + crypto::public_key calculated_view_public_key; + THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(view_secret_key, calculated_view_public_key), error::invalid_multisig_seed); + THROW_WALLET_EXCEPTION_IF(view_public_key != calculated_view_public_key, error::invalid_multisig_seed); + crypto::public_key local_signer; + THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(spend_secret_key, local_signer), error::invalid_multisig_seed); + THROW_WALLET_EXCEPTION_IF(std::find(multisig_signers.begin(), multisig_signers.end(), local_signer) == multisig_signers.end(), error::invalid_multisig_seed); + rct::key skey = rct::zero(); + for (const auto &msk: multisig_keys) + sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes); + THROW_WALLET_EXCEPTION_IF(!(rct::rct2sk(skey) == spend_secret_key), error::invalid_multisig_seed); + + m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys); + m_account.finalize_multisig(spend_public_key); + + m_account_public_address = m_account.get_keys().m_account_address; + m_watch_only = false; + m_multisig = true; + m_multisig_threshold = threshold; + m_multisig_signers = multisig_signers; + + if (!wallet_.empty()) + { + bool r = store_keys(m_keys_file, password, false); + THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); + + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); + if(!r) MERROR("String with address text not saved"); + } + + cryptonote::block b; + generate_genesis(b); + m_blockchain.push_back(get_block_hash(b)); + add_subaddress_account(tr("Primary account")); + + if (!wallet_.empty()) + store(); +} + +/*! + * \brief Generates a wallet or restores one. + * \param wallet_ Name of wallet file + * \param password Password of wallet file * \param recovery_param If it is a restore, the recovery key * \param recover Whether it is a restore * \param two_random Whether it is a non-deterministic wallet @@ -5993,7 +6159,8 @@ void wallet2::light_wallet_get_unspent_outs() add_tx_pub_key_to_extra(td.m_tx, tx_pub_key); td.m_key_image = unspent_key_image; - td.m_key_image_known = !m_watch_only; + td.m_key_image_known = !m_watch_only && !m_multisig; + td.m_key_image_partial = m_multisig; td.m_amount = o.amount; td.m_pk_index = 0; td.m_internal_output_index = o.index; @@ -6678,7 +6845,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp auto txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0); - LOG_PRINT_L2("Made a " << ((txBlob.size() + 1023) / 1024) << " kB tx, with " << print_money(available_for_fee) << " available for fee (" << + LOG_PRINT_L2("Made a " << get_size_string(txBlob) << " tx, with " << print_money(available_for_fee) << " available for fee (" << print_money(needed_fee) << " needed)"); if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0) @@ -6720,11 +6887,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); - LOG_PRINT_L2("Made an attempt at a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) << + LOG_PRINT_L2("Made an attempt at a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); } - LOG_PRINT_L2("Made a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) << + LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); tx.tx = test_tx; @@ -6776,7 +6943,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp for (size_t idx: tx.selected_transfers) tx_money += m_transfers[idx].amount(); LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() << - ": " << (tx.bytes+1023)/1024 << " kB, sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() << + ": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() << " outputs to " << tx.dsts.size() << " destination(s), including " << print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change"); ptx_vector.push_back(tx.ptx); @@ -6939,7 +7106,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton auto txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); available_for_fee = test_ptx.fee + test_ptx.dests[0].amount + test_ptx.change_dts.amount; - LOG_PRINT_L2("Made a " << ((txBlob.size() + 1023) / 1024) << " kB tx, with " << print_money(available_for_fee) << " available for fee (" << + LOG_PRINT_L2("Made a " << get_size_string(txBlob) << " tx, with " << print_money(available_for_fee) << " available for fee (" << print_money(needed_fee) << " needed)"); THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, "Transaction cannot pay for itself"); @@ -6955,11 +7122,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); - LOG_PRINT_L2("Made an attempt at a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) << + LOG_PRINT_L2("Made an attempt at a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); } - LOG_PRINT_L2("Made a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) << + LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); tx.tx = test_tx; @@ -6986,7 +7153,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton for (size_t idx: tx.selected_transfers) tx_money += m_transfers[idx].amount(); LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() << - ": " << (tx.bytes+1023)/1024 << " kB, sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() << + ": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() << " outputs to " << tx.dsts.size() << " destination(s), including " << print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change"); ptx_vector.push_back(tx.ptx); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index b1115f67b..2fbe05f89 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -436,6 +436,15 @@ namespace tools typedef std::tuple<uint64_t, crypto::public_key, rct::key> get_outs_entry; /*! + * \brief Generates a wallet or restores one. + * \param wallet_ Name of wallet file + * \param password Password of wallet file + * \param multisig_data The multisig restore info and keys + */ + void generate(const std::string& wallet_, const epee::wipeable_string& password, + const std::string& multisig_data); + + /*! * \brief Generates a wallet or restores one. * \param wallet_ Name of wallet file * \param password Password of wallet file @@ -610,6 +619,7 @@ namespace tools bool watch_only() const { return m_watch_only; } bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const; bool has_multisig_partial_key_images() const; + bool get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase = std::string(), bool raw = true) const; // locked & unlocked balance of given or current subaddress account uint64_t balance(uint32_t subaddr_index_major) const; diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 234c22d85..023b53f28 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -60,6 +60,7 @@ namespace tools // file_save_error // invalid_password // invalid_priority + // invalid_multisig_seed // refresh_error * // acc_outs_lookup_error // block_parse_error @@ -266,6 +267,16 @@ namespace tools std::string to_string() const { return wallet_logic_error::to_string(); } }; + struct invalid_multisig_seed : public wallet_logic_error + { + explicit invalid_multisig_seed(std::string&& loc) + : wallet_logic_error(std::move(loc), "invalid multisig seed") + { + } + + std::string to_string() const { return wallet_logic_error::to_string(); } + }; + //---------------------------------------------------------------------------------------------------- struct invalid_pregenerated_random : public wallet_logic_error { diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index f031b765d..3aba76da0 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -662,7 +662,98 @@ namespace tools } return true; } + //------------------------------------------------------------------------------------------------------------------------------ + static std::string ptx_to_string(const tools::wallet2::pending_tx &ptx) + { + std::ostringstream oss; + boost::archive::portable_binary_oarchive ar(oss); + try + { + ar << ptx; + } + catch (...) + { + return ""; + } + return epee::string_tools::buff_to_hex_nodelimer(oss.str()); + } + //------------------------------------------------------------------------------------------------------------------------------ + template<typename T> static bool is_error_value(const T &val) { return false; } + static bool is_error_value(const std::string &s) { return s.empty(); } + //------------------------------------------------------------------------------------------------------------------------------ + template<typename T, typename V> + static bool fill(T &where, V s) + { + if (is_error_value(s)) return false; + where = std::move(s); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + template<typename T, typename V> + static bool fill(std::list<T> &where, V s) + { + if (is_error_value(s)) return false; + where.emplace_back(std::move(s)); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + static uint64_t total_amount(const tools::wallet2::pending_tx &ptx) + { + uint64_t amount = 0; + for (const auto &dest: ptx.dests) amount += dest.amount; + return amount; + } + //------------------------------------------------------------------------------------------------------------------------------ + template<typename Ts, typename Tu> + bool wallet_rpc_server::fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector, + bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, bool do_not_relay, + Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, epee::json_rpc::error &er) + { + for (const auto & ptx : ptx_vector) + { + if (get_tx_key) + { + std::string s = epee::string_tools::pod_to_hex(ptx.tx_key); + for (const crypto::secret_key& additional_tx_key : ptx.additional_tx_keys) + s += epee::string_tools::pod_to_hex(additional_tx_key); + fill(tx_key, s); + } + // Compute amount leaving wallet in tx. By convention dests does not include change outputs + fill(amount, total_amount(ptx)); + fill(fee, ptx.fee); + } + if (m_wallet->multisig()) + { + multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector)); + if (multisig_txset.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "Failed to save multisig tx set after creation"; + return false; + } + } + else + { + if (!do_not_relay) + m_wallet->commit_tx(ptx_vector); + + // populate response with tx hashes + for (auto & ptx : ptx_vector) + { + bool r = fill(tx_hash, epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); + r = r && (!get_tx_hex || fill(tx_blob, epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)))); + r = r && (!get_tx_metadata || fill(tx_metadata, ptx_to_string(ptx))); + if (!r) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "Failed to save tx info"; + return false; + } + } + } + return true; + } //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er) { @@ -705,55 +796,8 @@ namespace tools return false; } - if (req.get_tx_key) - { - res.tx_key = epee::string_tools::pod_to_hex(ptx_vector.back().tx_key); - for (const crypto::secret_key& additional_tx_key : ptx_vector.back().additional_tx_keys) - res.tx_key += epee::string_tools::pod_to_hex(additional_tx_key); - } - res.fee = ptx_vector.back().fee; - - if (m_wallet->multisig()) - { - res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector)); - if (res.multisig_txset.empty()) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - } - else - { - if (!req.do_not_relay) - m_wallet->commit_tx(ptx_vector); - - // populate response with tx hash - res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx_vector.back().tx)); - if (req.get_tx_hex) - { - cryptonote::blobdata blob; - tx_to_blob(ptx_vector.back().tx, blob); - res.tx_blob = epee::string_tools::buff_to_hex_nodelimer(blob); - } - if (req.get_tx_metadata) - { - std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - try - { - ar << ptx_vector.back(); - } - catch (...) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - res.tx_metadata = epee::string_tools::buff_to_hex_nodelimer(oss.str()); - } - } - return true; + return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, req.do_not_relay, + res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er); } catch (const std::exception& e) { @@ -786,82 +830,12 @@ namespace tools try { uint64_t mixin = m_wallet->adjust_mixin(req.mixin); - uint64_t ptx_amount; - std::vector<wallet2::pending_tx> ptx_vector; LOG_PRINT_L2("on_transfer_split calling create_transactions_2"); - ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); + 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); LOG_PRINT_L2("on_transfer_split called create_transactions_2"); - // populate response with tx hashes - for (const auto & ptx : ptx_vector) - { - if (req.get_tx_keys) - { - res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); - for (const crypto::secret_key& additional_tx_key : ptx.additional_tx_keys) - res.tx_key_list.back() += epee::string_tools::pod_to_hex(additional_tx_key); - } - // Compute amount leaving wallet in tx. By convention dests does not include change outputs - ptx_amount = 0; - for(auto & dt: ptx.dests) - ptx_amount += dt.amount; - res.amount_list.push_back(ptx_amount); - - res.fee_list.push_back(ptx.fee); - } - - if (m_wallet->multisig()) - { - res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector)); - if (res.multisig_txset.empty()) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - } - - // populate response with tx hashes - for (const auto & ptx : ptx_vector) - { - if (!req.do_not_relay) - { - LOG_PRINT_L2("on_transfer_split calling commit_tx"); - m_wallet->commit_tx(ptx_vector); - LOG_PRINT_L2("on_transfer_split called commit_tx"); - } - - // populate response with tx hashes - for (auto & ptx : ptx_vector) - { - res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); - - if (req.get_tx_hex) - { - cryptonote::blobdata blob; - tx_to_blob(ptx.tx, blob); - res.tx_blob_list.push_back(epee::string_tools::buff_to_hex_nodelimer(blob)); - } - if (req.get_tx_metadata) - { - std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - try - { - ar << ptx; - } - catch (...) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str())); - } - } - } - - return true; + return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay, + res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er); } catch (const std::exception& e) { @@ -885,69 +859,8 @@ namespace tools { std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon); - for (const auto & ptx : ptx_vector) - { - if (req.get_tx_keys) - { - res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); - } - res.fee_list.push_back(ptx.fee); - } - - if (m_wallet->multisig()) - { - for (tools::wallet2::pending_tx &ptx: ptx_vector) - { - std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - try - { - ar << ptx; - } - catch (...) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - res.multisig_txset.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str())); - } - } - else - { - if (!req.do_not_relay) - m_wallet->commit_tx(ptx_vector); - - // populate response with tx hashes - for (auto & ptx : ptx_vector) - { - res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); - if (req.get_tx_hex) - { - cryptonote::blobdata blob; - tx_to_blob(ptx.tx, blob); - res.tx_blob_list.push_back(epee::string_tools::buff_to_hex_nodelimer(blob)); - } - if (req.get_tx_metadata) - { - std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - try - { - ar << ptx; - } - catch (...) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str())); - } - } - } - - return true; + return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay, + res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er); } catch (const std::exception& e) { @@ -985,68 +898,8 @@ namespace tools uint64_t mixin = m_wallet->adjust_mixin(req.mixin); std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); - for (const auto & ptx : ptx_vector) - { - if (req.get_tx_keys) - { - res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key)); - } - } - - if (m_wallet->multisig()) - { - for (tools::wallet2::pending_tx &ptx: ptx_vector) - { - std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - try - { - ar << ptx; - } - catch (...) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - res.multisig_txset.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str())); - } - } - else - { - if (!req.do_not_relay) - m_wallet->commit_tx(ptx_vector); - - // populate response with tx hashes - for (auto & ptx : ptx_vector) - { - res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); - if (req.get_tx_hex) - { - cryptonote::blobdata blob; - tx_to_blob(ptx.tx, blob); - res.tx_blob_list.push_back(epee::string_tools::buff_to_hex_nodelimer(blob)); - } - if (req.get_tx_metadata) - { - std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - try - { - ar << ptx; - } - catch (...) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str())); - } - } - } - - return true; + return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay, + res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er); } catch (const std::exception& e) { @@ -1112,63 +965,12 @@ namespace tools return false; } - if (req.get_tx_key) - { - res.tx_key = epee::string_tools::pod_to_hex(ptx.tx_key); - } - - if (m_wallet->multisig()) - { - res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector)); - if (res.multisig_txset.empty()) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - } - else - { - if (!req.do_not_relay) - m_wallet->commit_tx(ptx_vector); - - // populate response with tx hashes - res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)); - 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); - } - if (req.get_tx_metadata) - { - std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - try - { - ar << ptx; - } - catch (...) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; - return false; - } - res.tx_metadata = epee::string_tools::buff_to_hex_nodelimer(oss.str()); - } - } - return true; - } - catch (const tools::error::daemon_busy& e) - { - er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY; - er.message = e.what(); - return false; + return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, req.do_not_relay, + res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er); } catch (const std::exception& e) { - er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; - er.message = e.what(); + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR); return false; } catch (...) diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index b20198b78..88f2a85a4 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -207,6 +207,11 @@ namespace tools bool not_open(epee::json_rpc::error& er); void handle_rpc_exception(const std::exception_ptr& e, epee::json_rpc::error& er, int default_error_code); + template<typename Ts, typename Tu> + bool fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector, + bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, bool do_not_relay, + Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, epee::json_rpc::error &er); + wallet2 *m_wallet; std::string m_wallet_dir; tools::private_file rpc_login_file; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 76c02039b..d797af5c1 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -411,6 +411,7 @@ namespace wallet_rpc std::string tx_hash; std::string tx_key; std::list<std::string> amount_keys; + uint64_t amount; uint64_t fee; std::string tx_blob; std::string tx_metadata; @@ -420,6 +421,7 @@ namespace wallet_rpc KV_SERIALIZE(tx_hash) KV_SERIALIZE(tx_key) KV_SERIALIZE(amount_keys) + KV_SERIALIZE(amount) KV_SERIALIZE(fee) KV_SERIALIZE(tx_blob) KV_SERIALIZE(tx_metadata) @@ -520,14 +522,16 @@ namespace wallet_rpc { std::list<std::string> tx_hash_list; std::list<std::string> tx_key_list; + std::list<uint64_t> amount_list; std::list<uint64_t> fee_list; std::list<std::string> tx_blob_list; std::list<std::string> tx_metadata_list; - std::list<std::string> multisig_txset; + std::string multisig_txset; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) KV_SERIALIZE(tx_key_list) + KV_SERIALIZE(amount_list) KV_SERIALIZE(fee_list) KV_SERIALIZE(tx_blob_list) KV_SERIALIZE(tx_metadata_list) @@ -582,14 +586,16 @@ namespace wallet_rpc { std::list<std::string> tx_hash_list; std::list<std::string> tx_key_list; + std::list<uint64_t> amount_list; std::list<uint64_t> fee_list; std::list<std::string> tx_blob_list; std::list<std::string> tx_metadata_list; - std::list<std::string> multisig_txset; + std::string multisig_txset; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash_list) KV_SERIALIZE(tx_key_list) + KV_SERIALIZE(amount_list) KV_SERIALIZE(fee_list) KV_SERIALIZE(tx_blob_list) KV_SERIALIZE(tx_metadata_list) @@ -631,6 +637,7 @@ namespace wallet_rpc { std::string tx_hash; std::string tx_key; + uint64_t amount; uint64_t fee; std::string tx_blob; std::string tx_metadata; @@ -639,6 +646,7 @@ namespace wallet_rpc BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(tx_hash) KV_SERIALIZE(tx_key) + KV_SERIALIZE(amount) KV_SERIALIZE(fee) KV_SERIALIZE(tx_blob) KV_SERIALIZE(tx_metadata) |