Merge pull request 'wallet: faster value conveyance via five various velocity advances' (#433) from wowario/wownero:pr8046 into master

Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/433
This commit is contained in:
wowario 2023-01-05 22:17:01 +00:00
commit cc0889aa59
9 changed files with 143 additions and 41 deletions

Binary file not shown.

View File

@ -224,6 +224,7 @@ namespace cryptonote
ADD_CHECKPOINT2(332100, "d32c409058c1eceb9a105190c7a5f480b2d6f49f318b18652b49ae971c710124", "0x7c538441cca36"); ADD_CHECKPOINT2(332100, "d32c409058c1eceb9a105190c7a5f480b2d6f49f318b18652b49ae971c710124", "0x7c538441cca36");
ADD_CHECKPOINT2(334000, "17d3b15f8e1a73e1c61335ee7979e9e3d211b9055e8a7fb2481e5f49a51b1c22", "0x7ddd5a79d69c4"); ADD_CHECKPOINT2(334000, "17d3b15f8e1a73e1c61335ee7979e9e3d211b9055e8a7fb2481e5f49a51b1c22", "0x7ddd5a79d69c4");
ADD_CHECKPOINT2(348500, "2d43a157f369e2aa26a329b56456142ecd1361f5808c688d97112a2e3bbd23f4", "0x90889ed877ada"); ADD_CHECKPOINT2(348500, "2d43a157f369e2aa26a329b56456142ecd1361f5808c688d97112a2e3bbd23f4", "0x90889ed877ada");
ADD_CHECKPOINT2(489400, "b14f49eae77398117ea93435676100d8b655a804689f73a5a4d0d5e71160d603", "0x1123c39bb52f7e");
return true; return true;
} }

View File

@ -5541,7 +5541,7 @@ void Blockchain::cancel()
} }
#if defined(PER_BLOCK_CHECKPOINT) #if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "02777e7737e1a325558f28172d5041ed7b6e7026a0d19f3cd128966cad89299d"; static const char expected_block_hashes_hash[] = "cdb3d018fc4c2505619423a24b2d694348103df9af9a3f4f0cc203f4e21363bd";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints) void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{ {
if (get_checkpoints == nullptr || !m_fast_sync) if (get_checkpoints == nullptr || !m_fast_sync)

View File

