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
15 changes: 11 additions & 4 deletions include/bitcoin/database/impl/query/extent.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ size_t CLASS::name##_buckets() const NOEXCEPT \
return store_.name.buckets(); \
}

#define DEFINE_HEADMAP_BUCKETS(name) \
TEMPLATE \
size_t CLASS::name##_buckets() const NOEXCEPT \
{ \
return store_.name.count(); \
}

#define DEFINE_RECORDS(name) \
TEMPLATE \
size_t CLASS::name##_records() const NOEXCEPT \
Expand Down Expand Up @@ -194,7 +201,7 @@ DEFINE_SIZES(wtxid)
DEFINE_SIZES(filter_bk)
DEFINE_SIZES(filter_tx)

// Buckets (hashmap + arraymap).
// Buckets (hashmap + arraymap + headmap).
// ----------------------------------------------------------------------------

DEFINE_BUCKETS(header)
Expand All @@ -203,8 +210,11 @@ DEFINE_BUCKETS(outs)
DEFINE_BUCKETS(txs)
DEFINE_BUCKETS(tx)

DEFINE_HEADMAP_BUCKETS(candidate)
DEFINE_HEADMAP_BUCKETS(confirmed)
DEFINE_BUCKETS(strong)
DEFINE_BUCKETS(scan)
DEFINE_HEADMAP_BUCKETS(state)
DEFINE_BUCKETS(duplicate)
DEFINE_BUCKETS(prevout)
DEFINE_BUCKETS(pool)
Expand All @@ -220,8 +230,6 @@ DEFINE_RECORDS(ins)
DEFINE_RECORDS(outs)
DEFINE_RECORDS(tx)

DEFINE_RECORDS(candidate)
DEFINE_RECORDS(confirmed)
DEFINE_RECORDS(strong)
DEFINE_RECORDS(scan)
DEFINE_RECORDS(scan_prefix)
Expand All @@ -238,7 +246,6 @@ DEFINE_RECORDS(prevalid0)
DEFINE_RECORDS(prevalid1)
DEFINE_RECORDS(presilent0)
DEFINE_RECORDS(presilent1)
DEFINE_RECORDS(state)
DEFINE_RECORDS(pool)
DEFINE_RECORDS(spends)
DEFINE_RECORDS(wtxid)
Expand Down
20 changes: 20 additions & 0 deletions include/bitcoin/database/impl/query/navigate/navigate_natural.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,26 @@ inline ins_key CLASS::get_point_key(const ins_link& link) const NOEXCEPT
return point.key;
}

TEMPLATE
inline hash_digest CLASS::get_outs_key(const outs_link& link) const NOEXCEPT
{
table::outs::get_output put{};
if (!store_.outs.puts.get_raw(link, put))
return {};

table::output::get_script_hash output{};
if (!store_.output.raw(store_.output.get_memory(), put.out_fk, output))
return {};

return output.hash;
}

TEMPLATE
inline hash_digest CLASS::get_wtxid_key(const pool_link& link) const NOEXCEPT
{
return get_pooled_wtxid(link);
}

TEMPLATE
inline hash_digest CLASS::get_point_hash(const ins_link& link) const NOEXCEPT
{
Expand Down
13 changes: 13 additions & 0 deletions include/bitcoin/database/impl/query/pool.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ bool CLASS::is_confirmable_tx(const tx_link& link) const NOEXCEPT
return is_confirmable_tx(memo, link);
}

TEMPLATE
bool CLASS::is_confirmable_spent(const output_link& link) const NOEXCEPT
{
for (const auto& in: to_spenders(link))
{
const auto tx = to_input_tx(in);
if (is_pooled(tx) && is_confirmable_tx(tx))
return true;
}

return false;
}

TEMPLATE
code CLASS::get_pooled(pooled_tx& out, const tx_link& link,
const context& ctx) const NOEXCEPT
Expand Down
13 changes: 9 additions & 4 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,18 @@ class query
size_t filter_bk_size() const NOEXCEPT;
size_t filter_tx_size() const NOEXCEPT;

