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
11 changes: 7 additions & 4 deletions include/bitcoin/node/chasers/chaser_validate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,8 @@ class BCN_API chaser_validate
const header_link& link, bool bypass, bool startup=false) NOEXCEPT;

/// Batching.
virtual bool is_residual() NOEXCEPT;
virtual bool is_mature(bool residual) NOEXCEPT;
virtual code start_batch() NOEXCEPT;
virtual void close_batch() NOEXCEPT;
virtual void push_batch(const header_link& link, size_t height) NOEXCEPT;
virtual void process_batch(bool residual) NOEXCEPT;
virtual code do_process_batch(bool startup) NOEXCEPT;
Expand Down Expand Up @@ -118,12 +117,16 @@ class BCN_API chaser_validate

// Capture helpers.
signatures get_capture(const header_link& link) NOEXCEPT;
std::string log_rate(const std::string& name, size_t numerator,
size_t denominator) const NOEXCEPT;
std::string log_ratio(const std::string& name, size_t numerator,
size_t denominator) const NOEXCEPT;
void log_captures() const NOEXCEPT;

// Batching helpers.
bool is_residual() NOEXCEPT;
bool is_mature(bool residual) NOEXCEPT;
std::string log_rate(const std::string& name, size_t numerator,
size_t denominator) const NOEXCEPT;

