Skip to content
This repository was archived by the owner on Feb 12, 2025. It is now read-only.

Improve get balance time to compute #917

Merged
merged 4 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 10 additions & 19 deletions core/src/wallet/bitcoin/BitcoinLikeAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -464,9 +464,9 @@ namespace ledger {
std::vector<BitcoinLikeBlockchainExplorerOutput> utxo;

utils::cache_type<bool, std::string> cache{};
std::function<bool(const std::string &)> filter = utils::cached(cache, utils::to_function([&keychain](const std::string addr) -> bool { // NOLINT(performance-unnecessary-value-param)
return keychain->contains(addr);
}));
const std::function<bool(const std::string &)> filter = utils::cached(cache, utils::to_function([&keychain](const std::string addr) -> bool { // NOLINT(performance-unnecessary-value-param)
return keychain->contains(addr);
}));

BitcoinLikeUTXODatabaseHelper::queryUTXO(sql, self->getAccountUid(), from, to - from, worthlessUtxoAmount, utxo, filter);
return functional::map<BitcoinLikeBlockchainExplorerOutput, std::shared_ptr<api::BitcoinLikeOutput>>(utxo, [&currency](const BitcoinLikeBlockchainExplorerOutput &output) -> std::shared_ptr<api::BitcoinLikeOutput> {
Expand Down Expand Up @@ -597,20 +597,11 @@ namespace ledger {
return FuturePtr<Amount>::async(getWallet()->getPool()->getThreadPoolExecutionContext(), [=]() -> std::shared_ptr<Amount> {
const auto &uid = self->getAccountUid();
soci::session sql(self->getWallet()->getDatabase()->getReadonlyPool());
std::vector<BitcoinLikeBlockchainExplorerOutput> utxos;
auto keychain = self->getKeychain();
utils::cache_type<bool, std::string> cache{};
std::function<bool(const std::string &)> filter = utils::cached(cache, utils::to_function([&keychain](const std::string addr) -> bool { // NOLINT(performance-unnecessary-value-param)
return keychain->contains(addr);
}));

BigInt sum(0);
auto keychain = self->getKeychain();
// make sure ALL UTXOs are contained within the balance - although no transaction will be crafted with those
constexpr auto worthlessUtxoAmount = 0;
BitcoinLikeUTXODatabaseHelper::queryUTXO(sql, uid, 0, std::numeric_limits<int32_t>::max(), worthlessUtxoAmount, utxos, filter);
for (const auto &utxo : utxos) {
sum = sum + utxo.value;
}
Amount balance(self->getWallet()->getCurrency(), 0, sum);
const auto sum = BitcoinLikeUTXODatabaseHelper::sumUTXO(sql, uid, worthlessUtxoAmount);
const Amount balance(self->getWallet()->getCurrency(), 0, sum);
self->getWallet()->updateBalanceCache(self->getIndex(), balance);
return std::make_shared<Amount>(balance);
});
Expand All @@ -636,9 +627,9 @@ namespace ledger {
auto keychain = self->getKeychain();

utils::cache_type<bool, std::string> cache{};
std::function<bool(const std::string &)> filter = utils::cached(cache, utils::to_function([&keychain](const std::string addr) -> bool { // NOLINT(performance-unnecessary-value-param)
return keychain->contains(addr);
}));
const std::function<bool(const std::string &)> filter = utils::cached(cache, utils::to_function([&keychain](const std::string addr) -> bool { // NOLINT(performance-unnecessary-value-param)
return keychain->contains(addr);
}));

// Get operations related to an account
OperationDatabaseHelper::queryOperations(sql, uid, operations, filter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ namespace ledger {
namespace core {

std::size_t BitcoinLikeUTXODatabaseHelper::UTXOcount(soci::session &sql, const std::string &accountUid, int64_t dustAmount, const std::function<bool(const std::string &address)> &filter) {
rowset<row> rows = (sql.prepare << "SELECT o.address FROM bitcoin_outputs AS o "
" LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid "
" AND i.previous_output_idx = o.idx"
" WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount",
use(accountUid), use(dustAmount));
std::size_t count = 0;
const rowset<row> rows = (sql.prepare << "SELECT o.address FROM bitcoin_outputs AS o "
" LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid "
" AND i.previous_output_idx = o.idx"
" WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount",
use(accountUid), use(dustAmount));
std::size_t count = 0;
for (auto &row : rows) {
if (row.get_indicator(0) != i_null && filter(row.get<std::string>(0))) {
count += 1;
Expand All @@ -58,14 +58,14 @@ namespace ledger {

std::size_t
BitcoinLikeUTXODatabaseHelper::queryUTXO(soci::session &sql, const std::string &accountUid, int32_t offset, int32_t count, int64_t dustAmount, std::vector<BitcoinLikeBlockchainExplorerOutput> &out, const std::function<bool(const std::string &address)> &filter) {
rowset<row> rows = (sql.prepare << "SELECT o.address, o.idx, o.transaction_hash, o.amount, o.script, o.block_height,"
"replaceable"
" FROM bitcoin_outputs AS o "
" LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid "
" AND i.previous_output_idx = o.idx"
" WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount"
" ORDER BY block_height LIMIT :count OFFSET :off",
use(accountUid), use(dustAmount), use(count), use(offset));
const rowset<row> rows = (sql.prepare << "SELECT o.address, o.idx, o.transaction_hash, o.amount, o.script, o.block_height,"
"replaceable"
" FROM bitcoin_outputs AS o "
" LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid "
" AND i.previous_output_idx = o.idx"
" WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount"
" ORDER BY block_height LIMIT :count OFFSET :off",
use(accountUid), use(dustAmount), use(count), use(offset));

for (auto &row : rows) {
if (row.get_indicator(0) != i_null && filter(row.get<std::string>(0))) {
Expand All @@ -86,23 +86,39 @@ namespace ledger {
return out.size();
}

BigInt BitcoinLikeUTXODatabaseHelper::sumUTXO(soci::session &sql, const std::string &accountUid, int64_t dustAmount) {
const rowset<row> rows = (sql.prepare << "SELECT sum(o.amount)::bigint"
" FROM bitcoin_outputs AS o "
" LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid "
" AND i.previous_output_idx = o.idx"
" WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount",
use(accountUid), use(dustAmount));

for (auto &row : rows) {
if (row.get_indicator(0) != i_null) {
return row.get<BigInt>(0);
}
}
return BigInt(0);
}

std::vector<BitcoinLikeUtxo> BitcoinLikeUTXODatabaseHelper::queryAllUtxos(
soci::session &session,
std::string const &accountUid,
api::Currency const &currency,
int64_t dustAmount) {
soci::rowset<soci::row> rows = (session.prepare << "SELECT o.address, o.idx, o.transaction_hash, o.amount, o.script, o.block_height "
"FROM bitcoin_outputs AS o "
"LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid AND i.previous_output_idx = o.idx "
"WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount "
"ORDER BY o.block_height",
use(accountUid), use(dustAmount));
const soci::rowset<soci::row> rows = (session.prepare << "SELECT o.address, o.idx, o.transaction_hash, o.amount, o.script, o.block_height "
"FROM bitcoin_outputs AS o "
"LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid AND i.previous_output_idx = o.idx "
"WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount "
"ORDER BY o.block_height",
use(accountUid), use(dustAmount));

std::vector<BitcoinLikeUtxo> utxos;

for (auto &row : rows) {
if (row.get_indicator(0) != i_null) {
BitcoinLikeUtxo output{
const BitcoinLikeUtxo output{
get_number<uint64_t>(row, 1),
row.get<std::string>(2),
Amount(currency, 0, row.get<BigInt>(3)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ namespace ledger {
std::vector<BitcoinLikeBlockchainExplorerOutput> &out,
const std::function<bool(const std::string &address)> &filter);

static BigInt sumUTXO(soci::session &sql,
const std::string &accountUid,
int64_t dustAmount);

static std::size_t UTXOcount(soci::session &sql,
const std::string &accountUid,
int64_t dustAmount,
Expand Down