Merge pull request #8046
df2e680
wallet2: speedup large tx construction: reserve vector memory (moneromooo-monero)38cdf01
wallet2: speedup large tx construction: batch ringdb lookups (Crypto City)353cd53
wallet2: speedup large tx construction: no pointless clsag generation (Crypto City)2b95178
wallet2: speedup large tx construction: batch ringdb updates (Crypto City)c9cf0b7
wallet2: speedup large tx construction: cache public key validity (moneromooo-monero)
This commit is contained in:
commit
f4669bfa2b
|
@ -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 {
|
||||||
|
@ -1323,7 +1331,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
|
||||||
{
|
{
|
||||||
|
|
|
@ -344,12 +344,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);
|
||||||
|
@ -357,6 +360,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();
|
||||||
|
@ -367,6 +374,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; }
|
||||||
|
@ -380,6 +388,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)));
|
||||||
|
@ -387,20 +398,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)));
|
||||||
|
@ -408,6 +432,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;
|
||||||
|
|
|
@ -49,7 +49,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);
|
||||||
|
|
|
@ -7606,6 +7606,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)
|
||||||
|
@ -7644,6 +7652,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)
|
||||||
|
@ -7818,7 +7835,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;
|
||||||
|
@ -7829,16 +7846,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);
|
||||||
|
@ -7882,6 +7901,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
|
||||||
|
@ -7933,7 +7953,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);
|
||||||
}
|
}
|
||||||
|
@ -7970,12 +7990,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;
|
||||||
|
@ -7997,7 +8017,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();
|
||||||
|
@ -8041,6 +8061,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());
|
||||||
|
@ -8068,6 +8089,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());
|
||||||
|
@ -8114,6 +8136,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);
|
||||||
|
@ -8127,6 +8168,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;
|
||||||
|
@ -8236,9 +8279,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 " +
|
||||||
|
@ -8438,7 +8484,9 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||||
COMMAND_RPC_GET_OUTPUTS_BIN::request chunk_req = AUTO_VAL_INIT(chunk_req);
|
COMMAND_RPC_GET_OUTPUTS_BIN::request chunk_req = AUTO_VAL_INIT(chunk_req);
|
||||||
COMMAND_RPC_GET_OUTPUTS_BIN::response chunk_daemon_resp = AUTO_VAL_INIT(chunk_daemon_resp);
|
COMMAND_RPC_GET_OUTPUTS_BIN::response chunk_daemon_resp = AUTO_VAL_INIT(chunk_daemon_resp);
|
||||||
chunk_req.get_txid = false;
|
chunk_req.get_txid = false;
|
||||||
for (size_t i = 0; i < std::min<size_t>(req.outputs.size() - offset, chunk_size); ++i)
|
const size_t this_chunk_size = std::min<size_t>(req.outputs.size() - offset, chunk_size);
|
||||||
|
chunk_req.outputs.reserve(this_chunk_size);
|
||||||
|
for (size_t i = 0; i < this_chunk_size; ++i)
|
||||||
chunk_req.outputs.push_back(req.outputs[offset + i]);
|
chunk_req.outputs.push_back(req.outputs[offset + i]);
|
||||||
|
|
||||||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||||
|
@ -8508,9 +8556,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)
|
||||||
|
@ -8524,7 +8573,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;
|
||||||
}
|
}
|
||||||
|
@ -8549,7 +8598,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)
|
||||||
{
|
{
|
||||||
|
@ -8577,6 +8626,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];
|
||||||
|
@ -8586,14 +8637,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,
|
||||||
bool use_view_tags)
|
bool use_view_tags)
|
||||||
{
|
{
|
||||||
|
@ -8631,7 +8683,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");
|
||||||
|
@ -8755,7 +8807,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, bool use_view_tags)
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config, bool use_view_tags)
|
||||||
{
|
{
|
||||||
using namespace cryptonote;
|
using namespace cryptonote;
|
||||||
|
@ -8849,7 +8901,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");
|
||||||
|
@ -9735,6 +9787,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
bulletproof_plus ? 4 : 3
|
bulletproof_plus ? 4 : 3
|
||||||
};
|
};
|
||||||
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
|
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
|
||||||
|
std::unordered_set<crypto::public_key> valid_public_keys_cache;
|
||||||
|
|
||||||
const uint64_t base_fee = get_base_fee(priority);
|
const uint64_t base_fee = get_base_fee(priority);
|
||||||
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
|
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
|
||||||
|
@ -10112,10 +10165,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, use_view_tags);
|
test_tx, test_ptx, rct_config, use_view_tags);
|
||||||
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, use_view_tags);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
|
||||||
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_quantization_mask);
|
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask);
|
||||||
|
@ -10137,10 +10190,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, use_view_tags);
|
test_tx, test_ptx, rct_config, use_view_tags);
|
||||||
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, use_view_tags);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
|
||||||
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_quantization_mask);
|
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask);
|
||||||
|
@ -10206,6 +10259,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, */
|
||||||
|
@ -10218,6 +10272,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,
|
||||||
|
@ -10335,6 +10390,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 = (base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
|
const uint64_t fractional_threshold = (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");
|
||||||
|
|
||||||
|
@ -10416,6 +10472,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 {
|
||||||
|
@ -10518,10 +10575,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, use_view_tags);
|
test_tx, test_ptx, rct_config, use_view_tags);
|
||||||
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, use_view_tags);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
|
||||||
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_quantization_mask);
|
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask);
|
||||||
|
@ -10555,10 +10612,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, use_view_tags);
|
test_tx, test_ptx, rct_config, use_view_tags);
|
||||||
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, use_view_tags);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
|
||||||
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_quantization_mask);
|
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask);
|
||||||
|
@ -10594,10 +10651,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, use_view_tags);
|
test_tx, test_ptx, rct_config, use_view_tags);
|
||||||
} 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, use_view_tags);
|
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
|
||||||
}
|
}
|
||||||
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
||||||
|
|
|
@ -1001,10 +1001,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, const bool use_view_tags);
|
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, const bool use_view_tags);
|
||||||
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, const bool use_view_tags);
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config, const bool use_view_tags);
|
||||||
|
|
||||||
void commit_tx(pending_tx& ptx_vector);
|
void commit_tx(pending_tx& ptx_vector);
|
||||||
|
@ -1558,7 +1558,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);
|
||||||
|
@ -1665,9 +1667,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);
|
||||||
|
|
Loading…
Reference in New Issue