Skip to content
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: 18 additions & 11 deletions include/bitcoin/database/impl/query/objects.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -305,25 +305,32 @@ typename CLASS::output::cptr CLASS::get_output(
}

TEMPLATE
typename CLASS::point CLASS::get_spent(const output_link& link) const NOEXCEPT
typename CLASS::outpoint CLASS::get_spent(
const output_link& link) const NOEXCEPT
{
if (const auto tx = to_output_tx(link); !tx.is_terminal())
if (const auto index = to_output_index(tx, link);
index != point::null_index)
return { get_tx_key(tx), index };
table::output::get_parent_value out{};
if (!store_.output.get(link, out))
return {};

const auto index = to_output_index(out.parent_fk, link);
if (index == point::null_index)
return {};

return {};
return { { get_tx_key(out.parent_fk), index }, out.value };
}

TEMPLATE
typename CLASS::point CLASS::get_spender(const point_link& link) const NOEXCEPT
{
if (const auto tx = to_spending_tx(link); !tx.is_terminal())
if (const auto index = to_input_index(tx, link);
index != point::null_index)
return { get_tx_key(tx), index };
const auto tx = to_spending_tx(link);
if (tx.is_terminal())
return {};

const auto index = to_input_index(tx, link);
if (index == point::null_index)
return {};

return {};
return { get_tx_key(tx), index };
}

TEMPLATE
Expand Down
29 changes: 15 additions & 14 deletions include/bitcoin/database/impl/query/optional.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifndef LIBBITCOIN_DATABASE_QUERY_OPTIONAL_IPP
#define LIBBITCOIN_DATABASE_QUERY_OPTIONAL_IPP

#include <atomic>
#include <algorithm>
#include <ranges>
#include <utility>
Expand All @@ -32,19 +33,19 @@ namespace database {
// ----------------------------------------------------------------------------
// TODO: use point keys (for multimap compression).

// TODO: test more.
TEMPLATE
bool CLASS::to_address_outputs(output_links& out,
const hash_digest& key) const NOEXCEPT
bool CLASS::to_address_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT
{
out.clear();

// Pushing into the vector is more efficient than precomputation of size.
for (auto it = store_.address.it(key); it; ++it)
{
table::address::record address{};
if (!store_.address.get(it, address))
if (cancel || !store_.address.get(it, address))
{
out.clear();
out.shrink_to_fit();
return false;
}

Expand All @@ -56,11 +57,11 @@ bool CLASS::to_address_outputs(output_links& out,

// TODO: test more.
TEMPLATE
bool CLASS::to_confirmed_unspent_outputs(output_links& out,
const hash_digest& key) const NOEXCEPT
bool CLASS::to_confirmed_unspent_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT
{
output_links output_fks{};
if (!to_address_outputs(output_fks, key))
if (!to_address_outputs(cancel, output_fks, key))
return false;

out.clear();
Expand All @@ -75,11 +76,11 @@ bool CLASS::to_confirmed_unspent_outputs(output_links& out,

// TODO: test more.
TEMPLATE
bool CLASS::to_minimum_unspent_outputs(output_links& out,
const hash_digest& key, uint64_t minimum) const NOEXCEPT
bool CLASS::to_minimum_unspent_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT
{
output_links unspent_fks{};
if (!to_confirmed_unspent_outputs(unspent_fks, key))
if (!to_confirmed_unspent_outputs(cancel, unspent_fks, key))
return false;

out.clear();
Expand All @@ -104,12 +105,12 @@ bool CLASS::to_minimum_unspent_outputs(output_links& out,

// TODO: test more.
TEMPLATE
bool CLASS::get_confirmed_balance(uint64_t& out,
const hash_digest& key) const NOEXCEPT
bool CLASS::get_confirmed_balance(const std::atomic_bool& cancel,
uint64_t& out, const hash_digest& key) const NOEXCEPT
{
out = zero;
output_links unspent_fks{};
if (!to_confirmed_unspent_outputs(unspent_fks, key))
if (!to_confirmed_unspent_outputs(cancel, unspent_fks, key))
return false;

for (auto unspent_fk: unspent_fks)
Expand Down
21 changes: 11 additions & 10 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifndef LIBBITCOIN_DATABASE_QUERY_HPP
#define LIBBITCOIN_DATABASE_QUERY_HPP

#include <atomic>
#include <mutex>
#include <utility>
#include <bitcoin/system.hpp>
Expand Down Expand Up @@ -65,6 +66,7 @@ class query
using point = system::chain::point;
using input = system::chain::input;
using output = system::chain::output;
using outpoint = system::chain::outpoint;
using header = system::chain::header;
using script = system::chain::script;
using witness = system::chain::witness;
Expand Down Expand Up @@ -394,8 +396,8 @@ class query
input::cptr get_input(const tx_link& link, uint32_t index,
bool witness) const NOEXCEPT;

point get_spent(const output_link& link) const NOEXCEPT;
point get_spender(const point_link& link) const NOEXCEPT;
outpoint get_spent(const output_link& link) const NOEXCEPT;
script::cptr get_output_script(const output_link& link) const NOEXCEPT;
output::cptr get_output(const output_link& link) const NOEXCEPT;
output::cptr get_output(const tx_link& link, uint32_t index) const NOEXCEPT;
Expand Down Expand Up @@ -570,15 +572,14 @@ class query
/// Optional Tables.
/// -----------------------------------------------------------------------

/// Address, set internal to tx (natural-keyed).
bool to_address_outputs(output_links& out,
const hash_digest& key) const NOEXCEPT;
bool to_confirmed_unspent_outputs(output_links& out,
const hash_digest& key) const NOEXCEPT;
bool to_minimum_unspent_outputs(output_links& out, const hash_digest& key,
uint64_t value) const NOEXCEPT;
bool get_confirmed_balance(uint64_t& out,
const hash_digest& key) const NOEXCEPT;
bool to_address_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT;
bool to_confirmed_unspent_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT;
bool to_minimum_unspent_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key, uint64_t value) const NOEXCEPT;
bool get_confirmed_balance(const std::atomic_bool& cancel,
uint64_t& out, const hash_digest& key) const NOEXCEPT;

bool is_filtered_body(const header_link& link) const NOEXCEPT;
bool get_filter_body(filter& out, const header_link& link) const NOEXCEPT;
Expand Down
20 changes: 20 additions & 0 deletions include/bitcoin/database/tables/archives/output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,26 @@ struct output
system::chain::script::cptr script{};
};

struct get_parent_value
: public schema::output
{
link count() const NOEXCEPT
{
BC_ASSERT(false);
return {};
}

inline bool from_data(reader& source) NOEXCEPT
{
parent_fk = source.read_little_endian<tx::integer, tx::size>();
value = source.read_variable();
return source;
}

tx::integer parent_fk{};
uint64_t value{};
};

struct get_parent
: public schema::output
{
Expand Down
71 changes: 46 additions & 25 deletions test/query/optional.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const auto events_handler = [](auto, auto) {};

const auto genesis_address = test::genesis.transactions_ptr()->front()->outputs_ptr()->front()->script().hash();

BOOST_AUTO_TEST_CASE(query_optional__get_confirmed_balance__genesis__expected)
BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__genesis__expected)
{
settings settings{};
settings.path = TEST_DIRECTORY;
Expand All @@ -36,12 +36,14 @@ BOOST_AUTO_TEST_CASE(query_optional__get_confirmed_balance__genesis__expected)
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

uint64_t out{};
BOOST_REQUIRE(query.get_confirmed_balance(out, genesis_address));
BOOST_REQUIRE_EQUAL(out, 5000000000u);
output_links out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_address_outputs(cancel, out, genesis_address));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), query.to_output(0, 0));
}

BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__genesis__expected)
BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__cancel__canceled_false)
{
settings settings{};
settings.path = TEST_DIRECTORY;
Expand All @@ -51,9 +53,9 @@ BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__genesis__expected)
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
BOOST_REQUIRE(query.to_address_outputs(out, genesis_address));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), query.to_output(0, 0));
const std::atomic_bool cancel{ true };
BOOST_REQUIRE(!query.to_address_outputs(cancel, out, genesis_address));
BOOST_REQUIRE(out.empty());
}

