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
19 changes: 11 additions & 8 deletions include/bitcoin/node/chasers/chaser_validate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,17 @@ class BCN_API chaser_validate
network::threadpool validation_threadpool_;

// These are thread safe.
std::atomic<size_t> batched_ecdsa_{};
std::atomic<size_t> unbatched_ecdsa_{};
std::atomic<size_t> batched_schnorr_{};
std::atomic<size_t> unbatched_schnorr_{};
std::atomic<size_t> batched_multisig_{};
std::atomic<size_t> unbatched_multisig_{};
std::atomic<size_t> batched_threshold_{};
std::atomic<size_t> unbatched_threshold_{};

std::atomic<size_t> ecdsa_{};
std::atomic<size_t> schnorr_{};
std::atomic<size_t> multisig_{};
std::atomic<size_t> threshold_{};

std::atomic<size_t> missed_ecdsa_{};
std::atomic<size_t> missed_schnorr_{};
std::atomic<size_t> missed_multisig_{};
std::atomic<size_t> missed_threshold_{};

std::atomic<size_t> backlog_{};
network::asio::strand validation_strand_;
const uint32_t subsidy_interval_;
Expand Down
40 changes: 31 additions & 9 deletions include/bitcoin/node/events.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,39 @@ enum events : uint8_t
block_reorganized, // block popped

/// Mining.
template_issued, // block template issued for mining
template_issued, // block template issued for mining

/// Timespans.
snapshot_secs, // snapshot timespan in seconds.
prune_msecs, // prune timespan in milliseconds.
reload_msecs, // store reload timespan in milliseconds.
block_usecs, // getblock timespan in microseconds.
ancestry_msecs, // getancestry timespan in milliseconds.
filter_msecs, // getfilter timespan in milliseconds.
filterhashes_msecs, // getfilterhashes timespan in milliseconds.
filterchecks_msecs // getcfcheckpt timespan in milliseconds.
snapshot_secs, // snapshot timespan in seconds.
prune_msecs, // prune timespan in milliseconds.
reload_msecs, // store reload timespan in milliseconds.
block_usecs, // getblock timespan in microseconds.
ancestry_msecs, // getancestry timespan in milliseconds.
filter_msecs, // getfilter timespan in milliseconds.
filterhashes_msecs, // getfilterhashes timespan in milliseconds.
filterchecks_msecs, // getcfcheckpt timespan in milliseconds.

/// Batching (missed).
missed_ecdsa, // Failed to capture ecdsa signature.
missed_multisig, // Failed to capture ecdsa signatures.
missed_schnorr, // Failed to capture schnorr sig (single|multiple).
missed_overflow, // Failed to capture schnorr sigs (multiple >= 2^16).

/// Batching (captured).
checksigverify, // ecdsa single (checksig/verify).
checkmultisigverify, // ecdsa multiple (checkmultisig/verify).
checksigadd, // schnorr single (op_checksigadd|op_checksig/verify).
checksig, // schnorr multiple (multisig).
numequal, // schnorr multiple (threshold).
numequalverify, // schnorr multiple (threshold).
numnotequal, // schnorr multiple (threshold).
lessthan, // schnorr multiple (threshold).
greaterthan, // schnorr multiple (threshold).
lessthanorequal, // schnorr multiple (threshold).
greaterthanorequal, // schnorr multiple (threshold).
within, // schnorr multiple (threshold).

