Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VG-13107 feat(BTC): Use cached balance on bitcoin accounts #934

Merged
merged 10 commits into from
Apr 11, 2023
Merged
2 changes: 1 addition & 1 deletion core/src/database/DatabaseSessionPool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace ledger {
const std::string &dbName,
const std::string &password = "");

static const int CURRENT_DATABASE_SCHEME_VERSION = 31;
static const int CURRENT_DATABASE_SCHEME_VERSION = 32;

void performDatabaseMigration();
void performDatabaseRollback();
Expand Down
10 changes: 10 additions & 0 deletions core/src/database/migrations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1265,5 +1265,15 @@ namespace ledger {
void rollback<31>(soci::session &sql, api::DatabaseBackendType /*type*/) {
sql << "ALTER TABLE tezos_transactions DROP explorer_id";
}

template <>
void migrate<32>(soci::session &sql, api::DatabaseBackendType /*type*/) {
sql << "ALTER TABLE bitcoin_accounts ADD COLUMN balance BIGINT DEFAULT -1;";
}

template <>
void rollback<32>(soci::session &sql, api::DatabaseBackendType /*type*/) {
sql << "ALTER TABLE bitcoin_accounts DROP COLUMN balance;";
}
} // namespace core
} // namespace ledger
6 changes: 6 additions & 0 deletions core/src/database/migrations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,12 @@ namespace ledger {
void migrate<31>(soci::session &sql, api::DatabaseBackendType type);
template <>
void rollback<31>(soci::session &sql, api::DatabaseBackendType type);

// add explorer uid for tezos transactions
template <>
void migrate<32>(soci::session &sql, api::DatabaseBackendType type);
template <>
void rollback<32>(soci::session &sql, api::DatabaseBackendType type);
} // namespace core
} // namespace ledger

Expand Down
6 changes: 2 additions & 4 deletions core/src/wallet/bitcoin/BitcoinLikeAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,10 +577,8 @@ 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());
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;
const auto sum = BitcoinLikeUTXODatabaseHelper::sumUTXO(sql, uid, worthlessUtxoAmount);
auto keychain = self->getKeychain();
const auto sum = BitcoinLikeUTXODatabaseHelper::getBalance(sql, uid);
const Amount balance(self->getWallet()->getCurrency(), 0, sum);
self->getWallet()->updateBalanceCache(self->getIndex(), balance);
return std::make_shared<Amount>(balance);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,16 @@ 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));
constexpr auto uncachedBalanceQuery = R"(
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)";

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

BigInt BitcoinLikeUTXODatabaseHelper::getBalance(soci::session &sql, const std::string &accountUid) {
const rowset<row> rows = (sql.prepare << "SELECT balance from bitcoin_accounts WHERE uid=:uid",
use(accountUid));

for (auto &row : rows) {
if (row.get_indicator(0) != i_null) {
auto balance = row.get<BigInt>(0);
if (balance.isNegative()) {
// 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
return getUncachedBalance(sql, accountUid);
}
return balance;
}
}
return BigInt(0);
}

void BitcoinLikeUTXODatabaseHelper::updateBalance(session &sql, const std::string &accountUid) {
jcoatelen-ledger marked this conversation as resolved.
Show resolved Hide resolved
const rowset<row> rows = (sql.prepare << std::string{"UPDATE bitcoin_accounts SET balance = ("} + uncachedBalanceQuery + ") WHERE uid = :uid;",
use(accountUid), use(accountUid));
}

std::vector<BitcoinLikeUtxo> BitcoinLikeUTXODatabaseHelper::queryAllUtxos(
soci::session &session,
std::string const &accountUid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ namespace ledger {
int64_t dustAmount,
std::vector<BitcoinLikeBlockchainExplorerOutput> &out);

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

// Only used for tests (by libcore btc sync)
static void updateBalance(soci::session &sql,
const std::string &accountUid);

static std::size_t UTXOcount(soci::session &sql,
const std::string &accountUid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
*/
#include "BlockchainExplorerAccountSynchronizer.h"

#include "wallet/bitcoin/database/BitcoinLikeUTXODatabaseHelper.h"

#include <async/FutureUtils.hpp>
#include <async/algorithm.h>
#include <debug/Benchmarker.h>
Expand Down Expand Up @@ -535,6 +537,10 @@ namespace ledger {
buddy->account->getWallet()->getName(), duration.count());
buddy->logger->error("Due to {}, {}", api::to_string(ex.getErrorCode()), ex.getMessage());
return buddy->context;
})
.then(account->getContext(), [account, buddy]() {
soci::session sql(buddy->wallet->getDatabase()->getPool());
BitcoinLikeUTXODatabaseHelper::updateBalance(sql, account->getAccountUid());
});
};

Expand Down