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
6 changes: 4 additions & 2 deletions include/bitcoin/database/impl/query/archive/wire_writer.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,9 @@ code CLASS::set_code(const block_view& block, const header_link& key,
// Optional hash, only has value on height intervals.
auto interval = create_interval(key, height);

// Depth is only set by writer for genesis (is_zero(tx_fks[0])).
// Depth/forks only set by writer for genesis (is_zero(tx_fks[0])).
const auto depth = store_.interval_depth();
const auto forks = store_.fork_flags();

using bytes = linkage<schema::size>::integer;
const auto light = possible_narrow_cast<bytes>(
Expand All @@ -290,7 +291,8 @@ code CLASS::set_code(const block_view& block, const header_link& key,
count,
tx_fks,
std::move(interval),
depth
depth,
forks
}) ? error::success : error::txs_txs_put;
// ========================================================================
}
Expand Down
8 changes: 8 additions & 0 deletions include/bitcoin/database/impl/query/initialize.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ namespace database {
// Initialization (natural-keyed).
// ----------------------------------------------------------------------------

// server (warning)
TEMPLATE
uint32_t CLASS::initialized_forks() const NOEXCEPT
{
table::txs::get_genesis_forks txs{};
return store_.txs.at(to_txs(0), txs) ? txs.forks : store_.fork_flags();
}

// server/dumps
TEMPLATE
hash_digest CLASS::get_top_confirmed_hash() const NOEXCEPT
Expand Down
10 changes: 5 additions & 5 deletions include/bitcoin/database/impl/query/merkle.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,13 @@ code CLASS::get_merkle_subroots(hashes& roots, size_t waypoint) const NOEXCEPT
TEMPLATE
size_t CLASS::interval_span() const NOEXCEPT
{
if (const auto span = span_.load(std::memory_order_relaxed);
is_nonzero(span))
return span;
auto span = span_.load(std::memory_order_relaxed);

// initialize_span() never returns zero.
span_.store(initialize_span(), std::memory_order_relaxed);
return span_;
if (is_zero(span))
span_.store(span = initialize_span(), std::memory_order_relaxed);

return span;
}

// protected
Expand Down
6 changes: 6 additions & 0 deletions include/bitcoin/database/impl/store/store.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ uint8_t CLASS::interval_depth() const NOEXCEPT
return system::limit<uint8_t>(configuration_.interval_depth);
}

TEMPLATE
uint32_t CLASS::fork_flags() const NOEXCEPT
{
return configuration_.fork_flags;
}

TEMPLATE
bool CLASS::is_dirty() const NOEXCEPT
{
Expand Down
3 changes: 3 additions & 0 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class query
/// Count of puts not resulting in table body search to detect duplication.
size_t negative_search_count() const NOEXCEPT;

/// Forks configured at store creation.
uint32_t initialized_forks() const NOEXCEPT;

/// Store extent.
/// -----------------------------------------------------------------------

Expand Down
5 changes: 4 additions & 1 deletion include/bitcoin/database/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ struct BCD_API settings
/// Mark blocks as unconfirmable (disorganize vs. stall).
bool mark_unconfirmable{ true };

/// Depth of electrum merkle tree interval caching.
/// Depth of merkle tree interval caching (used at store create only).
uint16_t interval_depth{ max_uint8 };

/// Fork flags upon store creation (used at store create only).
uint32_t fork_flags{};

/// Path to the database directory.
std::filesystem::path path{ "bitcoin" };

Expand Down
5 changes: 4 additions & 1 deletion include/bitcoin/database/store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,12 @@ class store
/// Mark blocks as unconfirmable (disorganize vs. stall), configuration.
bool mark_unconfirmable() const NOEXCEPT;

/// Depth of electrum merkle tree interval caching.
/// Depth of electrum merkle tree interval caching upon store creation.
uint8_t interval_depth() const NOEXCEPT;

/// Fork flags upon store creation.
uint32_t fork_flags() const NOEXCEPT;

/// Determine if the store is non-empty/initialized.
bool is_dirty() const NOEXCEPT;
void set_dirty() NOEXCEPT;
Expand Down
72 changes: 63 additions & 9 deletions include/bitcoin/database/tables/archives/txs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct txs
: public array_map<schema::txs>
{
using ct = linkage<schema::count_>;
using flags = linkage<schema::flags>;
using tx = schema::transaction::link;
using keys = std::vector<tx::integer>;
using bytes = linkage<schema::size, sub1(to_bits(schema::size))>;
Expand Down Expand Up @@ -83,7 +84,7 @@ struct txs
return system::possible_narrow_cast<link::integer>(
skip_sizes + ct::size + (tx_fks.size() * tx::size) +
(interval.has_value() ? schema::hash : zero) +
to_int(is_genesis()));
(is_genesis() ? one + flags::size : zero));
}