@ -79,6 +79,7 @@ namespace
return rct::Bulletproof{rct::keyV(n_outs, I), I, I, I, I, I, I, rct::keyV(nrl, I), rct::keyV(nrl, I), I, I, I}; return rct::Bulletproof{rct::keyV(n_outs, I), I, I, I, I, I, I, rct::keyV(nrl, I), rct::keyV(nrl, I), I, I, I};
} }
rct::BulletproofPlus make_dummy_bulletproof_plus(const std::vector<uint64_t> &outamounts, rct::keyV &C, rct::keyV &masks) rct::BulletproofPlus make_dummy_bulletproof_plus(const std::vector<uint64_t> &outamounts, rct::keyV &C, rct::keyV &masks)
{ {
const size_t n_outs = outamounts.size(); const size_t n_outs = outamounts.size();
@ -109,6 +110,13 @@ namespace
return rct::BulletproofPlus{rct::keyV(n_outs, I), I, I, I, I, I, I, rct::keyV(nrl, I), rct::keyV(nrl, I)}; return rct::BulletproofPlus{rct::keyV(n_outs, I), I, I, I, I, I, I, rct::keyV(nrl, I), rct::keyV(nrl, I)};
} }
rct::clsag make_dummy_clsag(size_t ring_size)
{
const rct::key I = rct::identity();
const size_t n_scalars = ring_size;
return rct::clsag{rct::keyV(n_scalars, I), I, I, I};
}
} }
namespace rct { namespace rct {
@ -1400,7 +1408,10 @@ namespace rct {
{ {
if (is_rct_clsag(rv.type)) if (is_rct_clsag(rv.type))
{ {
rv.p.CLSAGs[i] = proveRctCLSAGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, msout ? &msout->mu_p[i] : NULL, index[i], hwdev); if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE)
rv.p.CLSAGs[i] = make_dummy_clsag(rv.mixRing[i].size());
else
rv.p.CLSAGs[i] = proveRctCLSAGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, msout ? &msout->mu_p[i] : NULL, index[i], hwdev);
} }
else else
{ {

View File

@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@" #define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.10.1.0" #define DEF_MONERO_VERSION "0.10.2.0"
#define DEF_MONERO_RELEASE_NAME "Junkie Jeff" #define DEF_MONERO_RELEASE_NAME "Junkie Jeff"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@ #define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@

View File

@ -346,12 +346,15 @@ bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const cryptonote
return remove_rings(chacha_key, key_images); return remove_rings(chacha_key, key_images);
} }
bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs) bool ringdb::get_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images, std::vector<std::vector<uint64_t>> &all_outs)
{ {
MDB_txn *txn; MDB_txn *txn;
int dbr; int dbr;
bool tx_active = false; bool tx_active = false;
all_outs.clear();
all_outs.reserve(key_images.size());
dbr = resize_env(env, filename.c_str(), 0); dbr = resize_env(env, filename.c_str(), 0);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr))); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr)));
dbr = mdb_txn_begin(env, NULL, 0, &txn); dbr = mdb_txn_begin(env, NULL, 0, &txn);
@ -359,6 +362,10 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);}); epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);});
tx_active = true; tx_active = true;
for (size_t i = 0; i < key_images.size(); ++i)
{
const crypto::key_image &key_image = key_images[i];
MDB_val key, data; MDB_val key, data;
std::string key_ciphertext = encrypt(key_image, chacha_key, 0); std::string key_ciphertext = encrypt(key_image, chacha_key, 0);
key.mv_data = (void*)key_ciphertext.data(); key.mv_data = (void*)key_ciphertext.data();
@ -369,6 +376,7 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
return false; return false;
THROW_WALLET_EXCEPTION_IF(data.mv_size <= 0, tools::error::wallet_internal_error, "Invalid ring data size"); THROW_WALLET_EXCEPTION_IF(data.mv_size <= 0, tools::error::wallet_internal_error, "Invalid ring data size");
std::vector<uint64_t> outs;
bool try_v0 = false; bool try_v0 = false;
std::string data_plaintext = decrypt(std::string((const char*)data.mv_data, data.mv_size), key_image, chacha_key, 1); std::string data_plaintext = decrypt(std::string((const char*)data.mv_data, data.mv_size), key_image, chacha_key, 1);
try { outs = decompress_ring(data_plaintext, V1TAG); if (outs.empty()) try_v0 = true; } try { outs = decompress_ring(data_plaintext, V1TAG); if (outs.empty()) try_v0 = true; }
@ -382,6 +390,9 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
MDEBUG("Relative: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " ")); MDEBUG("Relative: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
outs = cryptonote::relative_output_offsets_to_absolute(outs); outs = cryptonote::relative_output_offsets_to_absolute(outs);
MDEBUG("Absolute: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " ")); MDEBUG("Absolute: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
all_outs.push_back(std::move(outs));
}
dbr = mdb_txn_commit(txn); dbr = mdb_txn_commit(txn);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn getting ring from database: " + std::string(mdb_strerror(dbr))); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn getting ring from database: " + std::string(mdb_strerror(dbr)));
@ -389,20 +400,33 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
return true; return true;
} }
bool ringdb::set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative) bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs)
{
std::vector<std::vector<uint64_t>> all_outs;
if (!get_rings(chacha_key, std::vector<crypto::key_image>(1, key_image), all_outs))
return false;
outs = std::move(all_outs.front());
return true;
}
bool ringdb::set_rings(const crypto::chacha_key &chacha_key, const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative)
{ {
MDB_txn *txn; MDB_txn *txn;
int dbr; int dbr;
bool tx_active = false; bool tx_active = false;
dbr = resize_env(env, filename.c_str(), outs.size() * 64); size_t n_outs = 0;
for (const auto &e: rings)
n_outs += e.second.size();
dbr = resize_env(env, filename.c_str(), n_outs * 64);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr))); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr)));
dbr = mdb_txn_begin(env, NULL, 0, &txn); dbr = mdb_txn_begin(env, NULL, 0, &txn);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr))); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr)));
epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);}); epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);});
tx_active = true; tx_active = true;
store_relative_ring(txn, dbi_rings, key_image, relative ? outs : cryptonote::absolute_output_offsets_to_relative(outs), chacha_key); for (const auto &e: rings)
store_relative_ring(txn, dbi_rings, e.first, relative ? e.second : cryptonote::absolute_output_offsets_to_relative(e.second), chacha_key);
dbr = mdb_txn_commit(txn); dbr = mdb_txn_commit(txn);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn setting ring to database: " + std::string(mdb_strerror(dbr))); THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn setting ring to database: " + std::string(mdb_strerror(dbr)));
@ -410,6 +434,13 @@ bool ringdb::set_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
return true; return true;
} }
bool ringdb::set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative)
{
std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> rings;
rings.push_back(std::make_pair(key_image, outs));
return set_rings(chacha_key, rings, relative);
}
bool ringdb::blackball_worker(const std::vector<std::pair<uint64_t, uint64_t>> &outputs, int op) bool ringdb::blackball_worker(const std::vector<std::pair<uint64_t, uint64_t>> &outputs, int op)
{ {
MDB_txn *txn; MDB_txn *txn;

View File

@ -48,7 +48,9 @@ namespace tools
bool remove_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images); bool remove_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images);
bool remove_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx); bool remove_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx);
bool get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs); bool get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
bool get_rings(const crypto::chacha_key &chacha_key, const std::vector<crypto::key_image> &key_images, std::vector<std::vector<uint64_t>> &all_outs);
bool set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative); bool set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
bool set_rings(const crypto::chacha_key &chacha_key, const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative);
bool blackball(const std::pair<uint64_t, uint64_t> &output); bool blackball(const std::pair<uint64_t, uint64_t> &output);
bool blackball(const std::vector<std::pair<uint64_t, uint64_t>> &outputs); bool blackball(const std::vector<std::pair<uint64_t, uint64_t>> &outputs);

