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

Commit 05302f3

Browse files
authored
Improve get balance time to compute (#917)
* Improve get balance time to compute Use postgresql sum instead of useless fetching-all + ordering before summing in memory
1 parent b2d2473 commit 05302f3

File tree

3 files changed

+51
-40
lines changed

3 files changed

+51
-40
lines changed

core/src/wallet/bitcoin/BitcoinLikeAccount.cpp

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,9 @@ namespace ledger {
464464
std::vector<BitcoinLikeBlockchainExplorerOutput> utxo;
465465

466466
utils::cache_type<bool, std::string> cache{};
467-
std::function<bool(const std::string &)> filter = utils::cached(cache, utils::to_function([&keychain](const std::string addr) -> bool { // NOLINT(performance-unnecessary-value-param)
468-
return keychain->contains(addr);
469-
}));
467+
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)
468+
return keychain->contains(addr);
469+
}));
470470

471471
BitcoinLikeUTXODatabaseHelper::queryUTXO(sql, self->getAccountUid(), from, to - from, worthlessUtxoAmount, utxo, filter);
472472
return functional::map<BitcoinLikeBlockchainExplorerOutput, std::shared_ptr<api::BitcoinLikeOutput>>(utxo, [&currency](const BitcoinLikeBlockchainExplorerOutput &output) -> std::shared_ptr<api::BitcoinLikeOutput> {
@@ -597,20 +597,11 @@ namespace ledger {
597597
return FuturePtr<Amount>::async(getWallet()->getPool()->getThreadPoolExecutionContext(), [=]() -> std::shared_ptr<Amount> {
598598
const auto &uid = self->getAccountUid();
599599
soci::session sql(self->getWallet()->getDatabase()->getReadonlyPool());
600-
std::vector<BitcoinLikeBlockchainExplorerOutput> utxos;
601-
auto keychain = self->getKeychain();
602-
utils::cache_type<bool, std::string> cache{};
603-
std::function<bool(const std::string &)> filter = utils::cached(cache, utils::to_function([&keychain](const std::string addr) -> bool { // NOLINT(performance-unnecessary-value-param)
604-
return keychain->contains(addr);
605-
}));
606-
607-
BigInt sum(0);
600+
auto keychain = self->getKeychain();
601+
// make sure ALL UTXOs are contained within the balance - although no transaction will be crafted with those
608602
constexpr auto worthlessUtxoAmount = 0;
609-
BitcoinLikeUTXODatabaseHelper::queryUTXO(sql, uid, 0, std::numeric_limits<int32_t>::max(), worthlessUtxoAmount, utxos, filter);
610-
for (const auto &utxo : utxos) {
611-
sum = sum + utxo.value;
612-
}
613-
Amount balance(self->getWallet()->getCurrency(), 0, sum);
603+
const auto sum = BitcoinLikeUTXODatabaseHelper::sumUTXO(sql, uid, worthlessUtxoAmount);
604+
const Amount balance(self->getWallet()->getCurrency(), 0, sum);
614605
self->getWallet()->updateBalanceCache(self->getIndex(), balance);
615606
return std::make_shared<Amount>(balance);
616607
});
@@ -636,9 +627,9 @@ namespace ledger {
636627
auto keychain = self->getKeychain();
637628

638629
utils::cache_type<bool, std::string> cache{};
639-
std::function<bool(const std::string &)> filter = utils::cached(cache, utils::to_function([&keychain](const std::string addr) -> bool { // NOLINT(performance-unnecessary-value-param)
640-
return keychain->contains(addr);
641-
}));
630+
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)
631+
return keychain->contains(addr);
632+
}));
642633

643634
// Get operations related to an account
644635
OperationDatabaseHelper::queryOperations(sql, uid, operations, filter);