/// Buckets (hashmap + arraymap).
/// Buckets (hashmap + arraymap + headmap).
size_t header_buckets() const NOEXCEPT;
size_t ins_buckets() const NOEXCEPT;
size_t outs_buckets() const NOEXCEPT;
size_t txs_buckets() const NOEXCEPT;
size_t tx_buckets() const NOEXCEPT;

size_t candidate_buckets() const NOEXCEPT;
size_t confirmed_buckets() const NOEXCEPT;
size_t strong_buckets() const NOEXCEPT;
size_t scan_buckets() const NOEXCEPT;
size_t state_buckets() const NOEXCEPT;
size_t duplicate_buckets() const NOEXCEPT;
size_t prevout_buckets() const NOEXCEPT;
size_t pool_buckets() const NOEXCEPT;
Expand All @@ -260,8 +263,6 @@ class query
size_t outs_records() const NOEXCEPT;
size_t tx_records() const NOEXCEPT;

size_t candidate_records() const NOEXCEPT;
size_t confirmed_records() const NOEXCEPT;
size_t strong_records() const NOEXCEPT;
size_t scan_records() const NOEXCEPT;
size_t scan_prefix_records() const NOEXCEPT;
Expand All @@ -278,7 +279,6 @@ class query
size_t prevalid1_records() const NOEXCEPT;
size_t presilent0_records() const NOEXCEPT;
size_t presilent1_records() const NOEXCEPT;
size_t state_records() const NOEXCEPT;
size_t pool_records() const NOEXCEPT;
size_t spends_records() const NOEXCEPT;
size_t wtxid_records() const NOEXCEPT;
Expand Down Expand Up @@ -454,6 +454,8 @@ class query
inline hash_digest get_tx_key(const tx_link& link) const NOEXCEPT;
hash_digest get_wtxid(const tx_link& link) const NOEXCEPT;
inline ins_key get_point_key(const ins_link& link) const NOEXCEPT;
inline hash_digest get_outs_key(const outs_link& link) const NOEXCEPT;
inline hash_digest get_wtxid_key(const pool_link& link) const NOEXCEPT;
inline hash_digest get_point_hash(const ins_link& link) const NOEXCEPT;

/// False position implies not confirmed (or fault).
Expand Down Expand Up @@ -706,6 +708,9 @@ class query
/// Unconfirmed, and not conflicted by a confirmed tx (or via ancestry).
bool is_confirmable_tx(const tx_link& link) const NOEXCEPT;

/// Spent by a pooled and confirmable tx.
bool is_confirmable_spent(const output_link& link) const NOEXCEPT;

/// Confirmable tx links, from cursor toward end, at most limit.
code get_confirmable_txs(pool_link& cursor, tx_links& out,
const pool_link& end, size_t limit) 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 @@ -146,6 +146,26 @@ struct output
bool match{};
};

/// Unstreamed, hashes the script in place.
struct get_script_hash
: public schema::output
{
inline bool from_data(memory::iterator start) NOEXCEPT
{
using namespace system;

// Skip parent fk and value, and read the script size.
const auto* position = std::next(start, tx::size);
unsafe_from_variable(position);
const auto script_size = unsafe_from_variable(position);
const auto bytes = possible_narrow_cast<size_t>(script_size);
hash = accumulator<sha256>::hash(bytes, position);
return true;
}

system::hash_digest hash{};
};

/// Unstreamed, writes full output directly to the sink.
struct write_script
: public schema::output
Expand Down
6 changes: 3 additions & 3 deletions test/query/extent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ BOOST_AUTO_TEST_CASE(query_extent__buckets__genesis__expected)
BOOST_REQUIRE_EQUAL(query.txs_buckets(), 128u);
BOOST_REQUIRE_EQUAL(query.tx_buckets(), 128u);

BOOST_REQUIRE_EQUAL(query.candidate_buckets(), one);
BOOST_REQUIRE_EQUAL(query.confirmed_buckets(), one);
BOOST_REQUIRE_EQUAL(query.strong_buckets(), 128u);
BOOST_REQUIRE_EQUAL(query.state_buckets(), one);
BOOST_REQUIRE_EQUAL(query.duplicate_buckets(), 128u);
BOOST_REQUIRE_EQUAL(query.prevout_buckets(), 128);
BOOST_REQUIRE_EQUAL(query.pool_buckets(), 128u);
Expand All @@ -119,16 +122,13 @@ BOOST_AUTO_TEST_CASE(query_extent__records__genesis__expected)
BOOST_REQUIRE_EQUAL(query.outs_records(), one);
BOOST_REQUIRE_EQUAL(query.tx_records(), one);

