Skip to content

Commit

Permalink
Add hash to context query, add set/set_link(txs) query.
Browse files Browse the repository at this point in the history
  • Loading branch information
evoskuil committed Feb 25, 2024
1 parent 1924e40 commit e7e4acc
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 10 deletions.
33 changes: 33 additions & 0 deletions include/bitcoin/database/impl/query/archive.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ inline bool CLASS::set(const hash_digest& point_hash) NOEXCEPT
return !set_link(point_hash).is_terminal();
}

TEMPLATE
inline bool CLASS::set(const block& block) NOEXCEPT
{
return !set_link(block).is_terminal();
}

TEMPLATE
inline bool CLASS::set(const transaction& tx) NOEXCEPT
{
Expand Down Expand Up @@ -710,6 +716,33 @@ header_link CLASS::set_link(const block& block, const context& ctx) NOEXCEPT
// ========================================================================
}

TEMPLATE
header_link CLASS::set_link(const block& block) NOEXCEPT
{
// This sets only the txs of a block with header/context already archived.
const auto header_fk = to_header(block.hash());
if (header_fk.is_terminal())
return {};

// GUARDED (block (txs) redundancy)
// This guard is only effective if there is a single database thread.
if (is_associated(header_fk))
return header_fk;

tx_links links{};
links.reserve(block.transactions_ptr()->size());
for (const auto& tx: *block.transactions_ptr())
if (!push_link_value(links, set_link(*tx)))
return {};

// ========================================================================
const auto scope = store_.get_transactor();

return store_.txs.put(header_fk, table::txs::slab{ {}, links }) ?
header_fk : table::header::link{};
// ========================================================================
}

} // namespace database
} // namespace libbitcoin

Expand Down
7 changes: 4 additions & 3 deletions include/bitcoin/database/impl/query/validate.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,14 @@ bool CLASS::get_context(context& ctx,
}

TEMPLATE
bool CLASS::get_context_and_timestamp(context& ctx, uint32_t& timestamp,
const header_link& link) const NOEXCEPT
bool CLASS::get_check_context(context& ctx, hash_digest& hash,
uint32_t& timestamp, const header_link& link) const NOEXCEPT
{
table::header::get_context_and_timestamp header{};
table::header::get_check_context header{};
if (!store_.header.get(link, header))
return false;

hash = std::move(header.key);
ctx = std::move(header.ctx);
timestamp = header.timestamp;
return true;
Expand Down
5 changes: 4 additions & 1 deletion include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class query
using output = system::chain::output;
using header = system::chain::header;
using transaction = system::chain::transaction;
using transactions = system::chain::transaction_cptrs;
using inputs_ptr = system::chain::inputs_ptr;
using outputs_ptr = system::chain::outputs_ptr;
using transactions_ptr = system::chain::transactions_ptr;
Expand Down Expand Up @@ -198,6 +199,7 @@ class query
inline bool set(const header& header, const context& ctx) NOEXCEPT;
inline bool set(const block& block, const chain_context& ctx) NOEXCEPT;
inline bool set(const block& block, const context& ctx) NOEXCEPT;
inline bool set(const block& block) NOEXCEPT;
inline bool set(const hash_digest& point_hash) NOEXCEPT;
inline bool set(const transaction& tx) NOEXCEPT;

Expand Down Expand Up @@ -245,6 +247,7 @@ class query
header_link set_link(const header& header, const context& ctx) NOEXCEPT;
header_link set_link(const block& block, const chain_context& ctx) NOEXCEPT;
header_link set_link(const block& block, const context& ctx) NOEXCEPT;
header_link set_link(const block& block) NOEXCEPT;
point_link set_link(const hash_digest& point_hash) NOEXCEPT;
tx_link set_link(const transaction& tx) NOEXCEPT;

Expand Down Expand Up @@ -278,7 +281,7 @@ class query
bool get_version(uint32_t& version, const header_link& link) const NOEXCEPT;
bool get_bits(uint32_t& bits, const header_link& link) const NOEXCEPT;
bool get_context(context& ctx, const header_link& link) const NOEXCEPT;
bool get_context_and_timestamp(context& ctx, uint32_t& timestamp,
bool get_check_context(context& ctx, hash_digest& hash, uint32_t& timestamp,
const header_link& link) const NOEXCEPT;

bool set_block_preconfirmable(const header_link& link) NOEXCEPT;
Expand Down
5 changes: 4 additions & 1 deletion include/bitcoin/database/tables/archives/header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,17 +256,20 @@ struct header
uint32_t mtp{};
};

struct get_context_and_timestamp
struct get_check_context
: public schema::header
{
inline bool from_data(reader& source) NOEXCEPT
{
source.rewind_bytes(sk);
key = source.read_hash();
context::from_data(source, ctx);
source.skip_bytes(link::size + sizeof(uint32_t));
timestamp = source.read_little_endian<uint32_t>();
return source;
}

search_key key{};
context ctx{};
uint32_t timestamp{};
};
Expand Down
151 changes: 150 additions & 1 deletion test/query/archive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ BOOST_AUTO_TEST_CASE(query_archive__set_block__get_block__expected)
BOOST_REQUIRE_EQUAL(store.create(events), error::success);
BOOST_REQUIRE_EQUAL(store.open(events), error::success);

// Set header/tx/association.
// Set block (header/txs).
BOOST_REQUIRE(!query.is_block(test::genesis.hash()));
BOOST_REQUIRE(query.set(test::genesis, test::context));
BOOST_REQUIRE(query.is_block(test::genesis.hash()));
Expand Down Expand Up @@ -606,6 +606,155 @@ BOOST_AUTO_TEST_CASE(query_archive__set_block__get_block__expected)
BOOST_REQUIRE_EQUAL(hashes, test::genesis.transaction_hashes(false));
}

