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

Commit 45c9428

Browse files
authored
VG-13107 feat(BTC): Use cached balance on bitcoin accounts (#934)
* feat(BTC): Use cached balance on bitcoin accounts On update on bitcoin_outputs, the sql trigger updates the account balance; * Have separated trigger in bitcoin_inputs * comment debug raises * Fix rollback * Use postgres 14 for tests * Use postgres 14 for tests `OR REPLACE` on triggers is only supported from postgres 14 https://www.postgresql.org/docs/14/sql-createtrigger.html * Remove triggers & update balance after sync * don't need to upgrade postgres * format * Update misleading comments
1 parent 1cc4ed4 commit 45c9428

File tree

7 files changed

+62
-15
lines changed

7 files changed

+62
-15
lines changed

core/src/database/DatabaseSessionPool.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ namespace ledger {
6363
const std::string &dbName,
6464
const std::string &password = "");
6565

66-
static const int CURRENT_DATABASE_SCHEME_VERSION = 31;
66+
static const int CURRENT_DATABASE_SCHEME_VERSION = 32;
6767

6868
void performDatabaseMigration();
6969
void performDatabaseRollback();

core/src/database/migrations.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,5 +1265,15 @@ namespace ledger {
12651265
void rollback<31>(soci::session &sql, api::DatabaseBackendType /*type*/) {
12661266
sql << "ALTER TABLE tezos_transactions DROP explorer_id";
12671267
}
1268+
1269+
template <>
1270+
void migrate<32>(soci::session &sql, api::DatabaseBackendType /*type*/) {
1271+
sql << "ALTER TABLE bitcoin_accounts ADD COLUMN balance BIGINT DEFAULT -1;";
1272+
}
1273+
1274+
template <>
1275+
void rollback<32>(soci::session &sql, api::DatabaseBackendType /*type*/) {
1276+
sql << "ALTER TABLE bitcoin_accounts DROP COLUMN balance;";
1277+
}
12681278
} // namespace core
12691279
} // namespace ledger

core/src/database/migrations.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,12 @@ namespace ledger {
293293
void migrate<31>(soci::session &sql, api::DatabaseBackendType type);
294294
template <>
295295
void rollback<31>(soci::session &sql, api::DatabaseBackendType type);
296+
297+
// add explorer uid for tezos transactions
298+
template <>
299+
void migrate<32>(soci::session &sql, api::DatabaseBackendType type);
300+
template <>
301+
void rollback<32>(soci::session &sql, api::DatabaseBackendType type);
296302
} // namespace core
297303
} // namespace ledger
298304

core/src/wallet/bitcoin/BitcoinLikeAccount.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -577,10 +577,8 @@ namespace ledger {
577577
return FuturePtr<Amount>::async(getWallet()->getPool()->getThreadPoolExecutionContext(), [=]() -> std::shared_ptr<Amount> {
578578
const auto &uid = self->getAccountUid();
579579
soci::session sql(self->getWallet()->getDatabase()->getReadonlyPool());
580-
auto keychain = self->getKeychain();
581-
// make sure ALL UTXOs are contained within the balance - although no transaction will be crafted with those
582-
constexpr auto worthlessUtxoAmount = 0;
583-
const auto sum = BitcoinLikeUTXODatabaseHelper::sumUTXO(sql, uid, worthlessUtxoAmount);
580+
auto keychain = self->getKeychain();
581+
const auto sum = BitcoinLikeUTXODatabaseHelper::getBalance(sql, uid);
584582
const Amount balance(self->getWallet()->getCurrency(), 0, sum);
585583
self->getWallet()->updateBalanceCache(self->getIndex(), balance);
586584
return std::make_shared<Amount>(balance);

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

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,16 @@ 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));
89+
constexpr auto uncachedBalanceQuery = R"(
90+
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
95+
AND o.account_uid = :uid)";
9696

97+
BigInt getUncachedBalance(soci::session &sql, const std::string &accountUid) {
98+
const rowset<soci::row> rows = (sql.prepare << uncachedBalanceQuery, use(accountUid));
9799
for (auto &row : rows) {
98100
if (row.get_indicator(0) != i_null) {
99101
return row.get<BigInt>(0);
@@ -102,6 +104,28 @@ namespace ledger {
102104
return BigInt(0);
103105
}
104106

107+
BigInt BitcoinLikeUTXODatabaseHelper::getBalance(soci::session &sql, const std::string &accountUid) {
108+
const rowset<row> rows = (sql.prepare << "SELECT balance from bitcoin_accounts WHERE uid=:uid",
109+
use(accountUid));
110+
111+
for (auto &row : rows) {
112+
if (row.get_indicator(0) != i_null) {
113+
auto balance = row.get<BigInt>(0);
114+
if (balance.isNegative()) {
115+
// We compute balance from DB instead of updating it, to let only the sync (lama-bitcoin or libcore, depending on the coin) doing the update
116+
return getUncachedBalance(sql, accountUid);
117+
}
118+
return balance;
119+
}
120+
}
121+
return BigInt(0);
122+
}
123+
124+
void BitcoinLikeUTXODatabaseHelper::updateBalance(session &sql, const std::string &accountUid) {
125+
const rowset<row> rows = (sql.prepare << std::string{"UPDATE bitcoin_accounts SET balance = ("} + uncachedBalanceQuery + ") WHERE uid = :uid;",
126+
use(accountUid), use(accountUid));
127+
}
128+
105129
std::vector<BitcoinLikeUtxo> BitcoinLikeUTXODatabaseHelper::queryAllUtxos(
106130
soci::session &session,
107131
std::string const &accountUid,

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,12 @@ namespace ledger {
5151
int64_t dustAmount,
5252
std::vector<BitcoinLikeBlockchainExplorerOutput> &out);
5353

54-
static BigInt sumUTXO(soci::session &sql,
55-
const std::string &accountUid,
56-
int64_t dustAmount);
54+
static BigInt getBalance(soci::session &sql,
55+
const std::string &accountUid);
56+
57+
// Only used for tests (by libcore btc sync)
58+
static void updateBalance(soci::session &sql,
59+
const std::string &accountUid);
5760

5861
static std::size_t UTXOcount(soci::session &sql,
5962
const std::string &accountUid,

core/src/wallet/bitcoin/synchronizers/BlockchainExplorerAccountSynchronizer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
*/
3131
#include "BlockchainExplorerAccountSynchronizer.h"
3232

33+
#include "wallet/bitcoin/database/BitcoinLikeUTXODatabaseHelper.h"
34+
3335
#include <async/FutureUtils.hpp>
3436
#include <async/algorithm.h>
3537
#include <debug/Benchmarker.h>
@@ -535,6 +537,10 @@ namespace ledger {
535537
buddy->account->getWallet()->getName(), duration.count());
536538
buddy->logger->error("Due to {}, {}", api::to_string(ex.getErrorCode()), ex.getMessage());
537539
return buddy->context;
540+
})
541+
.then(account->getContext(), [account, buddy]() {
542+
soci::session sql(buddy->wallet->getDatabase()->getPool());
543+
BitcoinLikeUTXODatabaseHelper::updateBalance(sql, account->getAccountUid());
538544
});
539545
};
540546

0 commit comments

Comments
 (0)