BOOST_AUTO_TEST_CASE(query_optional__to_confirmed_unspent_outputs__genesis__expected)
Expand All @@ -66,24 +68,26 @@ BOOST_AUTO_TEST_CASE(query_optional__to_confirmed_unspent_outputs__genesis__expe
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
BOOST_REQUIRE(query.to_confirmed_unspent_outputs(out, genesis_address));
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_confirmed_unspent_outputs(cancel, out, genesis_address));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), 0);
}

////BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__above__excluded)
////{
//// settings settings{};
//// settings.path = TEST_DIRECTORY;
//// test::chunk_store store{ settings };
//// test::query_accessor query{ store };
//// BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
//// BOOST_REQUIRE(query.initialize(test::genesis));
////
//// output_links out{};
//// BOOST_REQUIRE(query.to_minimum_unspent_outputs(out, genesis_address, 5000000001));
//// BOOST_REQUIRE(out.empty());
////}
BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__above__excluded)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_minimum_unspent_outputs(cancel, out, genesis_address, 5000000001));
BOOST_REQUIRE(out.empty());
}

BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__at__included)
{
Expand All @@ -95,7 +99,8 @@ BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__at__included)
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
BOOST_REQUIRE(query.to_minimum_unspent_outputs(out, genesis_address, 5000000000));
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_minimum_unspent_outputs(cancel, out, genesis_address, 5000000000));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), 0);
}
Expand All @@ -110,14 +115,30 @@ BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__below__included
BOOST_REQUIRE(query.initialize(test::genesis));

output_links out{};
BOOST_REQUIRE(query.to_minimum_unspent_outputs(out, genesis_address, 0));
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.to_minimum_unspent_outputs(cancel, out, genesis_address, 0));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), 0);
BOOST_REQUIRE(query.to_minimum_unspent_outputs(out, genesis_address, 4999999999));
BOOST_REQUIRE(query.to_minimum_unspent_outputs(cancel, out, genesis_address, 4999999999));
BOOST_REQUIRE_EQUAL(out.size(), 1u);
BOOST_REQUIRE_EQUAL(out.front(), 0);
}

BOOST_AUTO_TEST_CASE(query_optional__get_confirmed_balance__genesis__expected)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE_EQUAL(store.create(events_handler), error::success);
BOOST_REQUIRE(query.initialize(test::genesis));

uint64_t out{};
const std::atomic_bool cancel{};
BOOST_REQUIRE(query.get_confirmed_balance(cancel, out, genesis_address));
BOOST_REQUIRE_EQUAL(out, 5000000000u);
}

////BOOST_AUTO_TEST_CASE(query_optional__set_filter__get_filter_and_head__expected)
////{
//// const auto& filter_head0 = system::null_hash;
Expand Down
Loading