// These are protected by strand.
header_links batched_{};
header_links invalids_{};
Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/node/impl/chasers/chaser_organize.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ void CLASS::do_organize(typename Block::cptr block,

// TODO: If any checkpoint is reached then reject non-candidates below.
// TODO: because checkpoints are storable (and therefore stored) along with
// TODO: all ancestor blocks, which therefore much be candidates as well.
// TODO: all ancestor blocks, which therefore must be candidates as well.
// TODO: When a checkpoint is pushed and after its branch is reorganized,
// TODO: purge all blocks in the tree with height at/below that checkpoint.
// TODO: The combination strongly mitigates low pow sybil attacks against
Expand Down
7 changes: 3 additions & 4 deletions src/chasers/chaser_validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,6 @@ void chaser_validate::do_bumped(height_t height) NOEXCEPT
complete_block(error::success, link, height, true);
break;
}
case database::error::block_prevalid:
{
break;
}
case database::error::block_unconfirmable:
{
return;
Expand Down Expand Up @@ -319,6 +315,9 @@ void chaser_validate::notify_block(const code& ec, size_t height,

void chaser_validate::stopping(const code& ec) NOEXCEPT
{
// closed() is now true so time to bump batched_ drain.
POST(close_batch);

// Stop long-running batch validations.
stopping_.store(true);

Expand Down
104 changes: 71 additions & 33 deletions src/chasers/chaser_validate_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,6 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
// ----------------------------------------------------------------------------
// protected

bool chaser_validate::is_residual() NOEXCEPT
{
// Verify residuals when recent.
return maximum_posted_.load() &&
is_zero(batch_backlog_.load()) &&
is_zero(validate_backlog_.load());
}

bool chaser_validate::is_mature(bool residual) NOEXCEPT
{
const auto& query = archive();
const auto ecdsa = query.ecdsa_records();
const auto schnorr = query.schnorr_records();

// Verify non-residuals when mature.
return residual || (ecdsa >= batch_target_) || (schnorr >= batch_target_);
}

// If there was a non-empty batch at startup, process it for invalids and set
// their states normally, then scan from fork point (position()) to association
// gap for all prevalids. Iterate over these setting their states to valid.
Expand All @@ -65,28 +47,49 @@ code chaser_validate::start_batch() NOEXCEPT
if (!batch_enabled_)
return {};

const auto& query = archive();
auto& query = archive();
batched_ = query.get_prevalids();
if (!query.purge_prevalids())
return error::batch1;

if (is_zero(query.ecdsa_records()) && is_zero(query.schnorr_records()))
return {};

// Accumulate all prevalid block links above the fork point.
batched_ = query.get_prevalids(position());
return do_process_batch(true);
}

// Shutdown drains batched_ to block prevalid states, recovered on startup.
// Snapshot restoration purges batch backlog as the tables are not append-only.
void chaser_validate::close_batch() NOEXCEPT
{
BC_ASSERT(stranded());
BC_ASSERT(closed());

// Set even if signature batch tables are empty.
if (is_zero(batch_backlog_.load()))
{
archive().set_prevalids(batched_);
batched_.clear();
}
}

// batched_ is redundant with the combined set of ecdsa/schnorr unfailed block
// identifiers stored in the two batch tables, so just a sort optimization.
void chaser_validate::push_batch(const header_link& link,
size_t height) NOEXCEPT
{
BC_ASSERT(stranded());

if (closed())
return;

// Accumulate even if closed. Sacrifices stop speed to save validations.
batched_.push_back(link);
--batch_backlog_;

if (closed())
{
close_batch();
return;
}

// Unblocks check chaser for download while verifying.
notify({}, chase::prevalid, possible_wide_cast<height_t>(height));

Expand All @@ -112,22 +115,27 @@ void chaser_validate::process_batch(bool residual) NOEXCEPT
// tables to be fully purged upon completion, and ensuring that evaluation
// does not operate over partial block records in the batch tables.
// ========================================================================
const std::unique_lock lock{ mutex_ };
{
const std::unique_lock lock{ mutex_ };

// Must retest inside the lock as table updates are running concurrently.
if (closed() || !is_mature(residual))
return;
// Must retest inside lock as table updates are running concurrently.
if (closed() || !is_mature(residual))
return;

if (const auto ec = do_process_batch(false))
fault(ec);
if (const auto ec = do_process_batch(false))
{
fault(ec);
return;
}
}
// ========================================================================

// Log outside of lock, oand nly when batch executes (non-verbose).
log_captures();
}

code chaser_validate::do_process_batch(bool startup) NOEXCEPT
{
if (!startup)
log_captures();

auto& query = archive();

const auto ecdsa = query.ecdsa_records();
Expand Down Expand Up @@ -252,6 +260,36 @@ bool chaser_validate::mark_valids(bool startup) NOEXCEPT
return !fault.load();
}

// Batch helpers.
// ----------------------------------------------------------------------------
// private

bool chaser_validate::is_residual() NOEXCEPT
{
// Verify residuals when recent.
return maximum_posted_.load() &&
is_zero(batch_backlog_.load()) &&
is_zero(validate_backlog_.load());
}

bool chaser_validate::is_mature(bool residual) NOEXCEPT
{
const auto& query = archive();
const auto ecdsa = query.ecdsa_records();
const auto schnorr = query.schnorr_records();

// Verify non-residuals when mature.
return residual || (ecdsa >= batch_target_) || (schnorr >= batch_target_);
}

std::string chaser_validate::log_rate(const std::string& name,
size_t numerator, size_t denominator) const NOEXCEPT
{
const auto rate = numerator / greater(denominator, one);
return (boost_format("%1% (%2% / %3%) = %4% sps") %
name % numerator % denominator % rate).str();
}

BC_POP_WARNING()

} // namespace node
Expand Down
16 changes: 4 additions & 12 deletions src/chasers/chaser_validate_capture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,6 @@ bool chaser_validate::do_threshold(const threshold& batch,
return set;
}

std::string chaser_validate::log_rate(const std::string& name,
size_t numerator, size_t denominator) const NOEXCEPT
{
const auto rate = numerator / greater(denominator, one);
return (boost_format("%1% (%2% / %3%) = %4% sps") %
name % numerator % denominator % rate).str();
}

// Capture helpers.
// ----------------------------------------------------------------------------
// private
Expand Down Expand Up @@ -160,10 +152,10 @@ std::string chaser_validate::log_ratio(const std::string& name,

void chaser_validate::log_captures() const NOEXCEPT
{
LOGV(log_ratio("Capture rate ecdsa.... ", ecdsa_, ecdsa_ + missed_ecdsa_));
LOGV(log_ratio("Capture rate multisig. ", multisig_, multisig_ + missed_multisig_));
LOGV(log_ratio("Capture rate schnorr.. ", schnorr_, schnorr_ + missed_schnorr_));
LOGV(log_ratio("Capture rate threshold ", threshold_, threshold_ + zero));
LOGN(log_ratio("Capture ecdsa.... ", ecdsa_, ecdsa_ + missed_ecdsa_));
LOGN(log_ratio("Capture multisig. ", multisig_, multisig_ + missed_multisig_));
LOGN(log_ratio("Capture schnorr.. ", schnorr_, schnorr_ + missed_schnorr_));
LOGN(log_ratio("Capture threshold ", threshold_, threshold_ + zero));
}

BC_POP_WARNING()
Expand Down
5 changes: 0 additions & 5 deletions src/chasers/chaser_validate_parallel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,6 @@ void chaser_validate::validate_block(const header_link& link,
if (!query.set_block_unconfirmable(link))
ec = error::validate5;
}
else if (batched && !faulted)
{
if (!query.set_block_prevalid(link))
ec = error::batch1;
}

--validate_backlog_;
complete_block(ec, link, ctx.height, bypass, batched, faulted, capturing);
Expand Down
Loading