BOOST_REQUIRE_EQUAL(query.candidate_records(), one);
BOOST_REQUIRE_EQUAL(query.confirmed_records(), one);
BOOST_REQUIRE_EQUAL(query.strong_records(), one);
BOOST_REQUIRE_EQUAL(query.scan_records(), zero);
BOOST_REQUIRE_EQUAL(query.ecdsa0_records(), zero);
BOOST_REQUIRE_EQUAL(query.schnorr0_records(), zero);
BOOST_REQUIRE_EQUAL(query.duplicate_records(), zero);
BOOST_REQUIRE_EQUAL(query.prevalid0_records(), zero);
BOOST_REQUIRE_EQUAL(query.presilent0_records(), zero);
BOOST_REQUIRE_EQUAL(query.state_records(), one);
BOOST_REQUIRE_EQUAL(query.pool_records(), zero);
BOOST_REQUIRE_EQUAL(query.spends_records(), zero);
BOOST_REQUIRE_EQUAL(query.wtxid_records(), zero);
Expand Down
13 changes: 13 additions & 0 deletions test/query/navigate/navigate_natural.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,19 @@ BOOST_AUTO_TEST_CASE(query_navigate__get_point_key__always__expected)
BOOST_CHECK_EQUAL(query.get_point_hash(4), system::one_hash);
}

// get_outs_key

BOOST_AUTO_TEST_CASE(query_navigate__get_outs_key__genesis__expected)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_CHECK(!store.create(test::events_handler));
BOOST_CHECK(query.initialize(test::genesis));
BOOST_CHECK_EQUAL(query.get_outs_key(0), test::genesis.transactions_ptr()->front()->outputs_ptr()->front()->script().hash());
}

// get_tx_key

BOOST_AUTO_TEST_CASE(query_navigate__get_tx_key__always__expected)
Expand Down
40 changes: 40 additions & 0 deletions test/query/pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,46 @@ BOOST_AUTO_TEST_CASE(query_pool__get_pooled__without_bip113__unvalidated)
BOOST_REQUIRE_EQUAL(query.get_pooled(pooled, 1, context{ 0, 8, 9 }), error::unvalidated);
}

// is_confirmable_spent

BOOST_AUTO_TEST_CASE(query_pool__is_confirmable_spent__pooled_spender__true)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
BOOST_REQUIRE(query.initialize(test::genesis));
store.set_pooling();

const auto parent = to_spend(genesis_coinbase(), 2u);
const auto child = to_spend(parent.hash(false), 1u);
BOOST_REQUIRE(archive_pool(query, parent));
BOOST_REQUIRE(!query.is_confirmable_spent(query.to_output(parent.hash(false), 0)));

BOOST_REQUIRE(archive_pool(query, child));
BOOST_REQUIRE(query.is_confirmable_spent(query.to_output(parent.hash(false), 0)));
BOOST_REQUIRE(!query.is_confirmable_spent(query.to_output(child.hash(false), 0)));
}

BOOST_AUTO_TEST_CASE(query_pool__is_confirmable_spent__conflicted_spender__false)
{
settings settings{};
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE(!store.create(test::events_handler));
BOOST_REQUIRE(query.initialize(test::genesis));
store.set_pooling();

const auto parent = to_spend(genesis_coinbase(), 2u);
const auto child = to_spend(parent.hash(false), 1u);
BOOST_REQUIRE(archive_pool(query, parent));
BOOST_REQUIRE(archive_pool(query, child));
BOOST_REQUIRE(!archive_confirm(query, to_spend(genesis_coinbase(), 3u)).is_terminal());
BOOST_REQUIRE(!query.is_confirmable_spent(query.to_output(parent.hash(false), 0)));
}

// get_pooled_time

BOOST_AUTO_TEST_CASE(query_pool__get_pooled_time__pooled__expected)
Expand Down
Loading