inline bool from_data(reader& source) NOEXCEPT
Expand All @@ -104,8 +105,13 @@ struct txs
interval.reset();
if (is_interval(merged)) interval = source.read_hash();

// depth (genesis only)
depth = is_genesis() ? source.read_byte() : zero;
// depth/forks (genesis only)
if (is_genesis())
{
depth = source.read_byte();
forks = source.read_little_endian<flags::integer, flags::size>();
}

BC_ASSERT(!source || source.get_read_position() == count());
return source;
}
Expand All @@ -131,8 +137,13 @@ struct txs
// interval (when specified)
if (interval.has_value()) sink.write_bytes(interval.value());

// depth (genesis only)
if (is_genesis()) sink.write_byte(depth);
// depth/forks (genesis only)
if (is_genesis())
{
sink.write_byte(depth);
sink.write_little_endian<flags::integer, flags::size>(forks);
}

BC_ASSERT(!sink || sink.get_write_position() == count());
return sink;
}
Expand All @@ -143,14 +154,16 @@ struct txs
&& heavy == other.heavy
&& tx_fks == other.tx_fks
&& interval == other.interval
&& depth == other.depth;
&& depth == other.depth
&& forks == other.forks;
}

bytes::integer light{};
bytes::integer heavy{};
keys tx_fks{};
hash interval{};
uint8_t depth{};
flags::integer forks{};
};

// put a contiguous set of tx identifiers.
Expand All @@ -167,7 +180,7 @@ struct txs
return system::possible_narrow_cast<link::integer>(
skip_sizes + ct::size + (number * tx::size) +
(interval.has_value() ? schema::hash : zero) +
to_int(is_zero(tx_fk)));
(is_genesis() ? one + flags::size : zero));
}

inline bool to_data(finalizer& sink) const NOEXCEPT
Expand All @@ -185,8 +198,13 @@ struct txs
// interval (when specified)
if (interval.has_value()) sink.write_bytes(interval.value());

// depth (genesis only)
if (is_genesis()) sink.write_byte(depth);
// depth/forks (genesis only)
if (is_genesis())
{
sink.write_byte(depth);
sink.write_little_endian<flags::integer, flags::size>(forks);
}

BC_ASSERT(!sink || sink.get_write_position() == count());
return sink;
}
Expand All @@ -197,6 +215,7 @@ struct txs
tx::integer tx_fk{};
hash interval{};
uint8_t depth{};
flags::integer forks{};
};

struct get_interval
Expand Down Expand Up @@ -259,6 +278,41 @@ struct txs
uint8_t depth{};
};

// This reader is only applicable to the genesis block.
struct get_genesis_forks
: public schema::txs
{
inline link count() const NOEXCEPT
{
BC_ASSERT(false);
return {};
}

// Stored at end since only read once (at startup).
inline bool from_data(reader& source) NOEXCEPT
{
// tx sizes
const auto merged = source.read_little_endian<bytes::integer, bytes::size>();
source.skip_bytes(bytes::size);

// tx fks
const auto number = source.read_little_endian<ct::integer, ct::size>();
source.skip_bytes(number * tx::size);

// interval
source.skip_bytes(is_interval(merged) ? schema::hash : zero);

// depth
source.skip_byte();

// forks
forks = source.read_little_endian<flags::integer, flags::size>();
return source;
}

flags::integer forks{};
};

