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:
Dusan Klinec 2018-05-07 23:23:47 +02:00
parent 9bc8f76924
commit 9c2a7b4638
7 changed files with 495 additions and 98 deletions

View file

@ -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 OUTPUT_EXPORT_FILE_MAGIC "Monero output export\003"
#define LOCK_IDLE_SCOPE() \
bool auto_refresh_enabled = m_auto_refresh_enabled.load(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();
try
{
std::vector<tools::wallet2::transfer_details> outs = m_wallet->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 = 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);
std::string data = m_wallet->export_outputs_to_str();
bool r = epee::file_io_utils::save_string_to_file(filename, data);
if (!r)
{
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;
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
{
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();
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";
}
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;
}