core/src/wallet/bitcoin/database/BitcoinLikeUTXODatabaseHelper.cpp

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ namespace ledger {
4242
namespace core {
4343

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

5959
std::size_t
6060
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) {
61-
rowset<row> rows = (sql.prepare << "SELECT o.address, o.idx, o.transaction_hash, o.amount, o.script, o.block_height,"
62-
"replaceable"
63-
" FROM bitcoin_outputs AS o "
64-
" LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid "
65-
" AND i.previous_output_idx = o.idx"
66-
" WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount"
67-
" ORDER BY block_height LIMIT :count OFFSET :off",
68-
use(accountUid), use(dustAmount), use(count), use(offset));
61+
const rowset<row> rows = (sql.prepare << "SELECT o.address, o.idx, o.transaction_hash, o.amount, o.script, o.block_height,"
62+
"replaceable"
63+
" FROM bitcoin_outputs AS o "
64+
" LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid "
65+
" AND i.previous_output_idx = o.idx"
66+
" WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount"
67+
" ORDER BY block_height LIMIT :count OFFSET :off",
68+
use(accountUid), use(dustAmount), use(count), use(offset));
6969

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

89+
BigInt BitcoinLikeUTXODatabaseHelper::sumUTXO(soci::session &sql, const std::string &accountUid, int64_t dustAmount) {
90+
const rowset<row> rows = (sql.prepare << "SELECT sum(o.amount)::bigint"
91+
" FROM bitcoin_outputs AS o "
92+
" LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid "
93+
" AND i.previous_output_idx = o.idx"
94+
" WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount",
95+
use(accountUid), use(dustAmount));
96+
97+
for (auto &row : rows) {
98+
if (row.get_indicator(0) != i_null) {
99+
return row.get<BigInt>(0);
100+
}
101+
}
102+
return BigInt(0);
103+
}
104+
89105
std::vector<BitcoinLikeUtxo> BitcoinLikeUTXODatabaseHelper::queryAllUtxos(
90106
soci::session &session,
91107
std::string const &accountUid,
92108
api::Currency const &currency,
93109
int64_t dustAmount) {
94-
soci::rowset<soci::row> rows = (session.prepare << "SELECT o.address, o.idx, o.transaction_hash, o.amount, o.script, o.block_height "
95-
"FROM bitcoin_outputs AS o "
96-
"LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid AND i.previous_output_idx = o.idx "
97-
"WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount "
98-
"ORDER BY o.block_height",
99-
use(accountUid), use(dustAmount));
110+
const soci::rowset<soci::row> rows = (session.prepare << "SELECT o.address, o.idx, o.transaction_hash, o.amount, o.script, o.block_height "
111+
"FROM bitcoin_outputs AS o "
112+
"LEFT OUTER JOIN bitcoin_inputs AS i ON i.previous_tx_uid = o.transaction_uid AND i.previous_output_idx = o.idx "
113+
"WHERE i.previous_tx_uid IS NULL AND o.account_uid = :uid AND o.amount > :dustAmount "
114+
"ORDER BY o.block_height",
115+
use(accountUid), use(dustAmount));
100116

101117
std::vector<BitcoinLikeUtxo> utxos;
102118

103119
for (auto &row : rows) {
104120
if (row.get_indicator(0) != i_null) {
105-
BitcoinLikeUtxo output{
121+
const BitcoinLikeUtxo output{
106122
get_number<uint64_t>(row, 1),
107123
row.get<std::string>(2),
108124
Amount(currency, 0, row.get<BigInt>(3)),

core/src/wallet/bitcoin/database/BitcoinLikeUTXODatabaseHelper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ namespace ledger {
5252
std::vector<BitcoinLikeBlockchainExplorerOutput> &out,
5353
const std::function<bool(const std::string &address)> &filter);
5454

55+
static BigInt sumUTXO(soci::session &sql,
56+
const std::string &accountUid,
57+
int64_t dustAmount);
58+
5559
static std::size_t UTXOcount(soci::session &sql,
5660
const std::string &accountUid,
5761
int64_t dustAmount,

0 commit comments

Comments
 (0)