Skip to content

Commit

Permalink
use utxo ordering at queryutxo
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoatelen-ledger committed Feb 21, 2023
1 parent 5748ef0 commit 0c48d5c
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 17 deletions.
30 changes: 26 additions & 4 deletions core/src/wallet/bitcoin/BitcoinLikeAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@

namespace {
using namespace ledger::core;

BitcoinLikeUTXODatabaseHelper::UTXOOrderType getUtxoOrder(const std::shared_ptr<DynamicObject>& conf) {
bool confirmFirst = conf->getBoolean(api::Configuration::QUERY_CONFIRMED_UTXO_FIRST).value_or(true);
return confirmFirst ? BitcoinLikeUTXODatabaseHelper::UTXOOrderType::CONFIRMED_FIRST : BitcoinLikeUTXODatabaseHelper::UTXOOrderType::UNCONFIRMED_FIRST;
}


/// Constructor of BitcoinLikeBlockchainExplorerTransaction that initializes some fields
/// with a just signed transaction.
///
Expand Down Expand Up @@ -461,8 +468,13 @@ namespace ledger {
self->logger()->info(fmt::format("Worthless utxo value is {}", worthlessUtxoAmount));
soci::session sql(self->getWallet()->getDatabase()->getReadonlyPool());
std::vector<BitcoinLikeBlockchainExplorerOutput> utxo;

BitcoinLikeUTXODatabaseHelper::queryUTXO(sql, self->getAccountUid(), from, to - from, worthlessUtxoAmount, utxo);
const auto& config = self->getWallet()->getConfig();
const auto& utxoOrder = getUtxoOrder(config);
BitcoinLikeUTXODatabaseHelper::queryUTXO(
sql,
self->getAccountUid(), from, to - from,
utxoOrder,
worthlessUtxoAmount, utxo);
return functional::map<BitcoinLikeBlockchainExplorerOutput, std::shared_ptr<api::BitcoinLikeOutput>>(utxo, [&currency](const BitcoinLikeBlockchainExplorerOutput &output) -> std::shared_ptr<api::BitcoinLikeOutput> {
return std::make_shared<BitcoinLikeOutputApi>(output, currency);
});
Expand Down Expand Up @@ -546,7 +558,14 @@ namespace ledger {
auto keychain = self->getKeychain();
const auto worthlessUtxoAmount = BitcoinLikeTransactionApi::computeWorthlessUtxoValue(self->getWallet()->getCurrency(), keychain->getKeychainEngine(), fees);
self->logger()->info(fmt::format("Worthless utxo value is {}", worthlessUtxoAmount));
BitcoinLikeUTXODatabaseHelper::queryUTXO(sql, uid, 0, std::numeric_limits<int32_t>::max(), worthlessUtxoAmount, utxos);
const auto& config = self->getWallet()->getConfig();
const auto& utxoOrder = getUtxoOrder(config);
BitcoinLikeUTXODatabaseHelper::queryUTXO(
sql, uid, 0, std::numeric_limits<int32_t>::max(),
utxoOrder,
worthlessUtxoAmount,
utxos
);
switch (strategy) {
case api::BitcoinLikePickingStrategy::DEEP_OUTPUTS_FIRST:
case api::BitcoinLikePickingStrategy::MERGE_OUTPUTS:
Expand Down Expand Up @@ -754,7 +773,10 @@ namespace ledger {

const auto worthlessUtxoAmount = BitcoinLikeTransactionApi::computeWorthlessUtxoValue(self->getWallet()->getCurrency(), keychain->getKeychainEngine(), fees);
self->logger()->info(fmt::format("Worthless utxo value is {}", worthlessUtxoAmount));
return BitcoinLikeUTXODatabaseHelper::queryAllUtxos(session, self->getAccountUid(), self->getWallet()->getCurrency(), worthlessUtxoAmount);

const auto& config = self->getWallet()->getConfig();
const auto& utxoOrder = getUtxoOrder(config);
return BitcoinLikeUTXODatabaseHelper::queryAllUtxos(session, self->getAccountUid(), self->getWallet()->getCurrency(), utxoOrder, worthlessUtxoAmount);
});
};
auto getTransaction = [self](const std::string &hash) -> FuturePtr<BitcoinLikeBlockchainExplorerTransaction> {
Expand Down
39 changes: 26 additions & 13 deletions core/src/wallet/bitcoin/database/BitcoinLikeUTXODatabaseHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ using namespace soci;
namespace ledger {
namespace core {

std::string serializeOrder(const BitcoinLikeUTXODatabaseHelper::UTXOOrderType& order) {
return order==BitcoinLikeUTXODatabaseHelper::UTXOOrderType::UNCONFIRMED_FIRST ? "ASC": "DESC";
}

std::size_t BitcoinLikeUTXODatabaseHelper::UTXOcount(soci::session &sql, const std::string &accountUid, int64_t dustAmount) {
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 "
Expand All @@ -57,14 +61,18 @@ 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 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",
BitcoinLikeUTXODatabaseHelper::queryUTXO(soci::session &sql, const std::string &accountUid, int32_t offset, int32_t count, UTXOOrderType order, int64_t dustAmount, std::vector<BitcoinLikeBlockchainExplorerOutput> &out) {
const std::string orderStr = serializeOrder(order);
auto queryFmt = fmt::format(
"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",
orderStr);
const rowset<row> rows = (sql.prepare << queryFmt,
use(accountUid), use(dustAmount), use(count), use(offset));

for (auto &row : rows) {
Expand Down Expand Up @@ -106,12 +114,17 @@ namespace ledger {
soci::session &session,
std::string const &accountUid,
api::Currency const &currency,
UTXOOrderType order,
int64_t 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",
const std::string orderStr = serializeOrder(order);
auto queryFmt = fmt::format(
"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 {} ",
orderStr);
const soci::rowset<soci::row> rows = (session.prepare << queryFmt,
use(accountUid), use(dustAmount));

std::vector<BitcoinLikeUtxo> utxos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,16 @@ namespace ledger {
~BitcoinLikeUTXODatabaseHelper() = delete;

public:
enum class UTXOOrderType {
UNCONFIRMED_FIRST,
CONFIRMED_FIRST
};

static std::size_t queryUTXO(soci::session &sql,
const std::string &accountUid,
int32_t offset,
int32_t count,
UTXOOrderType order,
int64_t dustAmount,
std::vector<BitcoinLikeBlockchainExplorerOutput> &out);

Expand All @@ -63,6 +69,7 @@ namespace ledger {
soci::session &session,
std::string const &accountUid,
api::Currency const &currency,
UTXOOrderType order,
int64_t dustAmount);
};
} // namespace core
Expand Down
20 changes: 20 additions & 0 deletions core/test/integration/accounts_public_interfaces_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ TEST_F(AccountsPublicInterfaceTest, GetBalanceOnAccountWithSomeTxs) {
EXPECT_EQ(uxtoCount, 8);
}

TEST_F(AccountsPublicInterfaceTest, UtxoOrderConfirmedFirstByDefault) {
auto account = ledger::testing::medium_xpub::inflate(pool, wallet);
auto utxos = uv::wait(account->getUTXO());
const auto size = utxos.size();
for(unsigned int i = 0; i < size-1; ++i) {
EXPECT_GE(utxos[i]->getBlockHeight().value(), utxos[i+1]->getBlockHeight().value());
}
}

TEST_F(AccountsPublicInterfaceTest, UtxoOrderUnConfirmedFirst) {
auto account = ledger::testing::medium_xpub::inflate(pool, wallet);
auto config = account->getWallet()->getConfig();
config->putBoolean(api::Configuration::QUERY_CONFIRMED_UTXO_FIRST, false);
auto utxos = uv::wait(account->getUTXO());
const auto size = utxos.size();
for(unsigned int i = 0; i < size-1; ++i) {
EXPECT_LE(utxos[i]->getBlockHeight().value(), utxos[i+1]->getBlockHeight().value());
}
}

TEST_F(AccountsPublicInterfaceTest, GetBalanceHistoryOnAccountWithSomeTxs) {
auto account = ledger::testing::medium_xpub::inflate(pool, wallet);
auto fromDate = "2017-10-12T13:38:23Z";
Expand Down

0 comments on commit 0c48d5c

Please sign in to comment.