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
1 change: 0 additions & 1 deletion include/bitcoin/node/chasers/chaser_validate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ class BCN_API chaser_validate
// These are thread safe.
const uint32_t subsidy_interval_;
const uint64_t initial_subsidy_;
const size_t silent_start_height_;
const size_t maximum_backlog_;
const size_t maximum_height_;
const uint64_t batch_target_;
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/node/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ enum error_t : uint8_t
transaction3,
transaction4,
transaction5,
transaction6,
estimates_initialize,
estimates_push1,
estimates_push2,
Expand Down
67 changes: 52 additions & 15 deletions src/chasers/chaser_transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,19 @@ void chaser_transaction::do_submit(const transactions_cptr& txs, bool test,
return;
}

if (!pooled && !query.set_pooled(link, tx, pool_))
if (!pooled)
{
handler(fault(error::transaction2), index);
return;
if (!query.set_pooled(link, tx, pool_))
{
handler(fault(error::transaction2), index);
return;
}

if (query.silent_enabled() && !query.set_silent(link, tx))
{
handler(fault(error::transaction6), index);
return;
}
}

fire(events::tx_archived, to_rate(tx));
Expand Down Expand Up @@ -233,29 +242,43 @@ void chaser_transaction::do_submit_compact(const transactions_cptr& txs,
return;
}

// Txs are an arbitrary subset of the block, so block checks are deferred to
// validation. Each is archived before the next, so in block order a parent
// is resolved from the store.
size_t index{};
auto filled = links;
for (auto& fk: filled)
using link_t = database::tx_link::integer;
const auto filler = [&](link_t& fk, size_t index) NOEXCEPT
{
if (fk != terminal)
continue;

database::tx_link out{};
if (const auto ec = fill(out, *txs->at(index), ctx))
{
const auto faulted = node::error::error_category::contains(ec) ||
database::error::error_category::contains(ec);
handler(faulted ? ec : unconfirmable(link, ctx.height, ec), index);
return;
return false;
}

fk = out;
return true;
};

// Txs are an arbitrary subset of the block, so block checks are deferred to
// validation. Each is archived before the next, so in block order a parent
// is resolved from the store. The coinbase (never a parent within its
// block) is archived last, as validation indexes only txs linked above it.
auto filled = links;
const auto deferred = filled.front() == terminal;
auto index = deferred ? one : zero;
for (auto fk = std::next(filled.begin()); fk != filled.end(); ++fk)
{
if (*fk != terminal)
continue;

if (!filler(*fk, index))
return;

++index;
}

if (deferred && !filler(filled.front(), zero))
return;