unknown
};

} // namespace node
Expand Down
170 changes: 116 additions & 54 deletions src/chasers/chaser_validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ code chaser_validate::validate(bool bypass, const chain::block& block,
code ec{};

// Skips identity validation (performed in downloader).
// This can be performed in donwnloader as well but moving it here with
// This can be performed in downloader as well but moving it here with
// more order than required allows the downloader to avoid block parse
// which significantly reduces memory consumption and CPU during sync.
// This slightly increases check() computation under full validation
Expand All @@ -298,78 +298,140 @@ code chaser_validate::validate(bool bypass, const chain::block& block,

if (batch_signatures_)
{
const chain::signatures capture
using namespace chain;
std::atomic<size_t> set{};

const auto to_events = [](opcode op) NOEXCEPT
{
switch (op)
{
// ecdsa single (checksig/verify).
case opcode::checksigverify:
return events::checksigverify;

// ecdsa multiple (checkmultisig/verify).
case opcode::checkmultisigverify:
return events::checkmultisigverify;

// schnorr single (op_checksigadd|op_checksig/verify).
case opcode::checksigadd:
return events::checksigadd;

// schnorr multiple (multisig pattern).
case opcode::checksig:
return events::checksig;

// schnorr multiple (is_threshold).
case opcode::numequal:
return events::numequal;
case opcode::numequalverify:
return events::numequalverify;
case opcode::numnotequal:
return events::numnotequal;
case opcode::lessthan:
return events::lessthan;
case opcode::greaterthan:
return events::greaterthan;
case opcode::lessthanorequal:
return events::lessthanorequal;
case opcode::greaterthanorequal:
return events::greaterthanorequal;
case opcode::within:
return events::within;

// should be no path to this.
default:
return events::unknown;
}
};

const signatures capture
{
// Enable/disable capture.
.enabled = batch_signatures_,

.ecdsa = [&](const hash_digest& ,
const ec_compressed& , const ec_signature& ) NOEXCEPT
.log = [&](const script& missed) NOEXCEPT
{
////query.set_signature(digest, point, sign, link);
LOGA("Sigop @ " << ctx.height << " -> "
<< missed.to_string(chain::flags::all_rules));
},
.schnorr = [&](const hash_digest& ,
const ec_xonly& , const ec_signature& ) NOEXCEPT
.fire = [&](signatures::miss miss) NOEXCEPT
{
////query.set_signature(digest, point, sign, link);
switch (miss)
{
case signatures::miss::ecdsa:
++missed_ecdsa_;
fire(events::missed_ecdsa, ctx.height);
break;
case signatures::miss::multisig:
++missed_multisig_;
fire(events::missed_multisig, ctx.height);
break;
case signatures::miss::schnorr:
++missed_schnorr_;
fire(events::missed_schnorr, ctx.height);
break;
case signatures::miss::overflow:
++missed_threshold_;
fire(events::missed_overflow, ctx.height);
break;

// should be no path to this.
default:
BC_ASSERT_MSG(false, "unknown signatures::miss");
}
},
.multisig = [&](const hash_digest& ,
const ec_compresseds& , const ec_signatures& ,
uint16_t ) NOEXCEPT
.ecdsa = [&](const hash_digest& digest,
const ec_compressed& point,
const ec_signature& sign) NOEXCEPT
{
////query.set_signatures(digest, points, signs, group, link);
++ecdsa_;
fire(to_events(opcode::checksigverify), ctx.height);
return query.set_signature(digest, point, sign, link);
},
.threshold = [&](const chain::signatures::threshold_group& ,
uint16_t ) NOEXCEPT
.schnorr = [&](const hash_digest& digest, const ec_xonly& point,
const ec_signature& sign) NOEXCEPT
{
////query.set_signatures(digest, points, signs, group, link);
++schnorr_;
fire(to_events(opcode::checksigadd), ctx.height);
return query.set_signature(digest, point, sign, link);
},
.multisig = [&](const hash_digest& digest,
const ec_compresseds& points,
const ec_signatures& signs) NOEXCEPT
{
BC_ASSERT(points.size() == signs.size());
multisig_ += points.size();
fire(to_events(opcode::checkmultisigverify), ctx.height);
return query.set_signatures(digest, points, signs, set, link);
},
.threshold = [&](
const signatures::threshold_entries& group) NOEXCEPT
{
// Sets condition to opcode::checksig for all required.
threshold_ += group.entries.size();
fire(to_events(group.condition), ctx.height);
return query.set_signatures(group, set, link);
}
};

if ((ec = block.connect(ctx, capture)))
return ec;

if (is_limited<uint16_t>(capture.group.load()))
const auto log_capture = [&](std::string_view name, size_t captured,
size_t missed) NOEXCEPT
{
LOGF("Multisig capture bypassed because correlation overflow ("
<< capture.group << ").");
}

// Diagnostics (ecdsa).
batched_ecdsa_ += capture.batched_ecdsa;
unbatched_ecdsa_ += capture.unbatched_ecdsa;
batched_multisig_ += capture.batched_multisig;
unbatched_multisig_ += capture.unbatched_multisig;

if (to_bool(batched_ecdsa_.load()) || to_bool(unbatched_ecdsa_.load()))
{
LOGV("Efficiency ecdsa " << batched_ecdsa_ << " / ("
<< batched_ecdsa_ << " + " << unbatched_ecdsa_ << ")");
}

if (to_bool(batched_multisig_.load()) || to_bool(unbatched_multisig_.load()))
{
LOGV("Efficiency multisig " << batched_multisig_ << " / ("
<< batched_multisig_ << " + " << unbatched_multisig_ << ")");
}

// Diagnostics (schnorr).
batched_schnorr_ += capture.batched_schnorr;
unbatched_schnorr_ += capture.unbatched_schnorr;
batched_threshold_ += capture.batched_threshold;
unbatched_threshold_ += capture.unbatched_threshold;

if (to_bool(batched_schnorr_.load()) || to_bool(unbatched_schnorr_.load()))
{
LOGV("Efficiency schnorr " << batched_schnorr_ << " / ("
<< batched_schnorr_ << " + " << unbatched_schnorr_ << ")");
}
if (!to_bool(captured) && !to_bool(missed)) return;
const auto ratio = (100.0f * captured) / (captured + missed);
const auto rate = (boost_format("%.2f") % ratio).str();
LOGA("Efficiency " << name << rate << "% = " << captured
<< "/(" << captured << "+" << missed << ")");
};

if (to_bool(batched_threshold_.load()) || to_bool(unbatched_threshold_.load()))
{
LOGV("Efficiency threshold " << batched_threshold_ << " / ("
<< batched_threshold_ << " + " << unbatched_threshold_ << ")");
}
log_capture("ecdsa.... ", ecdsa_, missed_ecdsa_);
log_capture("multisig. ", multisig_, missed_multisig_);
log_capture("schnorr.. ", schnorr_, missed_schnorr_);
log_capture("threshold ", threshold_,missed_threshold_);
}
else
{
Expand Down
Loading