diff --git a/include/bitcoin/node/chasers/chaser_confirm.hpp b/include/bitcoin/node/chasers/chaser_confirm.hpp index 78a1b4f4..a5f18a4b 100644 --- a/include/bitcoin/node/chasers/chaser_confirm.hpp +++ b/include/bitcoin/node/chasers/chaser_confirm.hpp @@ -94,6 +94,7 @@ class BCN_API chaser_confirm // These are protected by strand. network::threadpool threadpool_; neutrino_header neutrino_{}; + bool filters_{}; bool mature_{}; }; diff --git a/include/bitcoin/node/chasers/chaser_validate.hpp b/include/bitcoin/node/chasers/chaser_validate.hpp index 6491c666..dd5a98fc 100644 --- a/include/bitcoin/node/chasers/chaser_validate.hpp +++ b/include/bitcoin/node/chasers/chaser_validate.hpp @@ -61,9 +61,17 @@ class BCN_API chaser_validate bool stranded() const NOEXCEPT override; private: + inline bool unfilled() const NOEXCEPT + { + return backlog_ < maximum_backlog_; + } + bool set_neutrino(const database::header_link& link, const system::chain::block& block) NOEXCEPT; + bool set_prevouts(size_t height, + const system::chain::block& block) NOEXCEPT; + // These are thread safe. const bool concurrent_; const size_t maximum_backlog_; @@ -74,6 +82,7 @@ class BCN_API chaser_validate // These are protected by strand. network::threadpool threadpool_; size_t backlog_{}; + bool filters_{}; bool mature_{}; }; diff --git a/src/chasers/chaser_confirm.cpp b/src/chasers/chaser_confirm.cpp index 6abfae82..8c4559b2 100644 --- a/src/chasers/chaser_confirm.cpp +++ b/src/chasers/chaser_confirm.cpp @@ -49,7 +49,9 @@ chaser_confirm::chaser_confirm(full_node& node) NOEXCEPT code chaser_confirm::start() NOEXCEPT { - reset_position(archive().get_fork()); + const auto& query = archive(); + filters_ = query.neutrino_enabled(); + reset_position(query.get_fork()); SUBSCRIBE_EVENTS(handle_event, _1, _2, _3); return error::success; } @@ -70,9 +72,6 @@ void chaser_confirm::stop() NOEXCEPT } } -// Protected -// ---------------------------------------------------------------------------- - bool chaser_confirm::handle_event(const code&, chase event_, event_value value) NOEXCEPT { @@ -147,6 +146,9 @@ bool chaser_confirm::handle_event(const code&, chase event_, return true; } +// track validation +// ---------------------------------------------------------------------------- + void chaser_confirm::do_regressed(height_t branch_point) NOEXCEPT { BC_ASSERT(stranded()); @@ -164,11 +166,11 @@ void chaser_confirm::do_regressed(height_t branch_point) NOEXCEPT reset_position(branch_point); } +// Candidate block validated at given height, if next then confirm/advance. void chaser_confirm::do_validated(height_t height) NOEXCEPT { BC_ASSERT(stranded()); - // Candidate block was validated at the given height, confirm/advance. if (height == add1(position())) do_bump(height); } @@ -618,11 +620,11 @@ bool chaser_confirm::update_neutrino(const header_link& link) NOEXCEPT BC_ASSERT(archive().get_height(link) == add1(archive().get_height(neutrino_.link))); - auto& query = archive(); - if (!query.neutrino_enabled()) + if (!filters_) return true; data_chunk filter{}; + auto& query = archive(); if (!query.get_filter_body(filter, link)) return false; @@ -637,9 +639,9 @@ void chaser_confirm::reset_position(size_t confirmed_height) NOEXCEPT { set_position(confirmed_height); - const auto& query = archive(); - if (query.neutrino_enabled()) + if (filters_) { + const auto& query = archive(); neutrino_.link = query.to_confirmed(confirmed_height); query.get_filter_head(neutrino_.head, neutrino_.link); } diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index f03bd5c4..87eb1e37 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -54,7 +54,9 @@ chaser_validate::chaser_validate(full_node& node) NOEXCEPT code chaser_validate::start() NOEXCEPT { - set_position(archive().get_fork()); + const auto& query = archive(); + filters_ = query.neutrino_enabled(); + set_position(query.get_fork()); SUBSCRIBE_EVENTS(handle_event, _1, _2, _3); return error::success; } @@ -137,7 +139,7 @@ bool chaser_validate::handle_event(const code&, chase event_, return true; } -// track downloaded in order (to validate) +// track downloaded // ---------------------------------------------------------------------------- void chaser_validate::do_regressed(height_t branch_point) NOEXCEPT @@ -151,11 +153,11 @@ void chaser_validate::do_regressed(height_t branch_point) NOEXCEPT set_position(branch_point); } +// Candidate block checked at given height, if next then validate/advance. void chaser_validate::do_checked(height_t height) NOEXCEPT { BC_ASSERT(stranded()); - // Candidate block was checked at the given height, validate/advance. if (height == add1(position())) do_bump(height); } @@ -166,8 +168,7 @@ void chaser_validate::do_bump(height_t) NOEXCEPT const auto& query = archive(); // Bypass until next event if validation backlog is full. - for (auto height = add1(position()); - (backlog_ < maximum_backlog_) && !closed(); ++height) + for (auto height = add1(position()); unfilled() && !closed(); ++height) { const auto link = query.to_candidate(height); const auto ec = query.get_block_state(link); @@ -195,12 +196,11 @@ void chaser_validate::do_bump(height_t) NOEXCEPT continue; } - // concurrent by block - boost::asio::post(threadpool_.service(), - BIND(validate_block, link)); + PARALLEL(validate_block, link); } } +// unstranded (concurrent by block) void chaser_validate::validate_block(const header_link& link) NOEXCEPT { if (closed()) @@ -221,13 +221,9 @@ void chaser_validate::validate_block(const header_link& link) NOEXCEPT return; } - /////////////////////////////////////////////////////////////////////////// - // TODO: need to be able to differente populated here vs. store. - // TODO: as this tells us what not to cache. - /////////////////////////////////////////////////////////////////////////// if (!block->populate()) { - // Any input.metadata.locked is invalid for relative locktime (bip68). + // input.metadata.locked set invalid for relative locktime (bip68). // Otherwise internal spends do not require confirmability checks. POST(complete_block, error::validate3, link, ctx.height); return; @@ -253,10 +249,8 @@ void chaser_validate::validate_block(const header_link& link) NOEXCEPT } else { - /////////////////////////////////////////////////////////////////////// - // TODO: cache external spends. - /////////////////////////////////////////////////////////////////////// set_neutrino(link, *block); + set_prevouts(ctx.height, *block); fire(events::block_validated, ctx.height); } @@ -293,21 +287,22 @@ void chaser_validate::complete_block(const code& ec, const header_link& link, handle_event(ec, chase::bump, height_t{}); } -// neutrino +// setters // ---------------------------------------------------------------------------- +// unstranded (concurrent by block) -// This can only fail if prevouts are not fully populated or set_filter fails. bool chaser_validate::set_neutrino(const header_link& link, const chain::block& block) NOEXCEPT { - auto& query = archive(); - if (!query.neutrino_enabled()) + if (!filters_) return true; // Avoid computing the filter if already stored. + auto& query = archive(); if (!query.to_filter(link).is_terminal()) return true; + // Only fails if prevouts are not fully populated. data_chunk filter{}; if (!neutrino::compute_filter(filter, block)) return false; @@ -315,6 +310,13 @@ bool chaser_validate::set_neutrino(const header_link& link, return query.set_filter_body(link, filter); } +bool chaser_validate::set_prevouts(size_t, const chain::block&) NOEXCEPT +{ + // TODO: need to be able to differentiate internal vs. store. + // This tells us what to cache, skip internal and set store populated. + return {}; +} + // Strand. // ----------------------------------------------------------------------------