diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f118ea68b..0cedd4b50 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6349,17 +6349,17 @@ bool wallet2::save_multisig_tx(const std::vector& ptx_vector, const return epee::file_io_utils::save_string_to_file(filename, ciphertext); } //---------------------------------------------------------------------------------------------------- -bool wallet2::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported_txs, std::function accept_func) +bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const { const size_t magiclen = strlen(MULTISIG_UNSIGNED_TX_PREFIX); - if (strncmp(s.c_str(), MULTISIG_UNSIGNED_TX_PREFIX, magiclen)) + if (strncmp(multisig_tx_st.c_str(), MULTISIG_UNSIGNED_TX_PREFIX, magiclen)) { LOG_PRINT_L0("Bad magic from multisig tx data"); return false; } try { - s = decrypt_with_view_secret_key(std::string(s, magiclen)); + multisig_tx_st = decrypt_with_view_secret_key(std::string(multisig_tx_st, magiclen)); } catch (const std::exception &e) { @@ -6368,7 +6368,7 @@ bool wallet2::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported } try { - std::istringstream iss(s); + std::istringstream iss(multisig_tx_st); boost::archive::portable_binary_iarchive ar(iss); ar >> exported_txs; } @@ -6390,6 +6390,17 @@ bool wallet2::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported CHECK_AND_ASSERT_MES(ptx.construction_data.sources.size() == ptx.tx.vin.size(), false, "Mismatched sources/vin sizes"); } + return true; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported_txs, std::function accept_func) +{ + if(!parse_multisig_tx_from_str(s, exported_txs)) + { + LOG_PRINT_L0("Failed to parse multisig transaction from string"); + return false; + } + LOG_PRINT_L1("Loaded multisig tx unsigned data from binary: " << exported_txs.m_ptx.size() << " transactions"); for (auto &ptx: exported_txs.m_ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(ptx.tx)); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index be48895ae..1911a8e96 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -800,6 +800,7 @@ namespace tools void cold_tx_aux_import(const std::vector& ptx, const std::vector& tx_device_aux); void cold_sign_tx(const std::vector& ptx_vector, signed_tx_set &exported_txs, std::vector &dsts_info, std::vector & tx_device_aux); uint64_t cold_key_image_sync(uint64_t &spent, uint64_t &unspent); + bool parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const; bool load_multisig_tx(cryptonote::blobdata blob, multisig_tx_set &exported_txs, std::function accept_func = NULL); bool load_multisig_tx_from_file(const std::string &filename, multisig_tx_set &exported_txs, std::function accept_func = NULL); bool sign_multisig_tx_from_file(const std::string &filename, std::vector &txids, std::function accept_func); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 5b7cf90d0..7040597df 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -1074,40 +1074,70 @@ namespace tools er.message = "command not supported by watch-only wallet"; return false; } - - tools::wallet2::unsigned_tx_set exported_txs; - try + if(req.unsigned_txset.empty() && req.multisig_txset.empty()) { - cryptonote::blobdata blob; - if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob)) - { - er.code = WALLET_RPC_ERROR_CODE_BAD_HEX; - er.message = "Failed to parse hex."; - return false; - } - if(!m_wallet->parse_unsigned_tx_from_str(blob, exported_txs)) - { - er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA; - er.message = "cannot load unsigned_txset"; - return false; - } - } - catch (const std::exception &e) - { - er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA; - er.message = "failed to parse unsigned transfers: " + std::string(e.what()); + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "no txset provided"; return false; } + std::vector tx_constructions; + if (!req.unsigned_txset.empty()) { + try { + tools::wallet2::unsigned_tx_set exported_txs; + cryptonote::blobdata blob; + if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob)) { + er.code = WALLET_RPC_ERROR_CODE_BAD_HEX; + er.message = "Failed to parse hex."; + return false; + } + if (!m_wallet->parse_unsigned_tx_from_str(blob, exported_txs)) { + er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA; + er.message = "cannot load unsigned_txset"; + return false; + } + tx_constructions = exported_txs.txes; + } + catch (const std::exception &e) { + er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA; + er.message = "failed to parse unsigned transfers: " + std::string(e.what()); + return false; + } + } else if (!req.multisig_txset.empty()) { + try { + tools::wallet2::multisig_tx_set exported_txs; + cryptonote::blobdata blob; + if (!epee::string_tools::parse_hexstr_to_binbuff(req.multisig_txset, blob)) { + er.code = WALLET_RPC_ERROR_CODE_BAD_HEX; + er.message = "Failed to parse hex."; + return false; + } + if (!m_wallet->parse_multisig_tx_from_str(blob, exported_txs)) { + er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA; + er.message = "cannot load multisig_txset"; + return false; + } + + for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n) { + tx_constructions.push_back(exported_txs.m_ptx[n].construction_data); + } + } + catch (const std::exception &e) { + er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA; + er.message = "failed to parse multisig transfers: " + std::string(e.what()); + return false; + } + } + std::vector ptx; try { // gather info to ask the user std::unordered_map> dests; int first_known_non_zero_change_index = -1; - for (size_t n = 0; n < exported_txs.txes.size(); ++n) + for (size_t n = 0; n < tx_constructions.size(); ++n) { - const tools::wallet2::tx_construction_data &cd = exported_txs.txes[n]; + const tools::wallet2::tx_construction_data &cd = tx_constructions[n]; res.desc.push_back({0, 0, std::numeric_limits::max(), 0, {}, "", 0, "", 0, 0, ""}); wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::transfer_description &desc = res.desc.back(); @@ -1171,7 +1201,7 @@ namespace tools { if (first_known_non_zero_change_index == -1) first_known_non_zero_change_index = n; - const tools::wallet2::tx_construction_data &cdn = exported_txs.txes[first_known_non_zero_change_index]; + const tools::wallet2::tx_construction_data &cdn = tx_constructions[first_known_non_zero_change_index]; if (memcmp(&cd.change_dts.addr, &cdn.change_dts.addr, sizeof(cd.change_dts.addr))) { er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA; @@ -1199,7 +1229,7 @@ namespace tools if (desc.change_amount > 0) { - const tools::wallet2::tx_construction_data &cd0 = exported_txs.txes[0]; + const tools::wallet2::tx_construction_data &cd0 = tx_constructions[0]; desc.change_address = get_account_address_as_str(m_wallet->nettype(), cd0.subaddr_account > 0, cd0.change_dts.addr); } diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 0879502b9..b0e8bed93 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -610,9 +610,11 @@ namespace wallet_rpc struct request_t { std::string unsigned_txset; + std::string multisig_txset; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(unsigned_txset) + KV_SERIALIZE(multisig_txset) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init request;