View File

@ -8127,6 +8127,14 @@ bool wallet2::get_ring(const crypto::chacha_key &key, const crypto::key_image &k
catch (const std::exception &e) { return false; } catch (const std::exception &e) { return false; }
} }
bool wallet2::get_rings(const crypto::chacha_key &key, const std::vector<crypto::key_image> &key_images, std::vector<std::vector<uint64_t>> &outs)
{
if (!m_ringdb)
return false;
try { return m_ringdb->get_rings(key, key_images, outs); }
catch (const std::exception &e) { return false; }
}
bool wallet2::get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs) bool wallet2::get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs)
{ {
for (auto i: m_confirmed_txs) for (auto i: m_confirmed_txs)
@ -8165,6 +8173,15 @@ bool wallet2::set_ring(const crypto::key_image &key_image, const std::vector<uin
catch (const std::exception &e) { return false; } catch (const std::exception &e) { return false; }
} }
bool wallet2::set_rings(const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative)
{
if (!m_ringdb)
return false;
try { return m_ringdb->set_rings(get_ringdb_key(), rings, relative); }
catch (const std::exception &e) { return false; }
}
bool wallet2::unset_ring(const std::vector<crypto::key_image> &key_images) bool wallet2::unset_ring(const std::vector<crypto::key_image> &key_images)
{ {
if (!m_ringdb) if (!m_ringdb)
@ -8339,7 +8356,7 @@ bool wallet2::is_keys_file_locked() const
return m_keys_file_locker->locked(); return m_keys_file_locker->locked();
} }
bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& output_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& output_public_key, const rct::key& mask, uint64_t real_index, bool unlocked, std::unordered_set<crypto::public_key> &valid_public_keys_cache) const
{ {
if (!unlocked) // don't add locked outs if (!unlocked) // don't add locked outs
return false; return false;
@ -8350,16 +8367,18 @@ bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_out
if (std::find(outs.back().begin(), outs.back().end(), item) != outs.back().end()) // don't add duplicates if (std::find(outs.back().begin(), outs.back().end(), item) != outs.back().end()) // don't add duplicates
return false; return false;
// check the keys are valid // check the keys are valid
if (!rct::isInMainSubgroup(rct::pk2rct(output_public_key))) if (valid_public_keys_cache.find(output_public_key) == valid_public_keys_cache.end() && !rct::isInMainSubgroup(rct::pk2rct(output_public_key)))
{ {
MWARNING("Key " << output_public_key << " at index " << global_index << " is not in the main subgroup"); MWARNING("Key " << output_public_key << " at index " << global_index << " is not in the main subgroup");
return false; return false;
} }
if (!rct::isInMainSubgroup(mask)) valid_public_keys_cache.insert(output_public_key);
if (valid_public_keys_cache.find(rct::rct2pk(mask)) == valid_public_keys_cache.end() && !rct::isInMainSubgroup(mask))
{ {
MWARNING("Commitment " << mask << " at index " << global_index << " is not in the main subgroup"); MWARNING("Commitment " << mask << " at index " << global_index << " is not in the main subgroup");
return false; return false;
} }
valid_public_keys_cache.insert(rct::rct2pk(mask));
// if (is_output_blackballed(output_public_key)) // don't add blackballed outputs // if (is_output_blackballed(output_public_key)) // don't add blackballed outputs
// return false; // return false;
outs.back().push_back(item); outs.back().push_back(item);
@ -8404,6 +8423,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
MDEBUG("selected transfers size: " << selected_transfers.size()); MDEBUG("selected transfers size: " << selected_transfers.size());
std::unordered_set<crypto::public_key> valid_public_keys_cache;
for(size_t idx: selected_transfers) for(size_t idx: selected_transfers)
{ {
// Create new index // Create new index
@ -8455,7 +8475,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
if(!light_wallet_parse_rct_str(ores.amount_outs[amount_key].outputs[i].rct, tx_public_key, 0, mask, rct_commit, false)) if(!light_wallet_parse_rct_str(ores.amount_outs[amount_key].outputs[i].rct, tx_public_key, 0, mask, rct_commit, false))
rct_commit = rct::zeroCommit(td.amount()); rct_commit = rct::zeroCommit(td.amount());
if (tx_add_fake_output(outs, global_index, tx_public_key, rct_commit, td.m_global_output_index, true)) { if (tx_add_fake_output(outs, global_index, tx_public_key, rct_commit, td.m_global_output_index, true, valid_public_keys_cache)) {
MDEBUG("added fake output " << ores.amount_outs[amount_key].outputs[i].public_key); MDEBUG("added fake output " << ores.amount_outs[amount_key].outputs[i].public_key);
MDEBUG("index " << global_index); MDEBUG("index " << global_index);
} }
@ -8492,12 +8512,12 @@ std::pair<std::set<uint64_t>, size_t> outs_unique(const std::vector<std::vector<
return std::make_pair(std::move(unique), total); return std::make_pair(std::move(unique), total);
} }
void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct) void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct, std::unordered_set<crypto::public_key> &valid_public_keys_cache)
{ {
std::vector<uint64_t> rct_offsets; std::vector<uint64_t> rct_offsets;
for (size_t attempts = 3; attempts > 0; --attempts) for (size_t attempts = 3; attempts > 0; --attempts)
{ {
get_outs(outs, selected_transfers, fake_outputs_count, rct_offsets); get_outs(outs, selected_transfers, fake_outputs_count, rct_offsets, valid_public_keys_cache);
if (!rct) if (!rct)
return; return;
@ -8519,7 +8539,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
THROW_WALLET_EXCEPTION(error::wallet_internal_error, tr("Transaction sanity check failed")); THROW_WALLET_EXCEPTION(error::wallet_internal_error, tr("Transaction sanity check failed"));
} }
void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, std::vector<uint64_t> &rct_offsets) void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, std::vector<uint64_t> &rct_offsets, std::unordered_set<crypto::public_key> &valid_public_keys_cache)
{ {
LOG_PRINT_L2("fake_outputs_count: " << fake_outputs_count); LOG_PRINT_L2("fake_outputs_count: " << fake_outputs_count);
outs.clear(); outs.clear();
@ -8563,6 +8583,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t); cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t);
// request histogram for all outputs, except 0 if we have the rct distribution // request histogram for all outputs, except 0 if we have the rct distribution
req_t.amounts.reserve(selected_transfers.size());
for(size_t idx: selected_transfers) for(size_t idx: selected_transfers)
if (!m_transfers[idx].is_rct() || !has_rct_distribution) if (!m_transfers[idx].is_rct() || !has_rct_distribution)
req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount());
@ -8590,6 +8611,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{ {
cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response resp_t = AUTO_VAL_INIT(resp_t); cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response resp_t = AUTO_VAL_INIT(resp_t);
req_t.amounts.reserve(req_t.amounts.size() + selected_transfers.size());
for(size_t idx: selected_transfers) for(size_t idx: selected_transfers)
req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount());
std::sort(req_t.amounts.begin(), req_t.amounts.end()); std::sort(req_t.amounts.begin(), req_t.amounts.end());
@ -8636,6 +8658,25 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
} }
} }
std::vector<crypto::key_image> ring_key_images;
ring_key_images.reserve(selected_transfers.size());
std::unordered_map<crypto::key_image, std::vector<uint64_t>> existing_rings;
for(size_t idx: selected_transfers)
{
const transfer_details &td = m_transfers[idx];
if (td.m_key_image_known && !td.m_key_image_partial)
ring_key_images.push_back(td.m_key_image);
}
if (!ring_key_images.empty())
{
std::vector<std::vector<uint64_t>> all_outs;
if (get_rings(get_ringdb_key(), ring_key_images, all_outs))
{
for (size_t i = 0; i < ring_key_images.size(); ++i)
existing_rings[ring_key_images[i]] = std::move(all_outs[i]);
}
}
// we ask for more, to have spares if some outputs are still locked // we ask for more, to have spares if some outputs are still locked
size_t base_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1); size_t base_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1);
LOG_PRINT_L2("base_requested_outputs_count: " << base_requested_outputs_count); LOG_PRINT_L2("base_requested_outputs_count: " << base_requested_outputs_count);
@ -8649,6 +8690,8 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
gamma.reset(new gamma_picker(rct_offsets)); gamma.reset(new gamma_picker(rct_offsets));
size_t num_selected_transfers = 0; size_t num_selected_transfers = 0;
req.outputs.reserve(selected_transfers.size() * (base_requested_outputs_count + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW));
daemon_resp.outs.reserve(selected_transfers.size() * (base_requested_outputs_count + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW));
for(size_t idx: selected_transfers) for(size_t idx: selected_transfers)
{ {
++num_selected_transfers; ++num_selected_transfers;
@ -8758,9 +8801,12 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
// if we have a known ring, use it // if we have a known ring, use it
if (td.m_key_image_known && !td.m_key_image_partial) if (td.m_key_image_known && !td.m_key_image_partial)
{ {
std::vector<uint64_t> ring;
if (get_ring(get_ringdb_key(), td.m_key_image, ring)) const auto it = existing_rings.find(td.m_key_image);
const bool has_ring = it != existing_rings.end();
if (has_ring)
{ {
const std::vector<uint64_t> &ring = it->second;
MINFO("This output has a known ring, reusing (size " << ring.size() << ")"); MINFO("This output has a known ring, reusing (size " << ring.size() << ")");
THROW_WALLET_EXCEPTION_IF(ring.size() > fake_outputs_count + 1, error::wallet_internal_error, THROW_WALLET_EXCEPTION_IF(ring.size() > fake_outputs_count + 1, error::wallet_internal_error,
"An output in this transaction was previously spent on another chain with ring size " + "An output in this transaction was previously spent on another chain with ring size " +
@ -9018,9 +9064,10 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
// then pick outs from an existing ring, if any // then pick outs from an existing ring, if any
if (td.m_key_image_known && !td.m_key_image_partial) if (td.m_key_image_known && !td.m_key_image_partial)
{ {
std::vector<uint64_t> ring; const auto it = existing_rings.find(td.m_key_image);
if (get_ring(get_ringdb_key(), td.m_key_image, ring)) if (it != existing_rings.end())
{ {
const std::vector<uint64_t> &ring = it->second;
for (uint64_t out: ring) for (uint64_t out: ring)
{ {
if (out < num_outs) if (out < num_outs)
@ -9034,7 +9081,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (req.outputs[i].index == out) if (req.outputs[i].index == out)
{ {
LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key << " (from existing ring)"); LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key << " (from existing ring)");
tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked); tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache);
found = true; found = true;
break; break;
} }
@ -9059,7 +9106,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{ {
size_t i = base + order[o]; size_t i = base + order[o];
LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key); LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key);
tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked); tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache);
} }
if (outs.back().size() < fake_outputs_count + 1) if (outs.back().size() < fake_outputs_count + 1)
{ {
@ -9087,6 +9134,8 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
} }
// save those outs in the ringdb for reuse // save those outs in the ringdb for reuse
std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> rings;
rings.reserve(selected_transfers.size());
for (size_t i = 0; i < selected_transfers.size(); ++i) for (size_t i = 0; i < selected_transfers.size(); ++i)
{ {
const size_t idx = selected_transfers[i]; const size_t idx = selected_transfers[i];
@ -9096,14 +9145,15 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
ring.reserve(outs[i].size()); ring.reserve(outs[i].size());
for (const auto &e: outs[i]) for (const auto &e: outs[i])
ring.push_back(std::get<0>(e)); ring.push_back(std::get<0>(e));
if (!set_ring(td.m_key_image, ring, false)) rings.push_back(std::make_pair(td.m_key_image, std::move(ring)));
MERROR("Failed to set ring for " << td.m_key_image);
} }
if (!set_rings(rings, false))
MERROR("Failed to set rings");
} }
template<typename T> template<typename T>
void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::unordered_set<crypto::public_key> &valid_public_keys_cache,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx) uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx)
{ {
using namespace cryptonote; using namespace cryptonote;
@ -9140,7 +9190,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts"); THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts");
if (outs.empty()) if (outs.empty())
get_outs(outs, selected_transfers, fake_outputs_count, false); // may throw get_outs(outs, selected_transfers, fake_outputs_count, false, valid_public_keys_cache); // may throw
//prepare inputs //prepare inputs
LOG_PRINT_L2("preparing outputs"); LOG_PRINT_L2("preparing outputs");
@ -9263,7 +9313,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
} }
void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::unordered_set<crypto::public_key> &valid_public_keys_cache,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config) uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config)
{ {
using namespace cryptonote; using namespace cryptonote;
@ -9357,7 +9407,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts"); THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts");
if (outs.empty()) if (outs.empty())
get_outs(outs, selected_transfers, fake_outputs_count, all_rct); // may throw get_outs(outs, selected_transfers, fake_outputs_count, all_rct, valid_public_keys_cache); // may throw
//prepare inputs //prepare inputs
LOG_PRINT_L2("preparing outputs"); LOG_PRINT_L2("preparing outputs");
@ -10240,6 +10290,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
rct::RangeProofPaddedBulletproof, rct::RangeProofPaddedBulletproof,
bulletproof_plus ? 4 : 3 bulletproof_plus ? 4 : 3
}; };
std::unordered_set<crypto::public_key> valid_public_keys_cache;
const uint64_t base_fee = get_base_fee(); const uint64_t base_fee = get_base_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
@ -10585,10 +10636,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " << LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
tx.selected_transfers.size() << " inputs"); tx.selected_transfers.size() << " inputs");
if (use_rct) if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config); test_tx, test_ptx, rct_config);
else else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
auto txBlob = t_serializable_object_to_blob(test_ptx.tx); auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
@ -10628,10 +10679,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee)); LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee));
while (needed_fee > test_ptx.fee) { while (needed_fee > test_ptx.fee) {
if (use_rct) if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config); test_tx, test_ptx, rct_config);
else else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
txBlob = t_serializable_object_to_blob(test_ptx.tx); txBlob = t_serializable_object_to_blob(test_ptx.tx);
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
@ -10697,6 +10748,7 @@ skip_tx:
tx.selected_transfers, /* const std::list<size_t> selected_transfers */ tx.selected_transfers, /* const std::list<size_t> selected_transfers */
fake_outs_count, /* CONST size_t fake_outputs_count, */ fake_outs_count, /* CONST size_t fake_outputs_count, */
tx.outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */ tx.outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */
valid_public_keys_cache,
unlock_time, /* CONST uint64_t unlock_time, */ unlock_time, /* CONST uint64_t unlock_time, */
tx.needed_fee, /* CONST uint64_t fee, */ tx.needed_fee, /* CONST uint64_t fee, */
extra, /* const std::vector<uint8_t>& extra, */ extra, /* const std::vector<uint8_t>& extra, */
@ -10708,6 +10760,7 @@ skip_tx:
tx.selected_transfers, tx.selected_transfers,
fake_outs_count, fake_outs_count,
tx.outs, tx.outs,
valid_public_keys_cache,
unlock_time, unlock_time,
tx.needed_fee, tx.needed_fee,
extra, extra,
@ -10827,6 +10880,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!"); THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!");
const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring; const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring;
const uint64_t fractional_threshold = (fee_multiplier * base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024); const uint64_t fractional_threshold = (fee_multiplier * base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
std::unordered_set<crypto::public_key> valid_public_keys_cache;
THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, false) == 0, error::wallet_internal_error, "No unlocked balance in the specified account"); THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, false) == 0, error::wallet_internal_error, "No unlocked balance in the specified account");
@ -10908,6 +10962,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
hw::device &hwdev = m_account.get_device(); hw::device &hwdev = m_account.get_device();
boost::unique_lock<hw::device> hwdev_lock (hwdev); boost::unique_lock<hw::device> hwdev_lock (hwdev);
hw::reset_mode rst(hwdev); hw::reset_mode rst(hwdev);
std::unordered_set<crypto::public_key> valid_public_keys_cache;
uint64_t accumulated_fee, accumulated_outputs, accumulated_change; uint64_t accumulated_fee, accumulated_outputs, accumulated_change;
struct TX { struct TX {
@ -11010,10 +11065,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " << LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
tx.selected_transfers.size() << " outputs"); tx.selected_transfers.size() << " outputs");
if (use_rct) if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config); test_tx, test_ptx, rct_config);
else else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
auto txBlob = t_serializable_object_to_blob(test_ptx.tx); auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
@ -11047,10 +11102,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
dt.amount = dt_amount + dt_residue; dt.amount = dt_amount + dt_residue;
} }
if (use_rct) if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config); test_tx, test_ptx, rct_config);
else else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
txBlob = t_serializable_object_to_blob(test_ptx.tx); txBlob = t_serializable_object_to_blob(test_ptx.tx);
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
@ -11086,10 +11141,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
cryptonote::transaction test_tx; cryptonote::transaction test_tx;
pending_tx test_ptx; pending_tx test_ptx;
if (use_rct) { if (use_rct) {
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.needed_fee, extra, transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra,
test_tx, test_ptx, rct_config); test_tx, test_ptx, rct_config);
} else { } else {
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.needed_fee, extra, transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
} }
auto txBlob = t_serializable_object_to_blob(test_ptx.tx); auto txBlob = t_serializable_object_to_blob(test_ptx.tx);