BOOST_AUTO_TEST_CASE(query_archive__set_block_txs__get_block__expected)
{
const auto genesis_header_head = system::base16_chunk(
"010000" // record count
"ffffff" // bucket[0]...
"ffffff"
"ffffff"
"000000" // pk->
"ffffff");
const auto genesis_header_body = system::base16_chunk(
"ffffff" // next->
"6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" // sk (block.hash)
"04030201" // flags
"141312" // height
"24232221" // mtp
"ffffff" // previous_block_hash (header_fk - not found)
"01000000" // version
"29ab5f49" // timestamp
"ffff001d" // bits
"1dac2b7c" // nonce
"3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a"); // merkle_root
const auto genesis_tx_head = system::base16_chunk(
"01000000" // record count
"ffffffff" // bucket[0]...
"ffffffff"
"ffffffff"
"00000000" // pk->
"ffffffff");
const auto genesis_tx_body = system::base16_chunk(
"ffffffff" // next->
"3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a" // sk (tx.hash(false))
"01" // coinbase
"cc0000" // witless
"cc0000" // witness
"00000000" // locktime
"01000000" // version
"010000" // ins_count
"010000" // outs_count
"0000000000"); // puts_fk->
const auto genesis_puts_head = system::base16_chunk("0900000000");
const auto genesis_puts_body = system::base16_chunk(
"00000000" // spend0_fk->
"0000000000"); // output0_fk->

const auto genesis_output_head = system::base16_chunk("5100000000");
const auto genesis_output_body = system::base16_chunk(
"00000000" // parent_fk->
"ff00f2052a01000000" // value
"434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac"); // script
const auto genesis_point_head = system::base16_chunk(
"00000000" // record count (null point, empty)
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff");
const auto genesis_point_body = system::base16_chunk("");
const auto genesis_spend_head = system::base16_chunk(
"01000000" // record count
"00000000" // spend0_fk->
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff");

// ffffffffffffffffffffff00000000ffffffff0000000000
const auto genesis_spend_body = system::base16_chunk(
"ffffffff" // terminal->
"ffffffff" // fp: point_fk->
"ffffff" // fp: point_index (null)
"00000000" // parent_fk->
"ffffffff" // sequence
"0000000000"); // input_fk-> (coinbase)
const auto genesis_input_head = system::base16_chunk("4f00000000");
const auto genesis_input_body = system::base16_chunk(
"4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73" // script
"00"); // witness
const auto genesis_txs_head = system::base16_chunk(
"0f000000" // slabs size
"00000000" // pk->
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff"
"ffffffff");
const auto genesis_txs_body = system::base16_chunk(
"ffffffff" // next->
"000000" // header_fk
"01000000" // txs count (1)
"00000000"); // transaction[0]

settings settings{};
settings.header_buckets = 5;
settings.tx_buckets = 5;
settings.point_buckets = 5;
settings.spend_buckets = 5;
settings.txs_buckets = 10;
settings.path = TEST_DIRECTORY;
test::chunk_store store{ settings };
test::query_accessor query{ store };
BOOST_REQUIRE_EQUAL(store.create(events), error::success);
BOOST_REQUIRE_EQUAL(store.open(events), error::success);

// Set header and then txs.
BOOST_REQUIRE(!query.is_block(test::genesis.hash()));
BOOST_REQUIRE(query.set(test::genesis.header(), test::context));
BOOST_REQUIRE(query.set(test::genesis));
BOOST_REQUIRE(query.is_block(test::genesis.hash()));

// Verify idempotentcy (these do not change store state).
////BOOST_REQUIRE(query.set(test::genesis.header(), test::context));
////BOOST_REQUIRE(query.set(test::genesis.header(), test::context));
////BOOST_REQUIRE(query.set(test::genesis, test::context));
////BOOST_REQUIRE(query.set(test::genesis, test::context));

table::header::record element1{};
BOOST_REQUIRE(store.header.get(query.to_header(test::genesis.hash()), element1));
BOOST_REQUIRE_EQUAL(store.close(events), error::success);

BOOST_REQUIRE_EQUAL(store.header_head(), genesis_header_head);
BOOST_REQUIRE_EQUAL(store.tx_head(), genesis_tx_head);
BOOST_REQUIRE_EQUAL(store.point_head(), genesis_point_head);
BOOST_REQUIRE_EQUAL(store.input_head(), genesis_input_head);
BOOST_REQUIRE_EQUAL(store.output_head(), genesis_output_head);
BOOST_REQUIRE_EQUAL(store.puts_head(), genesis_puts_head);
BOOST_REQUIRE_EQUAL(store.spend_head(), genesis_spend_head);
BOOST_REQUIRE_EQUAL(store.txs_head(), genesis_txs_head);

BOOST_REQUIRE_EQUAL(store.header_body(), genesis_header_body);
BOOST_REQUIRE_EQUAL(store.tx_body(), genesis_tx_body);
BOOST_REQUIRE_EQUAL(store.point_body(), genesis_point_body);
BOOST_REQUIRE_EQUAL(store.input_body(), genesis_input_body);
BOOST_REQUIRE_EQUAL(store.output_body(), genesis_output_body);
BOOST_REQUIRE_EQUAL(store.spend_body(), genesis_spend_body);
BOOST_REQUIRE_EQUAL(store.txs_body(), genesis_txs_body);

const auto pointer1 = query.get_block(query.to_header(test::genesis.hash()));
BOOST_REQUIRE(pointer1);
BOOST_REQUIRE(*pointer1 == test::genesis);

const auto hashes = query.get_tx_keys(query.to_header(test::genesis.hash()));
BOOST_REQUIRE_EQUAL(hashes.size(), 1u);
BOOST_REQUIRE_EQUAL(hashes, test::genesis.transaction_hashes(false));
}

// Moved to protected, set_link(block) covers.
////BOOST_AUTO_TEST_CASE(query_archive__set_links__get_block__expected)
////{
Expand Down
9 changes: 5 additions & 4 deletions test/tables/archives/header.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,11 @@ BOOST_AUTO_TEST_CASE(header__put__get_context__expected)
BOOST_REQUIRE(instance.get(1, context));
BOOST_REQUIRE(context.ctx == expected.ctx);

table::header::get_context_and_timestamp context_and_timestamp{};
BOOST_REQUIRE(instance.get(1, context_and_timestamp));
BOOST_REQUIRE(context_and_timestamp.ctx == expected.ctx);
BOOST_REQUIRE_EQUAL(context_and_timestamp.timestamp, expected.timestamp);
table::header::get_check_context check_context{};
BOOST_REQUIRE(instance.get(1, check_context));
BOOST_REQUIRE(check_context.ctx == expected.ctx);
BOOST_REQUIRE_EQUAL(check_context.timestamp, expected.timestamp);
BOOST_REQUIRE_EQUAL(check_context.key, key);
}

BOOST_AUTO_TEST_CASE(header__it__pk__expected)
Expand Down

0 comments on commit e7e4acc

Please sign in to comment.