const auto strong = is_under_checkpoint(ctx.height);
if (const auto ec = query.set_code(link, filled, strong))
{
Expand Down Expand Up @@ -301,8 +324,22 @@ code chaser_transaction::fill(database::tx_link& out,
if (const auto ec = query.set_code(out, pooled, tx))
return fault(ec);

if (!pooled && !tx.is_coinbase() && !query.set_pooled(out, tx, ctx))
return fault(error::transaction2);
const auto coinbase = tx.is_coinbase();
if (!pooled && !coinbase)
{
if (!query.set_pooled(out, tx, ctx))
return fault(error::transaction2);

if (ctx.height >= query.silent_start_height() &&
!query.set_silent(out, tx))
return fault(error::transaction6);
}

if (!coinbase)
{
fire(events::tx_archived, to_rate(tx));
notify(error::success, chases::transaction{ out });
}

return error::success;
}
Expand Down
4 changes: 2 additions & 2 deletions src/chasers/chaser_validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ chaser_validate::chaser_validate(full_node& node) NOEXCEPT
validation_strand_(validation_threadpool_.service().get_executor()),
subsidy_interval_(node.system_settings().subsidy_interval_blocks),
initial_subsidy_(node.system_settings().initial_subsidy()),
silent_start_height_(node.node_settings().silent_start_height),
maximum_backlog_(node.node_settings().maximum_concurrency_()),
maximum_height_(node.node_settings().maximum_height_()),
batch_target_(node.node_settings().batch_signatures),
Expand Down Expand Up @@ -210,13 +209,14 @@ void chaser_validate::do_bumped(height_t height) NOEXCEPT

const auto bypass = is_under_checkpoint(height) ||
query.is_milestone(link);
const auto silent = height >= query.silent_start_height();

switch (ec.value())
{
case database::error::unvalidated:
case database::error::unknown_state:
{
if (bypass && !filter_)
if (bypass && !filter_ && !silent)
{
complete_block(error::success, link, height, true);
}
Expand Down
8 changes: 4 additions & 4 deletions src/chasers/chaser_validate_parallel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ code chaser_validate::populate(bool bypass, const chain::block& block,

if (bypass)
{
// Populating for filters only (no validation metadata required).
// Populating for optional indexes only (no validation metadata).
block.populate(ctx);
if (!query.populate_without_metadata(block))
return system::error::missing_previous_output;
Expand Down Expand Up @@ -139,12 +139,12 @@ code chaser_validate::validate_pooled(bool& pooled, const header_link& link,
error::validate11 : ec;
}

// A pooled block is valid, so is produced only as required for filters.
// A pooled block is valid, so is produced only as required for indexes.
code chaser_validate::complete_pooled(const header_link& link,
const chain::context& ctx) NOEXCEPT
{
auto& query = archive();
if (filter_ || (ctx.height >= silent_start_height_))
if (filter_ || (ctx.height >= query.silent_start_height()))
{
bool batched{}, capturing{};
constexpr auto bypass = true;
Expand Down Expand Up @@ -210,7 +210,7 @@ code chaser_validate::validate(bool& batched, bool& capturing, bool bypass,
if (!query.set_filter_body(link, block))
return error::validate8;

if ((ctx.height >= silent_start_height_) &&
if ((ctx.height >= query.silent_start_height()) &&
!query.set_silent(link, block))
return error::validate9;

Expand Down
14 changes: 13 additions & 1 deletion src/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,21 @@ configuration::configuration(system::chain::selection context) NOEXCEPT
{
}

// Silent payment indexing requires witness data, which a pruned store does not
// archive for checkpointed or milestoned (bypassed) blocks.
code configuration::initialize() NOEXCEPT
{
database.initialize(bitcoin, node.limited_blocks);
const auto silent = node.silent_start_height != max_uint32;
if (silent && !node.require_witness)
return network::error::invalid_configuration;

const auto checkpoint = bitcoin.top_checkpoint().height();
const auto milestone = bitcoin.milestone.height();
const auto bypassed = std::max(checkpoint, milestone);
if (silent && node.limited_blocks && node.silent_start_height <= bypassed)
return network::error::invalid_configuration;

database.initialize(bitcoin, node.limited_blocks, node.silent_start_height);
return network.initialize();
}

Expand Down
1 change: 1 addition & 0 deletions src/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)
{ transaction3, "transaction3" },
{ transaction4, "transaction4" },
{ transaction5, "transaction5" },
{ transaction6, "transaction6" },
{ estimates_initialize, "estimates_initialize" },
{ estimates_push1, "estimates_push1" },
{ estimates_push2, "estimates_push2" },
Expand Down
43 changes: 43 additions & 0 deletions test/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,47 @@ BOOST_AUTO_TEST_CASE(configuration__initialize__mainnet__success_peer_identifier
BOOST_REQUIRE_EQUAL(instance.network.peer.identifier, 0xd9b4bef9_u32);
}

BOOST_AUTO_TEST_CASE(configuration__initialize__silent_without_witness__invalid_configuration)
{
node::configuration instance(chain::selection::mainnet);
instance.node.silent_start_height = 0;
instance.node.require_witness = false;
BOOST_REQUIRE_EQUAL(instance.initialize(), network::error::invalid_configuration);
}

BOOST_AUTO_TEST_CASE(configuration__initialize__silent_with_witness__success)
{
node::configuration instance(chain::selection::mainnet);
instance.node.silent_start_height = 0;
instance.node.require_witness = true;
BOOST_REQUIRE(!instance.initialize());
}

BOOST_AUTO_TEST_CASE(configuration__initialize__limited_silent_at_bypassed__invalid_configuration)
{
node::configuration instance(chain::selection::mainnet);
const auto bypassed = std::max(instance.bitcoin.top_checkpoint().height(), instance.bitcoin.milestone.height());
instance.node.limited_blocks = true;
instance.node.silent_start_height = possible_narrow_cast<uint32_t>(bypassed);
BOOST_REQUIRE_EQUAL(instance.initialize(), network::error::invalid_configuration);
}

BOOST_AUTO_TEST_CASE(configuration__initialize__limited_silent_above_bypassed__success)
{
node::configuration instance(chain::selection::mainnet);
const auto bypassed = std::max(instance.bitcoin.top_checkpoint().height(), instance.bitcoin.milestone.height());
instance.node.limited_blocks = true;
instance.node.silent_start_height = possible_narrow_cast<uint32_t>(add1(bypassed));
BOOST_REQUIRE(!instance.initialize());
}

BOOST_AUTO_TEST_CASE(configuration__initialize__unlimited_silent_at_bypassed__success)
{
node::configuration instance(chain::selection::mainnet);
const auto bypassed = std::max(instance.bitcoin.top_checkpoint().height(), instance.bitcoin.milestone.height());
instance.node.limited_blocks = false;
instance.node.silent_start_height = possible_narrow_cast<uint32_t>(bypassed);
BOOST_REQUIRE(!instance.initialize());
}

BOOST_AUTO_TEST_SUITE_END()
Loading