wallet: encrypt (un)signed tx, also optionally save unencrypted raw tx hexstr
This commit is contained in:
parent
86e9de588c
commit
d74336d5c9
|
@ -3432,12 +3432,18 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
|
||||||
fail_msg_writer() << tr("This is a watch only wallet");
|
fail_msg_writer() << tr("This is a watch only wallet");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (args_.size() > 1 || (args_.size() == 1 && args_[0] != "export"))
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("usage: sign_transfer [export]");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
|
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
|
||||||
|
const bool export_raw = args_.size() == 1;
|
||||||
|
|
||||||
std::vector<tools::wallet2::pending_tx> ptx;
|
std::vector<tools::wallet2::pending_tx> ptx;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool r = m_wallet->sign_tx("unsigned_monero_tx", "signed_monero_tx", ptx, [&](const tools::wallet2::unsigned_tx_set &tx){ return accept_loaded_tx(tx); });
|
bool r = m_wallet->sign_tx("unsigned_monero_tx", "signed_monero_tx", ptx, [&](const tools::wallet2::unsigned_tx_set &tx){ return accept_loaded_tx(tx); }, export_raw);
|
||||||
if (!r)
|
if (!r)
|
||||||
{
|
{
|
||||||
fail_msg_writer() << tr("Failed to sign transaction");
|
fail_msg_writer() << tr("Failed to sign transaction");
|
||||||
|
@ -3458,6 +3464,17 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
|
||||||
txids_as_text += epee::string_tools::pod_to_hex(get_transaction_hash(t.tx));
|
txids_as_text += epee::string_tools::pod_to_hex(get_transaction_hash(t.tx));
|
||||||
}
|
}
|
||||||
success_msg_writer(true) << tr("Transaction successfully signed to file ") << "signed_monero_tx" << ", txid " << txids_as_text;
|
success_msg_writer(true) << tr("Transaction successfully signed to file ") << "signed_monero_tx" << ", txid " << txids_as_text;
|
||||||
|
if (export_raw)
|
||||||
|
{
|
||||||
|
std::string rawfiles_as_text;
|
||||||
|
for (size_t i = 0; i < ptx.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
rawfiles_as_text += ", ";
|
||||||
|
rawfiles_as_text += "signed_monero_tx_raw" + (ptx.size() == 1 ? "" : ("_" + std::to_string(i)));
|
||||||
|
}
|
||||||
|
success_msg_writer(true) << tr("Transaction raw hex data exported to ") << rawfiles_as_text;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -81,8 +81,8 @@ using namespace cryptonote;
|
||||||
// arbitrary, used to generate different hashes from the same input
|
// arbitrary, used to generate different hashes from the same input
|
||||||
#define CHACHA8_KEY_TAIL 0x8c
|
#define CHACHA8_KEY_TAIL 0x8c
|
||||||
|
|
||||||
#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003"
|
#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\004"
|
||||||
#define SIGNED_TX_PREFIX "Monero signed tx set\003"
|
#define SIGNED_TX_PREFIX "Monero signed tx set\004"
|
||||||
|
|
||||||
#define RECENT_OUTPUT_RATIO (0.5) // 50% of outputs are from the recent zone
|
#define RECENT_OUTPUT_RATIO (0.5) // 50% of outputs are from the recent zone
|
||||||
#define RECENT_OUTPUT_ZONE ((time_t)(1.8 * 86400)) // last 1.8 day makes up the recent zone (taken from monerolink.pdf, Miller et al)
|
#define RECENT_OUTPUT_ZONE ((time_t)(1.8 * 86400)) // last 1.8 day makes up the recent zone (taken from monerolink.pdf, Miller et al)
|
||||||
|
@ -3270,7 +3270,8 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_PRINT_L2("Saving unsigned tx data: " << oss.str());
|
LOG_PRINT_L2("Saving unsigned tx data: " << oss.str());
|
||||||
return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + 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);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs)
|
bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs)
|
||||||
|
@ -3288,22 +3289,55 @@ 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;
|
||||||
}
|
}
|
||||||
const size_t magiclen = strlen(UNSIGNED_TX_PREFIX);
|
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_filename);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
s = s.substr(magiclen);
|
s = s.substr(magiclen);
|
||||||
try
|
const char version = s[0];
|
||||||
|
s = s.substr(1);
|
||||||
|
if (version == '\003')
|
||||||
{
|
{
|
||||||
std::istringstream iss(s);
|
try
|
||||||
boost::archive::portable_binary_iarchive ar(iss);
|
{
|
||||||
ar >> exported_txs;
|
std::istringstream iss(s);
|
||||||
|
boost::archive::portable_binary_iarchive ar(iss);
|
||||||
|
ar >> exported_txs;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to parse data from " << unsigned_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
else if (version == '\004')
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to parse data from " << unsigned_filename);
|
try
|
||||||
|
{
|
||||||
|
s = decrypt_with_view_secret_key(s);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::istringstream iss(s);
|
||||||
|
boost::archive::portable_binary_iarchive ar(iss);
|
||||||
|
ar >> exported_txs;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to parse data from " << unsigned_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to decrypt " << unsigned_filename << ": " << e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Unsupported version in " << unsigned_filename);
|
||||||
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");
|
||||||
|
@ -3311,7 +3345,7 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, std::function<bool(const unsigned_tx_set&)> accept_func)
|
bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, std::function<bool(const unsigned_tx_set&)> accept_func, bool export_raw)
|
||||||
{
|
{
|
||||||
unsigned_tx_set exported_txs;
|
unsigned_tx_set exported_txs;
|
||||||
if(!load_unsigned_tx(unsigned_filename, exported_txs))
|
if(!load_unsigned_tx(unsigned_filename, exported_txs))
|
||||||
|
@ -3322,11 +3356,11 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s
|
||||||
LOG_PRINT_L1("Transactions rejected by callback");
|
LOG_PRINT_L1("Transactions rejected by callback");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return sign_tx(exported_txs, signed_filename, txs);
|
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 wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, bool export_raw)
|
||||||
{
|
{
|
||||||
import_outputs(exported_txs.transfers);
|
import_outputs(exported_txs.transfers);
|
||||||
|
|
||||||
|
@ -3399,8 +3433,28 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_PRINT_L3("Saving signed tx data: " << oss.str());
|
LOG_PRINT_L3("Saving signed tx data (with encryption): " << oss.str());
|
||||||
return epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + 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))
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to save file to " << signed_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// export signed raw tx without encryption
|
||||||
|
if (export_raw)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < signed_txes.ptx.size(); ++i)
|
||||||
|
{
|
||||||
|
std::string tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(signed_txes.ptx[i].tx));
|
||||||
|
std::string raw_filename = signed_filename + "_raw" + (signed_txes.ptx.size() == 1 ? "" : ("_" + std::to_string(i)));
|
||||||
|
if (!epee::file_io_utils::save_string_to_file(raw_filename, tx_as_hex))
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to save file to " << raw_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
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)
|
||||||
|
@ -3420,22 +3474,55 @@ 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;
|
||||||
}
|
}
|
||||||
const size_t magiclen = strlen(SIGNED_TX_PREFIX);
|
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_filename);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
s = s.substr(magiclen);
|
s = s.substr(magiclen);
|
||||||
try
|
const char version = s[0];
|
||||||
|
s = s.substr(1);
|
||||||
|
if (version == '\003')
|
||||||
{
|
{
|
||||||
std::istringstream iss(s);
|
try
|
||||||
boost::archive::portable_binary_iarchive ar(iss);
|
{
|
||||||
ar >> signed_txs;
|
std::istringstream iss(s);
|
||||||
|
boost::archive::portable_binary_iarchive ar(iss);
|
||||||
|
ar >> signed_txs;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to parse data from " << signed_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
else if (version == '\004')
|
||||||
{
|
{
|
||||||
LOG_PRINT_L0("Failed to parse data from " << signed_filename);
|
try
|
||||||
|
{
|
||||||
|
s = decrypt_with_view_secret_key(s);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::istringstream iss(s);
|
||||||
|
boost::archive::portable_binary_iarchive ar(iss);
|
||||||
|
ar >> signed_txs;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to parse decrypted data from " << signed_filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Failed to decrypt " << signed_filename << ": " << e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_PRINT_L0("Unsupported version in " << signed_filename);
|
||||||
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");
|
||||||
|
|
|
@ -456,9 +456,9 @@ namespace tools
|
||||||
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);
|
bool save_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename);
|
||||||
// load unsigned tx from file and sign it. Takes confirmation callback as argument. Used by the cli wallet
|
// load unsigned tx from file and sign it. Takes confirmation callback as argument. Used by the cli wallet
|
||||||
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 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 sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, bool export_raw = false);
|
||||||
// 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);
|
bool load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs);
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue