wallet2: only export necessary outputs and key images
and disable annoying test that requires ridiculous amounts of skullduggery every time some format changes
This commit is contained in:
parent
769ae42a7b
commit
8d71b2b1b3
|
@ -212,9 +212,10 @@ namespace trezor {
|
||||||
tools::wallet2::signed_tx_set & signed_tx,
|
tools::wallet2::signed_tx_set & signed_tx,
|
||||||
hw::tx_aux_data & aux_data)
|
hw::tx_aux_data & aux_data)
|
||||||
{
|
{
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(unsigned_tx.transfers.first == 0, "Unsuported non zero offset");
|
||||||
size_t num_tx = unsigned_tx.txes.size();
|
size_t num_tx = unsigned_tx.txes.size();
|
||||||
signed_tx.key_images.clear();
|
signed_tx.key_images.clear();
|
||||||
signed_tx.key_images.resize(unsigned_tx.transfers.size());
|
signed_tx.key_images.resize(unsigned_tx.transfers.second.size());
|
||||||
|
|
||||||
for(size_t tx_idx = 0; tx_idx < num_tx; ++tx_idx) {
|
for(size_t tx_idx = 0; tx_idx < num_tx; ++tx_idx) {
|
||||||
std::shared_ptr<protocol::tx::Signer> signer;
|
std::shared_ptr<protocol::tx::Signer> signer;
|
||||||
|
|
|
@ -6105,8 +6105,8 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
|
||||||
bool simple_wallet::accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs)
|
bool simple_wallet::accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs)
|
||||||
{
|
{
|
||||||
std::string extra_message;
|
std::string extra_message;
|
||||||
if (!txs.transfers.empty())
|
if (!txs.transfers.second.empty())
|
||||||
extra_message = (boost::format("%u outputs to import. ") % (unsigned)txs.transfers.size()).str();
|
extra_message = (boost::format("%u outputs to import. ") % (unsigned)txs.transfers.second.size()).str();
|
||||||
return accept_loaded_tx([&txs](){return txs.txes.size();}, [&txs](size_t n)->const tools::wallet2::tx_construction_data&{return txs.txes[n];}, extra_message);
|
return accept_loaded_tx([&txs](){return txs.txes.size();}, [&txs](size_t n)->const tools::wallet2::tx_construction_data&{return txs.txes[n];}, extra_message);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -113,11 +113,11 @@ using namespace cryptonote;
|
||||||
#define SUBADDRESS_LOOKAHEAD_MAJOR 50
|
#define SUBADDRESS_LOOKAHEAD_MAJOR 50
|
||||||
#define SUBADDRESS_LOOKAHEAD_MINOR 200
|
#define SUBADDRESS_LOOKAHEAD_MINOR 200
|
||||||
|
|
||||||
#define KEY_IMAGE_EXPORT_FILE_MAGIC "Monero key image export\002"
|
#define KEY_IMAGE_EXPORT_FILE_MAGIC "Monero key image export\003"
|
||||||
|
|
||||||
#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 OUTPUT_EXPORT_FILE_MAGIC "Monero output export\004"
|
||||||
|
|
||||||
#define SEGREGATION_FORK_HEIGHT 99999999
|
#define SEGREGATION_FORK_HEIGHT 99999999
|
||||||
#define TESTNET_SEGREGATION_FORK_HEIGHT 99999999
|
#define TESTNET_SEGREGATION_FORK_HEIGHT 99999999
|
||||||
|
@ -1606,6 +1606,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||||
td.m_txid = txid;
|
td.m_txid = txid;
|
||||||
td.m_key_image = tx_scan_info[o].ki;
|
td.m_key_image = tx_scan_info[o].ki;
|
||||||
td.m_key_image_known = !m_watch_only && !m_multisig;
|
td.m_key_image_known = !m_watch_only && !m_multisig;
|
||||||
|
td.m_key_image_requested = false;
|
||||||
td.m_key_image_partial = m_multisig;
|
td.m_key_image_partial = m_multisig;
|
||||||
td.m_amount = amount;
|
td.m_amount = amount;
|
||||||
td.m_pk_index = pk_index - 1;
|
td.m_pk_index = pk_index - 1;
|
||||||
|
@ -5466,7 +5467,7 @@ std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) c
|
||||||
txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
|
txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
|
||||||
}
|
}
|
||||||
|
|
||||||
txs.transfers = m_transfers;
|
txs.transfers = export_outputs();
|
||||||
// save as binary
|
// save as binary
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
boost::archive::portable_binary_oarchive ar(oss);
|
boost::archive::portable_binary_oarchive ar(oss);
|
||||||
|
@ -7952,6 +7953,7 @@ void wallet2::light_wallet_get_unspent_outs()
|
||||||
|
|
||||||
td.m_key_image = unspent_key_image;
|
td.m_key_image = unspent_key_image;
|
||||||
td.m_key_image_known = !m_watch_only && !m_multisig;
|
td.m_key_image_known = !m_watch_only && !m_multisig;
|
||||||
|
td.m_key_image_requested = false;
|
||||||
td.m_key_image_partial = m_multisig;
|
td.m_key_image_partial = m_multisig;
|
||||||
td.m_amount = o.amount;
|
td.m_amount = o.amount;
|
||||||
td.m_pk_index = 0;
|
td.m_pk_index = 0;
|
||||||
|
@ -9125,7 +9127,7 @@ void wallet2::cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_
|
||||||
{
|
{
|
||||||
txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
|
txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
|
||||||
}
|
}
|
||||||
txs.transfers = m_transfers;
|
txs.transfers = std::make_pair(0, m_transfers);
|
||||||
|
|
||||||
auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
|
auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
|
||||||
CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
|
CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
|
||||||
|
@ -9156,7 +9158,7 @@ uint64_t wallet2::cold_key_image_sync(uint64_t &spent, uint64_t &unspent) {
|
||||||
|
|
||||||
dev_cold->ki_sync(&wallet_shim, m_transfers, ski);
|
dev_cold->ki_sync(&wallet_shim, m_transfers, ski);
|
||||||
|
|
||||||
return import_key_images(ski, spent, unspent);
|
return import_key_images(ski, 0, spent, unspent);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void wallet2::get_hard_fork_info(uint8_t version, uint64_t &earliest_height) const
|
void wallet2::get_hard_fork_info(uint8_t version, uint64_t &earliest_height) const
|
||||||
|
@ -10519,15 +10521,21 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
|
||||||
bool wallet2::export_key_images(const std::string &filename) const
|
bool wallet2::export_key_images(const std::string &filename) const
|
||||||
{
|
{
|
||||||
PERF_TIMER(export_key_images);
|
PERF_TIMER(export_key_images);
|
||||||
std::vector<std::pair<crypto::key_image, crypto::signature>> ski = export_key_images();
|
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images();
|
||||||
std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC));
|
std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC));
|
||||||
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
|
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
|
||||||
|
const uint32_t offset = ski.first;
|
||||||
|
|
||||||
std::string data;
|
std::string data;
|
||||||
data.reserve(ski.size() * (sizeof(crypto::key_image) + sizeof(crypto::signature)) + 2 * sizeof(crypto::public_key));
|
data.reserve(4 + ski.second.size() * (sizeof(crypto::key_image) + sizeof(crypto::signature)) + 2 * sizeof(crypto::public_key));
|
||||||
|
data.resize(4);
|
||||||
|
data[0] = offset & 0xff;
|
||||||
|
data[1] = (offset >> 8) & 0xff;
|
||||||
|
data[2] = (offset >> 16) & 0xff;
|
||||||
|
data[3] = (offset >> 24) & 0xff;
|
||||||
data += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
|
data += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key));
|
||||||
data += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
|
data += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key));
|
||||||
for (const auto &i: ski)
|
for (const auto &i: ski.second)
|
||||||
{
|
{
|
||||||
data += std::string((const char *)&i.first, sizeof(crypto::key_image));
|
data += std::string((const char *)&i.first, sizeof(crypto::key_image));
|
||||||
data += std::string((const char *)&i.second, sizeof(crypto::signature));
|
data += std::string((const char *)&i.second, sizeof(crypto::signature));
|
||||||
|
@ -10540,13 +10548,17 @@ bool wallet2::export_key_images(const std::string &filename) const
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key_images() const
|
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images() const
|
||||||
{
|
{
|
||||||
PERF_TIMER(export_key_images_raw);
|
PERF_TIMER(export_key_images_raw);
|
||||||
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
|
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
|
||||||
|
|
||||||
ski.reserve(m_transfers.size());
|
size_t offset = 0;
|
||||||
for (size_t n = 0; n < m_transfers.size(); ++n)
|
while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_requested)
|
||||||
|
++offset;
|
||||||
|
|
||||||
|
ski.reserve(m_transfers.size() - offset);
|
||||||
|
for (size_t n = offset; n < m_transfers.size(); ++n)
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[n];
|
const transfer_details &td = m_transfers[n];
|
||||||
|
|
||||||
|
@ -10590,7 +10602,7 @@ std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key
|
||||||
|
|
||||||
ski.push_back(std::make_pair(td.m_key_image, signature));
|
ski.push_back(std::make_pair(td.m_key_image, signature));
|
||||||
}
|
}
|
||||||
return ski;
|
return std::make_pair(offset, ski);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent)
|
uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent)
|
||||||
|
@ -10617,15 +10629,17 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent
|
||||||
THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt ") + filename + ": " + e.what());
|
THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Failed to decrypt ") + filename + ": " + e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t headerlen = 2 * sizeof(crypto::public_key);
|
const size_t headerlen = 4 + 2 * sizeof(crypto::public_key);
|
||||||
THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, std::string("Bad data size from file ") + filename);
|
THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, std::string("Bad data size from file ") + filename);
|
||||||
const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0];
|
const uint32_t offset = (uint8_t)data[0] | (((uint8_t)data[1]) << 8) | (((uint8_t)data[2]) << 16) | (((uint8_t)data[3]) << 24);
|
||||||
const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)];
|
const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[4];
|
||||||
|
const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[4 + sizeof(crypto::public_key)];
|
||||||
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
|
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)
|
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( "Key images from ") + filename + " are for a different account");
|
THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string( "Key images from ") + filename + " are for a different account");
|
||||||
}
|
}
|
||||||
|
THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Offset larger than known outputs");
|
||||||
|
|
||||||
const size_t record_size = sizeof(crypto::key_image) + sizeof(crypto::signature);
|
const size_t record_size = sizeof(crypto::key_image) + sizeof(crypto::signature);
|
||||||
THROW_WALLET_EXCEPTION_IF((data.size() - headerlen) % record_size,
|
THROW_WALLET_EXCEPTION_IF((data.size() - headerlen) % record_size,
|
||||||
|
@ -10642,20 +10656,21 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent
|
||||||
ski.push_back(std::make_pair(key_image, signature));
|
ski.push_back(std::make_pair(key_image, signature));
|
||||||
}
|
}
|
||||||
|
|
||||||
return import_key_images(ski, spent, unspent);
|
return import_key_images(ski, offset, spent, unspent);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent)
|
uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent)
|
||||||
{
|
{
|
||||||
PERF_TIMER(import_key_images_lots);
|
PERF_TIMER(import_key_images_lots);
|
||||||
COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
|
COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
|
||||||
COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
|
COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
|
||||||
|
|
||||||
THROW_WALLET_EXCEPTION_IF(signed_key_images.size() > m_transfers.size(), error::wallet_internal_error,
|
THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Offset larger than known outputs");
|
||||||
|
THROW_WALLET_EXCEPTION_IF(signed_key_images.size() > m_transfers.size() - offset, error::wallet_internal_error,
|
||||||
"The blockchain is out of date compared to the signed key images");
|
"The blockchain is out of date compared to the signed key images");
|
||||||
|
|
||||||
if (signed_key_images.empty())
|
if (signed_key_images.empty() && offset == 0)
|
||||||
{
|
{
|
||||||
spent = 0;
|
spent = 0;
|
||||||
unspent = 0;
|
unspent = 0;
|
||||||
|
@ -10667,7 +10682,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
PERF_TIMER_START(import_key_images_A);
|
PERF_TIMER_START(import_key_images_A);
|
||||||
for (size_t n = 0; n < signed_key_images.size(); ++n)
|
for (size_t n = 0; n < signed_key_images.size(); ++n)
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[n];
|
const transfer_details &td = m_transfers[n + offset];
|
||||||
const crypto::key_image &key_image = signed_key_images[n].first;
|
const crypto::key_image &key_image = signed_key_images[n].first;
|
||||||
const crypto::signature &signature = signed_key_images[n].second;
|
const crypto::signature &signature = signed_key_images[n].second;
|
||||||
|
|
||||||
|
@ -10683,11 +10698,11 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
std::vector<const crypto::public_key*> pkeys;
|
std::vector<const crypto::public_key*> pkeys;
|
||||||
pkeys.push_back(&pkey);
|
pkeys.push_back(&pkey);
|
||||||
THROW_WALLET_EXCEPTION_IF(!(rct::scalarmultKey(rct::ki2rct(key_image), rct::curveOrder()) == rct::identity()),
|
THROW_WALLET_EXCEPTION_IF(!(rct::scalarmultKey(rct::ki2rct(key_image), rct::curveOrder()) == rct::identity()),
|
||||||
error::wallet_internal_error, "Key image out of validity domain: input " + boost::lexical_cast<std::string>(n) + "/"
|
error::wallet_internal_error, "Key image out of validity domain: input " + boost::lexical_cast<std::string>(n + offset) + "/"
|
||||||
+ boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image));
|
+ boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image));
|
||||||
|
|
||||||
THROW_WALLET_EXCEPTION_IF(!crypto::check_ring_signature((const crypto::hash&)key_image, key_image, pkeys, &signature),
|
THROW_WALLET_EXCEPTION_IF(!crypto::check_ring_signature((const crypto::hash&)key_image, key_image, pkeys, &signature),
|
||||||
error::signature_check_failed, boost::lexical_cast<std::string>(n) + "/"
|
error::signature_check_failed, boost::lexical_cast<std::string>(n + offset) + "/"
|
||||||
+ boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image)
|
+ boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image)
|
||||||
+ ", signature " + epee::string_tools::pod_to_hex(signature) + ", pubkey " + epee::string_tools::pod_to_hex(*pkeys[0]));
|
+ ", signature " + epee::string_tools::pod_to_hex(signature) + ", pubkey " + epee::string_tools::pod_to_hex(*pkeys[0]));
|
||||||
}
|
}
|
||||||
|
@ -10698,10 +10713,11 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
PERF_TIMER_START(import_key_images_B);
|
PERF_TIMER_START(import_key_images_B);
|
||||||
for (size_t n = 0; n < signed_key_images.size(); ++n)
|
for (size_t n = 0; n < signed_key_images.size(); ++n)
|
||||||
{
|
{
|
||||||
m_transfers[n].m_key_image = signed_key_images[n].first;
|
m_transfers[n + offset].m_key_image = signed_key_images[n].first;
|
||||||
m_key_images[m_transfers[n].m_key_image] = n;
|
m_key_images[m_transfers[n + offset].m_key_image] = n + offset;
|
||||||
m_transfers[n].m_key_image_known = true;
|
m_transfers[n + offset].m_key_image_known = true;
|
||||||
m_transfers[n].m_key_image_partial = false;
|
m_transfers[n + offset].m_key_image_requested = false;
|
||||||
|
m_transfers[n + offset].m_key_image_partial = false;
|
||||||
}
|
}
|
||||||
PERF_TIMER_STOP(import_key_images_B);
|
PERF_TIMER_STOP(import_key_images_B);
|
||||||
|
|
||||||
|
@ -10719,7 +10735,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size()));
|
std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size()));
|
||||||
for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n)
|
for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n)
|
||||||
{
|
{
|
||||||
transfer_details &td = m_transfers[n];
|
transfer_details &td = m_transfers[n + offset];
|
||||||
td.m_spent = daemon_resp.spent_status[n] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT;
|
td.m_spent = daemon_resp.spent_status[n] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10744,7 +10760,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
PERF_TIMER_START(import_key_images_D);
|
PERF_TIMER_START(import_key_images_D);
|
||||||
for(size_t i = 0; i < signed_key_images.size(); ++i)
|
for(size_t i = 0; i < signed_key_images.size(); ++i)
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[i];
|
const transfer_details &td = m_transfers[i + offset];
|
||||||
uint64_t amount = td.amount();
|
uint64_t amount = td.amount();
|
||||||
if (td.m_spent)
|
if (td.m_spent)
|
||||||
spent += amount;
|
spent += amount;
|
||||||
|
@ -10919,6 +10935,7 @@ bool wallet2::import_key_images(std::vector<crypto::key_image> key_images)
|
||||||
td.m_key_image = key_images[i];
|
td.m_key_image = key_images[i];
|
||||||
m_key_images[m_transfers[i].m_key_image] = i;
|
m_key_images[m_transfers[i].m_key_image] = i;
|
||||||
td.m_key_image_known = true;
|
td.m_key_image_known = true;
|
||||||
|
td.m_key_image_requested = false;
|
||||||
td.m_key_image_partial = false;
|
td.m_key_image_partial = false;
|
||||||
m_pub_keys[m_transfers[i].get_public_key()] = i;
|
m_pub_keys[m_transfers[i].get_public_key()] = i;
|
||||||
}
|
}
|
||||||
|
@ -10984,20 +11001,24 @@ void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vect
|
||||||
m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx);
|
m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
std::vector<tools::wallet2::transfer_details> wallet2::export_outputs() const
|
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs() const
|
||||||
{
|
{
|
||||||
PERF_TIMER(export_outputs);
|
PERF_TIMER(export_outputs);
|
||||||
std::vector<tools::wallet2::transfer_details> outs;
|
std::vector<tools::wallet2::transfer_details> outs;
|
||||||
|
|
||||||
outs.reserve(m_transfers.size());
|
size_t offset = 0;
|
||||||
for (size_t n = 0; n < m_transfers.size(); ++n)
|
while (offset < m_transfers.size() && m_transfers[offset].m_key_image_known)
|
||||||
|
++offset;
|
||||||
|
|
||||||
|
outs.reserve(m_transfers.size() - offset);
|
||||||
|
for (size_t n = offset; n < m_transfers.size(); ++n)
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[n];
|
const transfer_details &td = m_transfers[n];
|
||||||
|
|
||||||
outs.push_back(td);
|
outs.push_back(td);
|
||||||
}
|
}
|
||||||
|
|
||||||
return outs;
|
return std::make_pair(offset, outs);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
std::string wallet2::export_outputs_to_str() const
|
std::string wallet2::export_outputs_to_str() const
|
||||||
|
@ -11006,7 +11027,7 @@ std::string wallet2::export_outputs_to_str() const
|
||||||
|
|
||||||
std::stringstream oss;
|
std::stringstream oss;
|
||||||
boost::archive::portable_binary_oarchive ar(oss);
|
boost::archive::portable_binary_oarchive ar(oss);
|
||||||
ar << m_transfers;
|
ar << export_outputs();
|
||||||
|
|
||||||
std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC));
|
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;
|
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
|
||||||
|
@ -11018,20 +11039,27 @@ std::string wallet2::export_outputs_to_str() const
|
||||||
return magic + ciphertext;
|
return magic + ciphertext;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs)
|
size_t wallet2::import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs)
|
||||||
{
|
{
|
||||||
PERF_TIMER(import_outputs);
|
PERF_TIMER(import_outputs);
|
||||||
|
|
||||||
|
THROW_WALLET_EXCEPTION_IF(outputs.first > m_transfers.size(), error::wallet_internal_error,
|
||||||
|
"Imported outputs omit more outputs that we know of");
|
||||||
|
|
||||||
|
const size_t offset = outputs.first;
|
||||||
const size_t original_size = m_transfers.size();
|
const size_t original_size = m_transfers.size();
|
||||||
m_transfers.resize(outputs.size());
|
m_transfers.resize(offset + outputs.second.size());
|
||||||
for (size_t i = 0; i < outputs.size(); ++i)
|
for (size_t i = 0; i < offset; ++i)
|
||||||
|
m_transfers[i].m_key_image_requested = false;
|
||||||
|
for (size_t i = 0; i < outputs.second.size(); ++i)
|
||||||
{
|
{
|
||||||
transfer_details td = outputs[i];
|
transfer_details td = outputs.second[i];
|
||||||
|
|
||||||
// skip those we've already imported, or which have different data
|
// skip those we've already imported, or which have different data
|
||||||
if (i < original_size)
|
if (i + offset < original_size)
|
||||||
{
|
{
|
||||||
// compare the data used to create the key image below
|
// compare the data used to create the key image below
|
||||||
const transfer_details &org_td = m_transfers[i];
|
const transfer_details &org_td = m_transfers[i + offset];
|
||||||
if (!org_td.m_key_image_known)
|
if (!org_td.m_key_image_known)
|
||||||
goto process;
|
goto process;
|
||||||
#define CMPF(f) if (!(td.f == org_td.f)) goto process
|
#define CMPF(f) if (!(td.f == org_td.f)) goto process
|
||||||
|
@ -11043,7 +11071,7 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail
|
||||||
goto process;
|
goto process;
|
||||||
|
|
||||||
// copy anyway, since the comparison does not include ancillary fields which may have changed
|
// copy anyway, since the comparison does not include ancillary fields which may have changed
|
||||||
m_transfers[i] = std::move(td);
|
m_transfers[i + offset] = std::move(td);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11052,7 +11080,7 @@ process:
|
||||||
// the hot wallet wouldn't have known about key images (except if we already exported them)
|
// the hot wallet wouldn't have known about key images (except if we already exported them)
|
||||||
cryptonote::keypair in_ephemeral;
|
cryptonote::keypair in_ephemeral;
|
||||||
|
|
||||||
THROW_WALLET_EXCEPTION_IF(td.m_tx.vout.empty(), error::wallet_internal_error, "tx with no outputs at index " + boost::lexical_cast<std::string>(i));
|
THROW_WALLET_EXCEPTION_IF(td.m_tx.vout.empty(), error::wallet_internal_error, "tx with no outputs at index " + boost::lexical_cast<std::string>(i + offset));
|
||||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
|
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
|
||||||
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
|
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
|
||||||
|
|
||||||
|
@ -11063,13 +11091,14 @@ process:
|
||||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
|
||||||
expand_subaddresses(td.m_subaddr_index);
|
expand_subaddresses(td.m_subaddr_index);
|
||||||
td.m_key_image_known = true;
|
td.m_key_image_known = true;
|
||||||
|
td.m_key_image_requested = true;
|
||||||
td.m_key_image_partial = false;
|
td.m_key_image_partial = false;
|
||||||
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
|
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
|
||||||
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i));
|
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i + offset));
|
||||||
|
|
||||||
m_key_images[td.m_key_image] = i;
|
m_key_images[td.m_key_image] = i + offset;
|
||||||
m_pub_keys[td.get_public_key()] = i;
|
m_pub_keys[td.get_public_key()] = i + offset;
|
||||||
m_transfers[i] = std::move(td);
|
m_transfers[i + offset] = std::move(td);
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_transfers.size();
|
return m_transfers.size();
|
||||||
|
@ -11114,7 +11143,7 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st)
|
||||||
std::string body(data, headerlen);
|
std::string body(data, headerlen);
|
||||||
std::stringstream iss;
|
std::stringstream iss;
|
||||||
iss << body;
|
iss << body;
|
||||||
std::vector<tools::wallet2::transfer_details> outputs;
|
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boost::archive::portable_binary_iarchive ar(iss);
|
boost::archive::portable_binary_iarchive ar(iss);
|
||||||
|
@ -11306,6 +11335,7 @@ void wallet2::update_multisig_rescan_info(const std::vector<std::vector<rct::key
|
||||||
m_key_images.erase(td.m_key_image);
|
m_key_images.erase(td.m_key_image);
|
||||||
td.m_key_image = get_multisig_composite_key_image(n);
|
td.m_key_image = get_multisig_composite_key_image(n);
|
||||||
td.m_key_image_known = true;
|
td.m_key_image_known = true;
|
||||||
|
td.m_key_image_requested = false;
|
||||||
td.m_key_image_partial = false;
|
td.m_key_image_partial = false;
|
||||||
td.m_multisig_k = multisig_k[n];
|
td.m_multisig_k = multisig_k[n];
|
||||||
m_key_images[td.m_key_image] = n;
|
m_key_images[td.m_key_image] = n;
|
||||||
|
|
|
@ -247,6 +247,7 @@ namespace tools
|
||||||
uint64_t m_amount;
|
uint64_t m_amount;
|
||||||
bool m_rct;
|
bool m_rct;
|
||||||
bool m_key_image_known;
|
bool m_key_image_known;
|
||||||
|
bool m_key_image_requested;
|
||||||
size_t m_pk_index;
|
size_t m_pk_index;
|
||||||
cryptonote::subaddress_index m_subaddr_index;
|
cryptonote::subaddress_index m_subaddr_index;
|
||||||
bool m_key_image_partial;
|
bool m_key_image_partial;
|
||||||
|
@ -270,6 +271,7 @@ namespace tools
|
||||||
FIELD(m_amount)
|
FIELD(m_amount)
|
||||||
FIELD(m_rct)
|
FIELD(m_rct)
|
||||||
FIELD(m_key_image_known)
|
FIELD(m_key_image_known)
|
||||||
|
FIELD(m_key_image_requested)
|
||||||
FIELD(m_pk_index)
|
FIELD(m_pk_index)
|
||||||
FIELD(m_subaddr_index)
|
FIELD(m_subaddr_index)
|
||||||
FIELD(m_key_image_partial)
|
FIELD(m_key_image_partial)
|
||||||
|
@ -417,7 +419,7 @@ namespace tools
|
||||||
struct unsigned_tx_set
|
struct unsigned_tx_set
|
||||||
{
|
{
|
||||||
std::vector<tx_construction_data> txes;
|
std::vector<tx_construction_data> txes;
|
||||||
wallet2::transfer_container transfers;
|
std::pair<size_t, wallet2::transfer_container> transfers;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct signed_tx_set
|
struct signed_tx_set
|
||||||
|
@ -1071,9 +1073,9 @@ namespace tools
|
||||||
bool verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const;
|
bool verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const;
|
||||||
|
|
||||||
// Import/Export wallet data
|
// Import/Export wallet data
|
||||||
std::vector<tools::wallet2::transfer_details> export_outputs() const;
|
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> export_outputs() const;
|
||||||
std::string export_outputs_to_str() 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::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs);
|
||||||
size_t import_outputs_from_str(const std::string &outputs_st);
|
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);
|
||||||
|
@ -1081,8 +1083,8 @@ namespace tools
|
||||||
std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const;
|
std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const;
|
||||||
void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc);
|
void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc);
|
||||||
bool export_key_images(const std::string &filename) const;
|
bool export_key_images(const std::string &filename) const;
|
||||||
std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const;
|
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images() const;
|
||||||
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
|
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
|
||||||
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
|
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
|
||||||
bool import_key_images(std::vector<crypto::key_image> key_images);
|
bool import_key_images(std::vector<crypto::key_image> key_images);
|
||||||
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
|
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
|
||||||
|
@ -1396,7 +1398,7 @@ namespace tools
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
BOOST_CLASS_VERSION(tools::wallet2, 26)
|
BOOST_CLASS_VERSION(tools::wallet2, 26)
|
||||||
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 9)
|
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 10)
|
||||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
|
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
|
||||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
|
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
|
||||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
|
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
|
||||||
|
@ -1454,6 +1456,10 @@ namespace boost
|
||||||
x.m_multisig_k.clear();
|
x.m_multisig_k.clear();
|
||||||
x.m_multisig_info.clear();
|
x.m_multisig_info.clear();
|
||||||
}
|
}
|
||||||
|
if (ver < 10)
|
||||||
|
{
|
||||||
|
x.m_key_image_requested = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
|
@ -1535,6 +1541,12 @@ namespace boost
|
||||||
a & x.m_multisig_info;
|
a & x.m_multisig_info;
|
||||||
a & x.m_multisig_k;
|
a & x.m_multisig_k;
|
||||||
a & x.m_key_image_partial;
|
a & x.m_key_image_partial;
|
||||||
|
if (ver < 10)
|
||||||
|
{
|
||||||
|
initialize_transfer_details(a, x, ver);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a & x.m_key_image_requested;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
|
|
|
@ -2460,12 +2460,13 @@ namespace tools
|
||||||
if (!m_wallet) return not_open(er);
|
if (!m_wallet) return not_open(er);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::vector<std::pair<crypto::key_image, crypto::signature>> ski = m_wallet->export_key_images();
|
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images();
|
||||||
res.signed_key_images.resize(ski.size());
|
res.offset = ski.first;
|
||||||
for (size_t n = 0; n < ski.size(); ++n)
|
res.signed_key_images.resize(ski.second.size());
|
||||||
|
for (size_t n = 0; n < ski.second.size(); ++n)
|
||||||
{
|
{
|
||||||
res.signed_key_images[n].key_image = epee::string_tools::pod_to_hex(ski[n].first);
|
res.signed_key_images[n].key_image = epee::string_tools::pod_to_hex(ski.second[n].first);
|
||||||
res.signed_key_images[n].signature = epee::string_tools::pod_to_hex(ski[n].second);
|
res.signed_key_images[n].signature = epee::string_tools::pod_to_hex(ski.second[n].second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2518,7 +2519,7 @@ namespace tools
|
||||||
ski[n].second = *reinterpret_cast<const crypto::signature*>(bd.data());
|
ski[n].second = *reinterpret_cast<const crypto::signature*>(bd.data());
|
||||||
}
|
}
|
||||||
uint64_t spent = 0, unspent = 0;
|
uint64_t spent = 0, unspent = 0;
|
||||||
uint64_t height = m_wallet->import_key_images(ski, spent, unspent);
|
uint64_t height = m_wallet->import_key_images(ski, req.offset, spent, unspent);
|
||||||
res.spent = spent;
|
res.spent = spent;
|
||||||
res.unspent = unspent;
|
res.unspent = unspent;
|
||||||
res.height = height;
|
res.height = height;
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
// advance which version they will stop working with
|
// advance which version they will stop working with
|
||||||
// Don't go over 32767 for any of these
|
// Don't go over 32767 for any of these
|
||||||
#define WALLET_RPC_VERSION_MAJOR 1
|
#define WALLET_RPC_VERSION_MAJOR 1
|
||||||
#define WALLET_RPC_VERSION_MINOR 5
|
#define WALLET_RPC_VERSION_MINOR 6
|
||||||
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
|
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
|
||||||
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
|
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
|
||||||
namespace tools
|
namespace tools
|
||||||
|
@ -1579,9 +1579,11 @@ namespace wallet_rpc
|
||||||
|
|
||||||
struct response
|
struct response
|
||||||
{
|
{
|
||||||
|
uint32_t offset;
|
||||||
std::vector<signed_key_image> signed_key_images;
|
std::vector<signed_key_image> signed_key_images;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(offset);
|
||||||
KV_SERIALIZE(signed_key_images);
|
KV_SERIALIZE(signed_key_images);
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
|
@ -1602,9 +1604,11 @@ namespace wallet_rpc
|
||||||
|
|
||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
|
uint32_t offset;
|
||||||
std::vector<signed_key_image> signed_key_images;
|
std::vector<signed_key_image> signed_key_images;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE_OPT(offset, (uint32_t)0);
|
||||||
KV_SERIALIZE(signed_key_images);
|
KV_SERIALIZE(signed_key_images);
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
|
|
Binary file not shown.
|
@ -77,7 +77,7 @@ int ColdOutputsFuzzer::run(const std::string &filename)
|
||||||
s = std::string("\x01\x16serialization::archive") + s;
|
s = std::string("\x01\x16serialization::archive") + s;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::vector<tools::wallet2::transfer_details> outputs;
|
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
|
||||||
std::stringstream iss;
|
std::stringstream iss;
|
||||||
iss << s;
|
iss << s;
|
||||||
boost::archive::portable_binary_iarchive ar(iss);
|
boost::archive::portable_binary_iarchive ar(iss);
|
||||||
|
|
|
@ -908,9 +908,21 @@ TEST(Serialization, portability_outputs)
|
||||||
ASSERT_TRUE(td2.m_pk_index == 0);
|
ASSERT_TRUE(td2.m_pk_index == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct unsigned_tx_set
|
||||||
|
{
|
||||||
|
std::vector<tools::wallet2::tx_construction_data> txes;
|
||||||
|
tools::wallet2::transfer_container transfers;
|
||||||
|
};
|
||||||
|
template <class Archive>
|
||||||
|
inline void serialize(Archive &a, unsigned_tx_set &x, const boost::serialization::version_type ver)
|
||||||
|
{
|
||||||
|
a & x.txes;
|
||||||
|
a & x.transfers;
|
||||||
|
}
|
||||||
#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003"
|
#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003"
|
||||||
TEST(Serialization, portability_unsigned_tx)
|
TEST(Serialization, portability_unsigned_tx)
|
||||||
{
|
{
|
||||||
|
|
||||||
const boost::filesystem::path filename = unit_test::data_dir / "unsigned_monero_tx";
|
const boost::filesystem::path filename = unit_test::data_dir / "unsigned_monero_tx";
|
||||||
std::string s;
|
std::string s;
|
||||||
const cryptonote::network_type nettype = cryptonote::TESTNET;
|
const cryptonote::network_type nettype = cryptonote::TESTNET;
|
||||||
|
@ -918,7 +930,7 @@ TEST(Serialization, portability_unsigned_tx)
|
||||||
ASSERT_TRUE(r);
|
ASSERT_TRUE(r);
|
||||||
const size_t magiclen = strlen(UNSIGNED_TX_PREFIX);
|
const size_t magiclen = strlen(UNSIGNED_TX_PREFIX);
|
||||||
ASSERT_FALSE(strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen));
|
ASSERT_FALSE(strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen));
|
||||||
tools::wallet2::unsigned_tx_set exported_txs;
|
unsigned_tx_set exported_txs;
|
||||||
s = s.substr(magiclen);
|
s = s.substr(magiclen);
|
||||||
r = false;
|
r = false;
|
||||||
try
|
try
|
||||||
|
|
Loading…
Reference in New Issue