mirror of
https://github.com/monero-project/monero.git
synced 2024-11-18 00:37:43 +00:00
wallet-rpc: watch-only and cold wallet features added
- unsigned_txset, signed_txset in transfer / submit_transfer / sign_transfer - export_outputs, import_outputs Squashed commits: [f4d9f3d4] wallet-rpc: do_not_relay removed from submit_transfer [5b16a86f] wallet-rpc: review-fix - method signature changes, renaming [b7fbb10a] wallet-rpc: naming fixes (unsigned vs signed), consts renamed [8c7d2727] wallet-rpc: sign_transfer added [481d024a] wallet2: sign_tx splitted to work with strings and structs, more granular [2a474db9] wallet-rpc: wallet2::load_unsigned_tx split to load from str, file [b1e3a018] wallet-rpc: review fix, load_tx_from_str variable rename [1f6373be] wallet-rpc: review fix: save_tx_to_{str,file} [2a08eafc] wallet-rpc: review comments fixes - redundant this removed from wallet2.cpp - load_tx_from_str, load_tx_from_file [43498052] wallet-rpc: submit_transfer added [9c45d1ad] wallet-rpc: watch_only check, return unsigned_txset [62831396] wallet2: added string variants to load_tx, save_tx - analogously to save_multisig_tx - required for monero-wallet-rpc to support watch-only wallet
This commit is contained in:
parent
9bc8f76924
commit
9c2a7b4638
7 changed files with 495 additions and 98 deletions
|
@ -90,8 +90,6 @@ typedef cryptonote::simple_wallet sw;
|
||||||
|
|
||||||
#define MIN_RING_SIZE 7 // Used to inform user about min ring size -- does not track actual protocol
|
#define MIN_RING_SIZE 7 // Used to inform user about min ring size -- does not track actual protocol
|
||||||
|
|
||||||
#define OUTPUT_EXPORT_FILE_MAGIC "Monero output export\003"
|
|
||||||
|
|
||||||
#define LOCK_IDLE_SCOPE() \
|
#define LOCK_IDLE_SCOPE() \
|
||||||
bool auto_refresh_enabled = m_auto_refresh_enabled.load(std::memory_order_relaxed); \
|
bool auto_refresh_enabled = m_auto_refresh_enabled.load(std::memory_order_relaxed); \
|
||||||
m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \
|
m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \
|
||||||
|
@ -7182,19 +7180,8 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
|
||||||
LOCK_IDLE_SCOPE();
|
LOCK_IDLE_SCOPE();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::vector<tools::wallet2::transfer_details> outs = m_wallet->export_outputs();
|
std::string data = m_wallet->export_outputs_to_str();
|
||||||
|
bool r = epee::file_io_utils::save_string_to_file(filename, data);
|
||||||
std::stringstream oss;
|
|
||||||
boost::archive::portable_binary_oarchive ar(oss);
|
|
||||||
ar << outs;
|
|
||||||
|
|
||||||
std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC));
|
|
||||||
const cryptonote::account_public_address &keys = m_wallet->get_account().get_keys().m_account_address;
|
|
||||||
std::string header;
|
|
||||||
header += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
|
|
||||||
header += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
|
|
||||||
std::string ciphertext = m_wallet->encrypt_with_view_secret_key(header + oss.str());
|
|
||||||
bool r = epee::file_io_utils::save_string_to_file(filename, magic + ciphertext);
|
|
||||||
if (!r)
|
if (!r)
|
||||||
{
|
{
|
||||||
fail_msg_writer() << tr("failed to save file ") << filename;
|
fail_msg_writer() << tr("failed to save file ") << filename;
|
||||||
|
@ -7233,63 +7220,16 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
|
||||||
fail_msg_writer() << tr("failed to read file ") << filename;
|
fail_msg_writer() << tr("failed to read file ") << filename;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const size_t magiclen = strlen(OUTPUT_EXPORT_FILE_MAGIC);
|
|
||||||
if (data.size() < magiclen || memcmp(data.data(), OUTPUT_EXPORT_FILE_MAGIC, magiclen))
|
|
||||||
{
|
|
||||||
fail_msg_writer() << "Bad output export file magic in " << filename;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
data = m_wallet->decrypt_with_view_secret_key(std::string(data, magiclen));
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
fail_msg_writer() << "Failed to decrypt " << filename << ": " << e.what();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t headerlen = 2 * sizeof(crypto::public_key);
|
|
||||||
if (data.size() < headerlen)
|
|
||||||
{
|
|
||||||
fail_msg_writer() << "Bad data size from file " << filename;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0];
|
|
||||||
const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)];
|
|
||||||
const cryptonote::account_public_address &keys = m_wallet->get_account().get_keys().m_account_address;
|
|
||||||
if (public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key)
|
|
||||||
{
|
|
||||||
fail_msg_writer() << "Outputs from " << filename << " are for a different account";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::string body(data, headerlen);
|
|
||||||
std::stringstream iss;
|
|
||||||
iss << body;
|
|
||||||
std::vector<tools::wallet2::transfer_details> outputs;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
boost::archive::portable_binary_iarchive ar(iss);
|
|
||||||
ar >> outputs;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
iss.str("");
|
|
||||||
iss << body;
|
|
||||||
boost::archive::binary_iarchive ar(iss);
|
|
||||||
ar >> outputs;
|
|
||||||
}
|
|
||||||
LOCK_IDLE_SCOPE();
|
LOCK_IDLE_SCOPE();
|
||||||
size_t n_outputs = m_wallet->import_outputs(outputs);
|
size_t n_outputs = m_wallet->import_outputs_from_str(data);
|
||||||
success_msg_writer() << boost::lexical_cast<std::string>(n_outputs) << " outputs imported";
|
success_msg_writer() << boost::lexical_cast<std::string>(n_outputs) << " outputs imported";
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
fail_msg_writer() << "Failed to import outputs: " << e.what();
|
fail_msg_writer() << "Failed to import outputs " << filename << ": " << e.what();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,8 @@ using namespace cryptonote;
|
||||||
|
|
||||||
#define MULTISIG_EXPORT_FILE_MAGIC "Monero multisig export\001"
|
#define MULTISIG_EXPORT_FILE_MAGIC "Monero multisig export\001"
|
||||||
|
|
||||||
|
#define OUTPUT_EXPORT_FILE_MAGIC "Monero output export\003"
|
||||||
|
|
||||||
#define SEGREGATION_FORK_HEIGHT 1546000
|
#define SEGREGATION_FORK_HEIGHT 1546000
|
||||||
#define TESTNET_SEGREGATION_FORK_HEIGHT 1000000
|
#define TESTNET_SEGREGATION_FORK_HEIGHT 1000000
|
||||||
#define STAGENET_SEGREGATION_FORK_HEIGHT 1000000
|
#define STAGENET_SEGREGATION_FORK_HEIGHT 1000000
|
||||||
|
@ -4659,6 +4661,15 @@ void wallet2::commit_tx(std::vector<pending_tx>& ptx_vector)
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename) const
|
bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename) const
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("saving " << ptx_vector.size() << " transactions");
|
||||||
|
std::string ciphertext = dump_tx_to_str(ptx_vector);
|
||||||
|
if (ciphertext.empty())
|
||||||
|
return false;
|
||||||
|
return epee::file_io_utils::save_string_to_file(filename, ciphertext);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) const
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("saving " << ptx_vector.size() << " transactions");
|
LOG_PRINT_L0("saving " << ptx_vector.size() << " transactions");
|
||||||
unsigned_tx_set txs;
|
unsigned_tx_set txs;
|
||||||
|
@ -4680,11 +4691,11 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
return false;
|
return std::string();
|
||||||
}
|
}
|
||||||
LOG_PRINT_L2("Saving unsigned tx data: " << oss.str());
|
LOG_PRINT_L2("Saving unsigned tx data: " << oss.str());
|
||||||
std::string ciphertext = encrypt_with_view_secret_key(oss.str());
|
std::string ciphertext = encrypt_with_view_secret_key(oss.str());
|
||||||
return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + ciphertext);
|
return std::string(UNSIGNED_TX_PREFIX) + ciphertext;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs) const
|
bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs) const
|
||||||
|
@ -4702,10 +4713,17 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx
|
||||||
LOG_PRINT_L0("Failed to load from " << unsigned_filename);
|
LOG_PRINT_L0("Failed to load from " << unsigned_filename);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return parse_unsigned_tx_from_str(s, exported_txs);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
bool wallet2::parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const
|
||||||
|
{
|
||||||
|
std::string s = unsigned_tx_st;
|
||||||
const size_t magiclen = strlen(UNSIGNED_TX_PREFIX) - 1;
|
const size_t magiclen = strlen(UNSIGNED_TX_PREFIX) - 1;
|
||||||
if (strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen))
|
if (strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Bad magic from " << unsigned_filename);
|
LOG_PRINT_L0("Bad magic from unsigned tx");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
s = s.substr(magiclen);
|
s = s.substr(magiclen);
|
||||||
|
@ -4721,7 +4739,7 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to parse data from " << unsigned_filename);
|
LOG_PRINT_L0("Failed to parse data from unsigned tx");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4738,19 +4756,19 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to parse data from " << unsigned_filename);
|
LOG_PRINT_L0("Failed to parse data from unsigned tx");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to decrypt " << unsigned_filename << ": " << e.what());
|
LOG_PRINT_L0("Failed to decrypt unsigned tx: " << e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Unsupported version in " << unsigned_filename);
|
LOG_PRINT_L0("Unsupported version in unsigned tx");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_PRINT_L1("Loaded tx unsigned data from binary: " << exported_txs.txes.size() << " transactions");
|
LOG_PRINT_L1("Loaded tx unsigned data from binary: " << exported_txs.txes.size() << " transactions");
|
||||||
|
@ -4771,14 +4789,12 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s
|
||||||
}
|
}
|
||||||
return sign_tx(exported_txs, signed_filename, txs, export_raw);
|
return sign_tx(exported_txs, signed_filename, txs, export_raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, bool export_raw)
|
bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pending_tx> &txs, signed_tx_set &signed_txes)
|
||||||
{
|
{
|
||||||
import_outputs(exported_txs.transfers);
|
import_outputs(exported_txs.transfers);
|
||||||
|
|
||||||
// sign the transactions
|
// sign the transactions
|
||||||
signed_tx_set signed_txes;
|
|
||||||
for (size_t n = 0; n < exported_txs.txes.size(); ++n)
|
for (size_t n = 0; n < exported_txs.txes.size(); ++n)
|
||||||
{
|
{
|
||||||
tools::wallet2::tx_construction_data &sd = exported_txs.txes[n];
|
tools::wallet2::tx_construction_data &sd = exported_txs.txes[n];
|
||||||
|
@ -4840,19 +4856,20 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
|
||||||
signed_txes.key_images[i] = m_transfers[i].m_key_image;
|
signed_txes.key_images[i] = m_transfers[i].m_key_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save as binary
|
return true;
|
||||||
std::ostringstream oss;
|
}
|
||||||
boost::archive::portable_binary_oarchive ar(oss);
|
//----------------------------------------------------------------------------------------------------
|
||||||
try
|
bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, bool export_raw)
|
||||||
{
|
{
|
||||||
ar << signed_txes;
|
// sign the transactions
|
||||||
}
|
signed_tx_set signed_txes;
|
||||||
catch(...)
|
std::string ciphertext = sign_tx_dump_to_str(exported_txs, txs, signed_txes);
|
||||||
|
if (ciphertext.empty())
|
||||||
{
|
{
|
||||||
|
LOG_PRINT_L0("Failed to sign unsigned_tx_set");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_PRINT_L3("Saving signed tx data (with encryption): " << oss.str());
|
|
||||||
std::string ciphertext = encrypt_with_view_secret_key(oss.str());
|
|
||||||
if (!epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + ciphertext))
|
if (!epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + ciphertext))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to save file to " << signed_filename);
|
LOG_PRINT_L0("Failed to save file to " << signed_filename);
|
||||||
|
@ -4875,6 +4892,32 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
std::string wallet2::sign_tx_dump_to_str(unsigned_tx_set &exported_txs, std::vector<wallet2::pending_tx> &ptx, signed_tx_set &signed_txes)
|
||||||
|
{
|
||||||
|
// sign the transactions
|
||||||
|
bool r = sign_tx(exported_txs, ptx, signed_txes);
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to sign unsigned_tx_set");
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// save as binary
|
||||||
|
std::ostringstream oss;
|
||||||
|
boost::archive::portable_binary_oarchive ar(oss);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ar << signed_txes;
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
LOG_PRINT_L3("Saving signed tx data (with encryption): " << oss.str());
|
||||||
|
std::string ciphertext = encrypt_with_view_secret_key(oss.str());
|
||||||
|
return std::string(SIGNED_TX_PREFIX) + ciphertext;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func)
|
bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func)
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
|
@ -4892,10 +4935,20 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
|
||||||
LOG_PRINT_L0("Failed to load from " << signed_filename);
|
LOG_PRINT_L0("Failed to load from " << signed_filename);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return parse_tx_from_str(s, ptx, accept_func);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func)
|
||||||
|
{
|
||||||
|
std::string s = signed_tx_st;
|
||||||
|
boost::system::error_code errcode;
|
||||||
|
signed_tx_set signed_txs;
|
||||||
|
|
||||||
const size_t magiclen = strlen(SIGNED_TX_PREFIX) - 1;
|
const size_t magiclen = strlen(SIGNED_TX_PREFIX) - 1;
|
||||||
if (strncmp(s.c_str(), SIGNED_TX_PREFIX, magiclen))
|
if (strncmp(s.c_str(), SIGNED_TX_PREFIX, magiclen))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Bad magic from " << signed_filename);
|
LOG_PRINT_L0("Bad magic from signed transaction");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
s = s.substr(magiclen);
|
s = s.substr(magiclen);
|
||||||
|
@ -4911,7 +4964,7 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to parse data from " << signed_filename);
|
LOG_PRINT_L0("Failed to parse data from signed transaction");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4928,23 +4981,23 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to parse decrypted data from " << signed_filename);
|
LOG_PRINT_L0("Failed to parse decrypted data from signed transaction");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to decrypt " << signed_filename << ": " << e.what());
|
LOG_PRINT_L0("Failed to decrypt signed transaction: " << e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Unsupported version in " << signed_filename);
|
LOG_PRINT_L0("Unsupported version in signed transaction");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_PRINT_L0("Loaded signed tx data from binary: " << signed_txs.ptx.size() << " transactions");
|
LOG_PRINT_L0("Loaded signed tx data from binary: " << signed_txs.ptx.size() << " transactions");
|
||||||
for (auto &ptx: signed_txs.ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(ptx.tx));
|
for (auto &c_ptx: signed_txs.ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(c_ptx.tx));
|
||||||
|
|
||||||
if (accept_func && !accept_func(signed_txs))
|
if (accept_func && !accept_func(signed_txs))
|
||||||
{
|
{
|
||||||
|
@ -9772,6 +9825,23 @@ std::vector<tools::wallet2::transfer_details> wallet2::export_outputs() const
|
||||||
return outs;
|
return outs;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
std::string wallet2::export_outputs_to_str() const
|
||||||
|
{
|
||||||
|
std::vector<tools::wallet2::transfer_details> outs = export_outputs();
|
||||||
|
|
||||||
|
std::stringstream oss;
|
||||||
|
boost::archive::portable_binary_oarchive ar(oss);
|
||||||
|
ar << outs;
|
||||||
|
|
||||||
|
std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC));
|
||||||
|
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
|
||||||
|
std::string header;
|
||||||
|
header += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
|
||||||
|
header += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
|
||||||
|
std::string ciphertext = encrypt_with_view_secret_key(header + oss.str());
|
||||||
|
return magic + ciphertext;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs)
|
size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs)
|
||||||
{
|
{
|
||||||
m_transfers.clear();
|
m_transfers.clear();
|
||||||
|
@ -9804,6 +9874,67 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail
|
||||||
return m_transfers.size();
|
return m_transfers.size();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
size_t wallet2::import_outputs_from_str(const std::string &outputs_st)
|
||||||
|
{
|
||||||
|
std::string data = outputs_st;
|
||||||
|
const size_t magiclen = strlen(OUTPUT_EXPORT_FILE_MAGIC);
|
||||||
|
if (data.size() < magiclen || memcmp(data.data(), OUTPUT_EXPORT_FILE_MAGIC, magiclen))
|
||||||
|
{
|
||||||
|
THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad magic from outputs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
data = decrypt_with_view_secret_key(std::string(data, magiclen));
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt outputs: ") + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t headerlen = 2 * sizeof(crypto::public_key);
|
||||||
|
if (data.size() < headerlen)
|
||||||
|
{
|
||||||
|
THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Bad data size for outputs"));
|
||||||
|
}
|
||||||
|
const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0];
|
||||||
|
const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)];
|
||||||
|
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
|
||||||
|
if (public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key)
|
||||||
|
{
|
||||||
|
THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Outputs from are for a different account"));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t imported_outputs = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::string body(data, headerlen);
|
||||||
|
std::stringstream iss;
|
||||||
|
iss << body;
|
||||||
|
std::vector<tools::wallet2::transfer_details> outputs;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
boost::archive::portable_binary_iarchive ar(iss);
|
||||||
|
ar >> outputs;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
iss.str("");
|
||||||
|
iss << body;
|
||||||
|
boost::archive::binary_iarchive ar(iss);
|
||||||
|
ar >> outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
imported_outputs = import_outputs(outputs);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to import outputs") + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return imported_outputs;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
crypto::public_key wallet2::get_multisig_signer_public_key(const crypto::secret_key &spend_skey) const
|
crypto::public_key wallet2::get_multisig_signer_public_key(const crypto::secret_key &spend_skey) const
|
||||||
{
|
{
|
||||||
crypto::public_key pkey;
|
crypto::public_key pkey;
|
||||||
|
|
|
@ -684,6 +684,7 @@ namespace tools
|
||||||
void commit_tx(pending_tx& ptx_vector);
|
void commit_tx(pending_tx& ptx_vector);
|
||||||
void commit_tx(std::vector<pending_tx>& ptx_vector);
|
void commit_tx(std::vector<pending_tx>& ptx_vector);
|
||||||
bool save_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename) const;
|
bool save_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename) const;
|
||||||
|
std::string dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) const;
|
||||||
std::string save_multisig_tx(multisig_tx_set txs);
|
std::string save_multisig_tx(multisig_tx_set txs);
|
||||||
bool save_multisig_tx(const multisig_tx_set &txs, const std::string &filename);
|
bool save_multisig_tx(const multisig_tx_set &txs, const std::string &filename);
|
||||||
std::string save_multisig_tx(const std::vector<pending_tx>& ptx_vector);
|
std::string save_multisig_tx(const std::vector<pending_tx>& ptx_vector);
|
||||||
|
@ -692,9 +693,13 @@ namespace tools
|
||||||
bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, std::function<bool(const unsigned_tx_set&)> accept_func = NULL, bool export_raw = false);
|
bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, std::function<bool(const unsigned_tx_set&)> accept_func = NULL, bool export_raw = false);
|
||||||
// sign unsigned tx. Takes unsigned_tx_set as argument. Used by GUI
|
// sign unsigned tx. Takes unsigned_tx_set as argument. Used by GUI
|
||||||
bool sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, bool export_raw = false);
|
bool sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, bool export_raw = false);
|
||||||
|
bool sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pending_tx> &ptx, signed_tx_set &signed_txs);
|
||||||
|
std::string sign_tx_dump_to_str(unsigned_tx_set &exported_txs, std::vector<wallet2::pending_tx> &ptx, signed_tx_set &signed_txes);
|
||||||
// load unsigned_tx_set from file.
|
// load unsigned_tx_set from file.
|
||||||
bool load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs) const;
|
bool load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs) const;
|
||||||
|
bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const;
|
||||||
bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
|
bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
|
||||||
|
bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func);
|
||||||
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<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_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_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);
|
||||||
|
@ -970,7 +975,9 @@ namespace tools
|
||||||
|
|
||||||
// Import/Export wallet data
|
// Import/Export wallet data
|
||||||
std::vector<tools::wallet2::transfer_details> export_outputs() const;
|
std::vector<tools::wallet2::transfer_details> export_outputs() const;
|
||||||
|
std::string export_outputs_to_str() const;
|
||||||
size_t import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs);
|
size_t import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs);
|
||||||
|
size_t import_outputs_from_str(const std::string &outputs_st);
|
||||||
payment_container export_payments() const;
|
payment_container export_payments() const;
|
||||||
void import_payments(const payment_container &payments);
|
void import_payments(const payment_container &payments);
|
||||||
void import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments);
|
void import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments);
|
||||||
|
|
|
@ -712,7 +712,7 @@ namespace tools
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
template<typename Ts, typename Tu>
|
template<typename Ts, typename Tu>
|
||||||
bool wallet_rpc_server::fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector,
|
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,
|
bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, std::string &unsigned_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)
|
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)
|
for (const auto & ptx : ptx_vector)
|
||||||
|
@ -741,7 +741,16 @@ namespace tools
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!do_not_relay)
|
if (m_wallet->watch_only()){
|
||||||
|
unsigned_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->dump_tx_to_str(ptx_vector));
|
||||||
|
if (unsigned_txset.empty())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||||
|
er.message = "Failed to save unsigned tx set after creation";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!do_not_relay)
|
||||||
m_wallet->commit_tx(ptx_vector);
|
m_wallet->commit_tx(ptx_vector);
|
||||||
|
|
||||||
// populate response with tx hashes
|
// populate response with tx hashes
|
||||||
|
@ -811,7 +820,7 @@ namespace tools
|
||||||
return false;
|
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,
|
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
|
||||||
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
|
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
|
@ -858,7 +867,7 @@ namespace tools
|
||||||
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, 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, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
|
||||||
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
|
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
|
||||||
|
|
||||||
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,
|
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_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);
|
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)
|
catch (const std::exception& e)
|
||||||
|
@ -869,6 +878,141 @@ namespace tools
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool wallet_rpc_server::on_sign_transfer(const wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::response& res, epee::json_rpc::error& er)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (m_wallet->key_on_device())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||||
|
er.message = "command not supported by HW wallet";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(m_wallet->watch_only())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY;
|
||||||
|
er.message = "command not supported by watch-only wallet";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
tools::wallet2::unsigned_tx_set exported_txs;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<tools::wallet2::pending_tx> ptxs;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tools::wallet2::signed_tx_set signed_txs;
|
||||||
|
std::string ciphertext = m_wallet->sign_tx_dump_to_str(exported_txs, ptxs, signed_txs);
|
||||||
|
if (ciphertext.empty())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_SIGN_UNSIGNED;
|
||||||
|
er.message = "Failed to sign unsigned tx";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.signed_txset = epee::string_tools::buff_to_hex_nodelimer(ciphertext);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_SIGN_UNSIGNED;
|
||||||
|
er.message = std::string("Failed to sign unsigned tx: ") + e.what();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &ptx: ptxs)
|
||||||
|
{
|
||||||
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.export_raw)
|
||||||
|
{
|
||||||
|
for (auto &ptx: ptxs)
|
||||||
|
{
|
||||||
|
res.tx_raw_list.push_back(epee::string_tools::buff_to_hex_nodelimer(cryptonote::tx_to_blob(ptx.tx)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool wallet_rpc_server::on_submit_transfer(const wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::response& res, epee::json_rpc::error& er)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (m_wallet->key_on_device())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||||
|
er.message = "command not supported by HW wallet";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptonote::blobdata blob;
|
||||||
|
if (!epee::string_tools::parse_hexstr_to_binbuff(req.tx_data_hex, blob))
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
|
||||||
|
er.message = "Failed to parse hex.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<tools::wallet2::pending_tx> ptx_vector;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool r = m_wallet->parse_tx_from_str(blob, ptx_vector, NULL);
|
||||||
|
if (!r)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_BAD_SIGNED_TX_DATA;
|
||||||
|
er.message = "Failed to parse signed tx data.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_BAD_SIGNED_TX_DATA;
|
||||||
|
er.message = std::string("Failed to parse signed tx: ") + e.what();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (auto &ptx: ptx_vector)
|
||||||
|
{
|
||||||
|
m_wallet->commit_tx(ptx);
|
||||||
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_SIGNED_SUBMISSION;
|
||||||
|
er.message = std::string("Failed to submit signed tx: ") + e.what();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::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 wallet_rpc_server::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)
|
||||||
{
|
{
|
||||||
if (!m_wallet) return not_open(er);
|
if (!m_wallet) return not_open(er);
|
||||||
|
@ -883,7 +1027,7 @@ namespace tools
|
||||||
{
|
{
|
||||||
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
|
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
|
||||||
|
|
||||||
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,
|
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_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);
|
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)
|
catch (const std::exception& e)
|
||||||
|
@ -931,7 +1075,7 @@ namespace tools
|
||||||
uint32_t priority = m_wallet->adjust_priority(req.priority);
|
uint32_t priority = m_wallet->adjust_priority(req.priority);
|
||||||
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, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
|
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, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
|
||||||
|
|
||||||
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,
|
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_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);
|
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)
|
catch (const std::exception& e)
|
||||||
|
@ -1007,7 +1151,7 @@ namespace tools
|
||||||
return false;
|
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,
|
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
|
||||||
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
|
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
|
@ -1974,6 +2118,72 @@ namespace tools
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool wallet_rpc_server::on_export_outputs(const wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS::request& req, wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS::response& res, epee::json_rpc::error& er)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (m_wallet->key_on_device())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||||
|
er.message = "command not supported by HW wallet";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
res.outputs_data_hex = epee::string_tools::buff_to_hex_nodelimer(m_wallet->export_outputs_to_str());
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool wallet_rpc_server::on_import_outputs(const wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS::request& req, wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS::response& res, epee::json_rpc::error& er)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (m_wallet->key_on_device())
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||||
|
er.message = "command not supported by HW wallet";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptonote::blobdata blob;
|
||||||
|
if (!epee::string_tools::parse_hexstr_to_binbuff(req.outputs_data_hex, blob))
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
|
||||||
|
er.message = "Failed to parse hex.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
res.num_imported = m_wallet->import_outputs_from_str(blob);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool wallet_rpc_server::on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er)
|
bool wallet_rpc_server::on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er)
|
||||||
{
|
{
|
||||||
if (!m_wallet) return not_open(er);
|
if (!m_wallet) return not_open(er);
|
||||||
|
|
|
@ -84,6 +84,8 @@ namespace tools
|
||||||
MAP_JON_RPC_WE("getheight", on_getheight, wallet_rpc::COMMAND_RPC_GET_HEIGHT)
|
MAP_JON_RPC_WE("getheight", on_getheight, wallet_rpc::COMMAND_RPC_GET_HEIGHT)
|
||||||
MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
|
MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
|
||||||
MAP_JON_RPC_WE("transfer_split", on_transfer_split, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT)
|
MAP_JON_RPC_WE("transfer_split", on_transfer_split, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT)
|
||||||
|
MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER)
|
||||||
|
MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER)
|
||||||
MAP_JON_RPC_WE("sweep_dust", on_sweep_dust, wallet_rpc::COMMAND_RPC_SWEEP_DUST)
|
MAP_JON_RPC_WE("sweep_dust", on_sweep_dust, wallet_rpc::COMMAND_RPC_SWEEP_DUST)
|
||||||
MAP_JON_RPC_WE("sweep_unmixable", on_sweep_dust, wallet_rpc::COMMAND_RPC_SWEEP_DUST)
|
MAP_JON_RPC_WE("sweep_unmixable", 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_all", on_sweep_all, wallet_rpc::COMMAND_RPC_SWEEP_ALL)
|
||||||
|
@ -114,6 +116,8 @@ namespace tools
|
||||||
MAP_JON_RPC_WE("get_transfer_by_txid", on_get_transfer_by_txid, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID)
|
MAP_JON_RPC_WE("get_transfer_by_txid", on_get_transfer_by_txid, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID)
|
||||||
MAP_JON_RPC_WE("sign", on_sign, wallet_rpc::COMMAND_RPC_SIGN)
|
MAP_JON_RPC_WE("sign", on_sign, wallet_rpc::COMMAND_RPC_SIGN)
|
||||||
MAP_JON_RPC_WE("verify", on_verify, wallet_rpc::COMMAND_RPC_VERIFY)
|
MAP_JON_RPC_WE("verify", on_verify, wallet_rpc::COMMAND_RPC_VERIFY)
|
||||||
|
MAP_JON_RPC_WE("export_outputs", on_export_outputs, wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS)
|
||||||
|
MAP_JON_RPC_WE("import_outputs", on_import_outputs, wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS)
|
||||||
MAP_JON_RPC_WE("export_key_images", on_export_key_images, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES)
|
MAP_JON_RPC_WE("export_key_images", on_export_key_images, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES)
|
||||||
MAP_JON_RPC_WE("import_key_images", on_import_key_images, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES)
|
MAP_JON_RPC_WE("import_key_images", on_import_key_images, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES)
|
||||||
MAP_JON_RPC_WE("make_uri", on_make_uri, wallet_rpc::COMMAND_RPC_MAKE_URI)
|
MAP_JON_RPC_WE("make_uri", on_make_uri, wallet_rpc::COMMAND_RPC_MAKE_URI)
|
||||||
|
@ -154,6 +158,8 @@ namespace tools
|
||||||
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 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(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_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_sign_transfer(const wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::response& res, epee::json_rpc::error& er);
|
||||||
|
bool on_submit_transfer(const wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::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_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_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_sweep_single(const wallet_rpc::COMMAND_RPC_SWEEP_SINGLE::request& req, wallet_rpc::COMMAND_RPC_SWEEP_SINGLE::response& res, epee::json_rpc::error& er);
|
||||||
|
@ -182,6 +188,8 @@ namespace tools
|
||||||
bool on_get_transfer_by_txid(const wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::response& res, epee::json_rpc::error& er);
|
bool on_get_transfer_by_txid(const wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::response& res, epee::json_rpc::error& er);
|
||||||
bool on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er);
|
bool on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er);
|
||||||
bool on_verify(const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response& res, epee::json_rpc::error& er);
|
bool on_verify(const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response& res, epee::json_rpc::error& er);
|
||||||
|
bool on_export_outputs(const wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS::request& req, wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS::response& res, epee::json_rpc::error& er);
|
||||||
|
bool on_import_outputs(const wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS::request& req, wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS::response& res, epee::json_rpc::error& er);
|
||||||
bool on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er);
|
bool on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er);
|
||||||
bool on_import_key_images(const wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er);
|
bool on_import_key_images(const wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er);
|
||||||
bool on_make_uri(const wallet_rpc::COMMAND_RPC_MAKE_URI::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI::response& res, epee::json_rpc::error& er);
|
bool on_make_uri(const wallet_rpc::COMMAND_RPC_MAKE_URI::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI::response& res, epee::json_rpc::error& er);
|
||||||
|
@ -217,7 +225,7 @@ namespace tools
|
||||||
|
|
||||||
template<typename Ts, typename Tu>
|
template<typename Ts, typename Tu>
|
||||||
bool fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector,
|
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,
|
bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, std::string &unsigned_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);
|
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;
|
wallet2 *m_wallet;
|
||||||
|
|
|
@ -419,6 +419,7 @@ namespace wallet_rpc
|
||||||
std::string tx_blob;
|
std::string tx_blob;
|
||||||
std::string tx_metadata;
|
std::string tx_metadata;
|
||||||
std::string multisig_txset;
|
std::string multisig_txset;
|
||||||
|
std::string unsigned_txset;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(tx_hash)
|
KV_SERIALIZE(tx_hash)
|
||||||
|
@ -429,6 +430,7 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE(tx_blob)
|
KV_SERIALIZE(tx_blob)
|
||||||
KV_SERIALIZE(tx_metadata)
|
KV_SERIALIZE(tx_metadata)
|
||||||
KV_SERIALIZE(multisig_txset)
|
KV_SERIALIZE(multisig_txset)
|
||||||
|
KV_SERIALIZE(unsigned_txset)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -484,6 +486,7 @@ namespace wallet_rpc
|
||||||
std::list<std::string> tx_blob_list;
|
std::list<std::string> tx_blob_list;
|
||||||
std::list<std::string> tx_metadata_list;
|
std::list<std::string> tx_metadata_list;
|
||||||
std::string multisig_txset;
|
std::string multisig_txset;
|
||||||
|
std::string unsigned_txset;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(tx_hash_list)
|
KV_SERIALIZE(tx_hash_list)
|
||||||
|
@ -493,6 +496,55 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE(tx_blob_list)
|
KV_SERIALIZE(tx_blob_list)
|
||||||
KV_SERIALIZE(tx_metadata_list)
|
KV_SERIALIZE(tx_metadata_list)
|
||||||
KV_SERIALIZE(multisig_txset)
|
KV_SERIALIZE(multisig_txset)
|
||||||
|
KV_SERIALIZE(unsigned_txset)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_SIGN_TRANSFER
|
||||||
|
{
|
||||||
|
struct request
|
||||||
|
{
|
||||||
|
std::string unsigned_txset;
|
||||||
|
bool export_raw;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(unsigned_txset)
|
||||||
|
KV_SERIALIZE_OPT(export_raw, false)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response
|
||||||
|
{
|
||||||
|
std::string signed_txset;
|
||||||
|
std::list<std::string> tx_hash_list;
|
||||||
|
std::list<std::string> tx_raw_list;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(signed_txset)
|
||||||
|
KV_SERIALIZE(tx_hash_list)
|
||||||
|
KV_SERIALIZE(tx_raw_list)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_SUBMIT_TRANSFER
|
||||||
|
{
|
||||||
|
struct request
|
||||||
|
{
|
||||||
|
std::string tx_data_hex;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(tx_data_hex)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response
|
||||||
|
{
|
||||||
|
std::list<std::string> tx_hash_list;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(tx_hash_list)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -532,6 +584,7 @@ namespace wallet_rpc
|
||||||
std::list<std::string> tx_blob_list;
|
std::list<std::string> tx_blob_list;
|
||||||
std::list<std::string> tx_metadata_list;
|
std::list<std::string> tx_metadata_list;
|
||||||
std::string multisig_txset;
|
std::string multisig_txset;
|
||||||
|
std::string unsigned_txset;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(tx_hash_list)
|
KV_SERIALIZE(tx_hash_list)
|
||||||
|
@ -541,6 +594,7 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE(tx_blob_list)
|
KV_SERIALIZE(tx_blob_list)
|
||||||
KV_SERIALIZE(tx_metadata_list)
|
KV_SERIALIZE(tx_metadata_list)
|
||||||
KV_SERIALIZE(multisig_txset)
|
KV_SERIALIZE(multisig_txset)
|
||||||
|
KV_SERIALIZE(unsigned_txset)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -598,6 +652,7 @@ namespace wallet_rpc
|
||||||
std::list<std::string> tx_blob_list;
|
std::list<std::string> tx_blob_list;
|
||||||
std::list<std::string> tx_metadata_list;
|
std::list<std::string> tx_metadata_list;
|
||||||
std::string multisig_txset;
|
std::string multisig_txset;
|
||||||
|
std::string unsigned_txset;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(tx_hash_list)
|
KV_SERIALIZE(tx_hash_list)
|
||||||
|
@ -607,6 +662,7 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE(tx_blob_list)
|
KV_SERIALIZE(tx_blob_list)
|
||||||
KV_SERIALIZE(tx_metadata_list)
|
KV_SERIALIZE(tx_metadata_list)
|
||||||
KV_SERIALIZE(multisig_txset)
|
KV_SERIALIZE(multisig_txset)
|
||||||
|
KV_SERIALIZE(unsigned_txset)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -651,6 +707,7 @@ namespace wallet_rpc
|
||||||
std::string tx_blob;
|
std::string tx_blob;
|
||||||
std::string tx_metadata;
|
std::string tx_metadata;
|
||||||
std::string multisig_txset;
|
std::string multisig_txset;
|
||||||
|
std::string unsigned_txset;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(tx_hash)
|
KV_SERIALIZE(tx_hash)
|
||||||
|
@ -660,6 +717,7 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE(tx_blob)
|
KV_SERIALIZE(tx_blob)
|
||||||
KV_SERIALIZE(tx_metadata)
|
KV_SERIALIZE(tx_metadata)
|
||||||
KV_SERIALIZE(multisig_txset)
|
KV_SERIALIZE(multisig_txset)
|
||||||
|
KV_SERIALIZE(unsigned_txset)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1364,6 +1422,45 @@ namespace wallet_rpc
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_EXPORT_OUTPUTS
|
||||||
|
{
|
||||||
|
struct request
|
||||||
|
{
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response
|
||||||
|
{
|
||||||
|
std::string outputs_data_hex;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(outputs_data_hex);
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_IMPORT_OUTPUTS
|
||||||
|
{
|
||||||
|
struct request
|
||||||
|
{
|
||||||
|
std::string outputs_data_hex;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(outputs_data_hex);
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response
|
||||||
|
{
|
||||||
|
uint64_t num_imported;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(num_imported);
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct COMMAND_RPC_EXPORT_KEY_IMAGES
|
struct COMMAND_RPC_EXPORT_KEY_IMAGES
|
||||||
{
|
{
|
||||||
struct request
|
struct request
|
||||||
|
|
|
@ -69,3 +69,7 @@
|
||||||
#define WALLET_RPC_ERROR_CODE_MULTISIG_SUBMISSION -36
|
#define WALLET_RPC_ERROR_CODE_MULTISIG_SUBMISSION -36
|
||||||
#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_MONEY -37
|
#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_MONEY -37
|
||||||
#define WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION -38
|
#define WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION -38
|
||||||
|
#define WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA -39
|
||||||
|
#define WALLET_RPC_ERROR_CODE_BAD_SIGNED_TX_DATA -40
|
||||||
|
#define WALLET_RPC_ERROR_CODE_SIGNED_SUBMISSION -41
|
||||||
|
#define WALLET_RPC_ERROR_CODE_SIGN_UNSIGNED -42
|
||||||
|
|
Loading…
Reference in a new issue