struct get_position
: public schema::txs
{
Expand Down
10 changes: 6 additions & 4 deletions test/query/archive/chain_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ BOOST_AUTO_TEST_CASE(query_chain_writer__set_block__get_block__expected)
"4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73" // script
"00"); // witness
const auto genesis_txs_head = system::base16_chunk(
"0d00000000" // slab size
"1100000000" // slab size
"0000000000" // pk->
"ffffffffff"
"ffffffffff"
Expand All @@ -538,7 +538,8 @@ BOOST_AUTO_TEST_CASE(query_chain_writer__set_block__get_block__expected)
"1d0100" // size heavy (285)
"0100" // txs count (1)
"00000000" // transaction[0]
"ff"); // depth (255)
"ff" // depth (255) - genesis only
"00000000"); // forks (0) - genesis only

settings settings{};
settings.header_buckets = 8;
Expand Down Expand Up @@ -664,7 +665,7 @@ BOOST_AUTO_TEST_CASE(query_chain_writer__set_block_txs__get_block__expected)
"4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73" // script
"00"); // witness
const auto genesis_txs_head = system::base16_chunk(
"0d00000000" // slab size
"1100000000" // slab size
"0000000000" // pk->
"ffffffffff"
"ffffffffff"
Expand All @@ -686,7 +687,8 @@ BOOST_AUTO_TEST_CASE(query_chain_writer__set_block_txs__get_block__expected)
"1d0100" // size heavy (285)
"0100" // txs count (1)
"00000000" // transaction[0]
"ff"); // depth (255)
"ff" // depth (255) - genesis only
"00000000"); // forks (0) - genesis only

settings settings{};
settings.header_buckets = 8;
Expand Down
2 changes: 1 addition & 1 deletion test/query/extent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(query_extent__body_sizes__genesis__expected)
BOOST_REQUIRE_EQUAL(query.point_body_size(), schema::point::minrow);
BOOST_REQUIRE_EQUAL(query.ins_body_size(), schema::ins::minrow);
BOOST_REQUIRE_EQUAL(query.outs_body_size(), schema::outs::minrow);
BOOST_REQUIRE_EQUAL(query.txs_body_size(), add1(schema::txs::minrow));
BOOST_REQUIRE_EQUAL(query.txs_body_size(), schema::txs::minrow + one + schema::flags);
BOOST_REQUIRE_EQUAL(query.tx_body_size(), schema::transaction::minrow);

BOOST_REQUIRE_EQUAL(query.candidate_body_size(), schema::height::minrow);
Expand Down
1 change: 1 addition & 0 deletions test/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ BOOST_AUTO_TEST_CASE(settings__construct__default__expected)
BOOST_REQUIRE_EQUAL(configuration.turbo, false);
BOOST_REQUIRE_EQUAL(configuration.mark_unconfirmable, true);
BOOST_REQUIRE_EQUAL(configuration.interval_depth, 255u);
BOOST_REQUIRE_EQUAL(configuration.fork_flags, 0u);
BOOST_REQUIRE_EQUAL(configuration.path, "bitcoin");

// Archives.
Expand Down
12 changes: 9 additions & 3 deletions test/tables/archives/txs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ const table::txs::slab slab0
// tx fk 0 uniquely identifies genesis, resulting in depth storage.
0x00000000_u32
},
{}, // interval (unused due to default span)
0x42 // depth (genesis only)
{}, // interval (unused due to default span)
0x42, // depth (genesis only)
0x12345678 // flags (genesis only)
};
const table::txs::slab slab1
{
Expand Down Expand Up @@ -81,7 +82,10 @@ const data_chunk expected0
0x00, 0x00, 0x00, 0x00,

// depth (genesis)
0x42
0x42,

// flags (genesis)
0x78, 0x56, 0x34, 0x12
};
const data_chunk expected1
{
Expand Down Expand Up @@ -147,6 +151,8 @@ BOOST_AUTO_TEST_CASE(txs__put__get__expected)
BOOST_CHECK(slab == slab0);
BOOST_CHECK_EQUAL(body_store.buffer(), build_chunk({ expected0 }));

slab.depth = {};
slab.forks = {};
BOOST_CHECK(instance.put(key, slab1));
BOOST_CHECK(instance.exists(key));
BOOST_CHECK(instance.at(key, slab));
Expand Down
Loading