View File

@ -951,10 +951,10 @@ private:
uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL); uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL);
template<typename T> template<typename T>
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::unordered_set<crypto::public_key> &valid_public_keys_cache,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx); uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx);
void transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, void transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::unordered_set<crypto::public_key> &valid_public_keys_cache,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config); uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config);
void commit_tx(pending_tx& ptx_vector); void commit_tx(pending_tx& ptx_vector);
@ -1505,7 +1505,9 @@ private:
const std::string get_ring_database() const { return m_ring_database; } const std::string get_ring_database() const { return m_ring_database; }
bool get_ring(const crypto::key_image &key_image, std::vector<uint64_t> &outs); bool get_ring(const crypto::key_image &key_image, std::vector<uint64_t> &outs);
bool get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs); bool get_rings(const crypto::hash &txid, std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &outs);
bool get_rings(const crypto::chacha_key &key, const std::vector<crypto::key_image> &key_images, std::vector<std::vector<uint64_t>> &outs);
bool set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative); bool set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
bool set_rings(const std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> &rings, bool relative);
bool unset_ring(const std::vector<crypto::key_image> &key_images); bool unset_ring(const std::vector<crypto::key_image> &key_images);
bool unset_ring(const crypto::hash &txid); bool unset_ring(const crypto::hash &txid);
bool find_and_save_rings(bool force = true); bool find_and_save_rings(bool force = true);
@ -1633,9 +1635,9 @@ private:
void set_unspent(size_t idx); void set_unspent(size_t idx);
bool is_spent(const transfer_details &td, bool strict = true) const; bool is_spent(const transfer_details &td, bool strict = true) const;
bool is_spent(size_t idx, bool strict = true) const; bool is_spent(size_t idx, bool strict = true) const;
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct); void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, bool rct, std::unordered_set<crypto::public_key> &valid_public_keys_cache);
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, std::vector<uint64_t> &rct_offsets); void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count, std::vector<uint64_t> &rct_offsets, std::unordered_set<crypto::public_key> &valid_public_keys_cache);
bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const; bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked, std::unordered_set<crypto::public_key> &valid_public_keys_cache) const;
bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const; std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const;
void scan_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map<cryptonote::subaddress_index, uint64_t> &tx_money_got_in_outs, std::vector<size_t> &outs, bool pool); void scan_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map<cryptonote::subaddress_index, uint64_t> &tx_money_got_in_outs, std::vector<size_t> &outs, bool pool);