Skip to content

Commit 0f3a8e4

Browse files
committed
feat: add -parbls and validate async quorumSig and membersSig in QC
It introduces new commandline argument -parbls to set up amount of parallel threads for BLS validation New parallel BlsChecker validates asynchonously quorumSig and membersSig in Quorum Commitment
1 parent 76e4e72 commit 0f3a8e4

File tree

8 files changed

+124
-21
lines changed

8 files changed

+124
-21
lines changed

src/init.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,8 @@ void SetupServerArgs(ArgsManager& argsman)
529529
argsman.AddArg("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
530530
argsman.AddArg("-par=<n>", strprintf("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)",
531531
-GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
532+
argsman.AddArg("-parbls=<n>", strprintf("Set the number of bls verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)",
533+
-GetNumCores(), llmq::MAX_BLSCHECK_THREADS, llmq::DEFAULT_BLSCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
532534
argsman.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
533535
argsman.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
534536
argsman.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex, -rescan and -disablegovernance=false. "

src/llmq/blockprocessor.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <chain.h>
1414
#include <chainparams.h>
15+
#include <checkqueue.h>
1516
#include <consensus/params.h>
1617
#include <consensus/validation.h>
1718
#include <deploymentstatus.h>
@@ -52,8 +53,25 @@ CQuorumBlockProcessor::CQuorumBlockProcessor(CChainState& chainstate, CDetermini
5253
m_qsnapman(qsnapman)
5354
{
5455
utils::InitQuorumsCache(mapHasMinedCommitmentCache);
56+
57+
int bls_threads = gArgs.GetIntArg("-parbls", DEFAULT_BLSCHECK_THREADS);
58+
if (bls_threads <= 0) {
59+
// -parbls=0 means autodetect (number of cores - 1 validator threads)
60+
// -parbls=-n means "leave n cores free" (number of cores - n - 1 validator threads)
61+
bls_threads += GetNumCores();
62+
}
63+
// Subtract 1 because the main thread counts towards the par threads
64+
bls_threads = std::max(bls_threads - 1, 0);
65+
66+
// Number of script-checking threads <= MAX_BLSCHECK_THREADS
67+
bls_threads = std::min(bls_threads, MAX_BLSCHECK_THREADS);
68+
69+
LogPrintf("Bls verification uses %d additional threads\n", bls_threads);
70+
m_bls_queue.StartWorkerThreads(bls_threads);
5571
}
5672

73+
CQuorumBlockProcessor::~CQuorumBlockProcessor() { m_bls_queue.StopWorkerThreads(); }
74+
5775
MessageProcessingResult CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view msg_type,
5876
CDataStream& vRecv)
5977
{
@@ -197,18 +215,18 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, gsl::not_null<cons
197215
}
198216

199217
if (fBLSChecks) {
218+
CCheckQueueControl<utils::BlsCheck> queue_control(&m_bls_queue);
200219
for (const auto& [_, qc] : qcs) {
201220
if (qc.IsNull()) continue;
202221
const auto* pQuorumBaseBlockIndex = m_chainstate.m_blockman.LookupBlockIndex(qc.quorumHash);
203-
if (!qc.VerifySignature(m_dmnman, m_qsnapman, pQuorumBaseBlockIndex)) {
204-
LogPrintf("[ProcessBlock] failed h[%d] llmqType[%d] version[%d] quorumIndex[%d] quorumHash[%s]\n",
205-
pindex->nHeight, ToUnderlying(qc.llmqType), qc.nVersion, qc.quorumIndex,
206-
qc.quorumHash.ToString());
207-
return false;
208-
}
222+
qc.VerifySignatureAsync(m_dmnman, m_qsnapman, pQuorumBaseBlockIndex, &queue_control);
209223
}
210-
}
211224

225+
if (!queue_control.Wait()) {
226+
// at least one check failed
227+
return false;
228+
}
229+
}
212230
for (const auto& [_, qc] : qcs) {
213231
if (!ProcessCommitment(pindex->nHeight, blockHash, qc, state, fJustCheck, false)) {
214232
LogPrintf("[ProcessBlock] failed h[%d] llmqType[%d] version[%d] quorumIndex[%d] quorumHash[%s]\n", pindex->nHeight, ToUnderlying(qc.llmqType), qc.nVersion, qc.quorumIndex, qc.quorumHash.ToString());

src/llmq/blockprocessor.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
#include <unordered_lru_cache.h>
99

10+
#include <bls/bls.h>
11+
#include <checkqueue.h>
1012
#include <llmq/params.h>
13+
#include <llmq/utils.h>
1114
#include <protocol.h>
1215
#include <saltedhasher.h>
1316
#include <sync.h>
@@ -19,6 +22,7 @@
1922
class BlockValidationState;
2023
class CBlock;
2124
class CBlockIndex;
25+
class CBLSSignature;
2226
class CChain;
2327
class CChainState;
2428
class CDataStream;
@@ -41,6 +45,8 @@ class CQuorumBlockProcessor
4145
CEvoDB& m_evoDb;
4246
CQuorumSnapshotManager& m_qsnapman;
4347

48+
CCheckQueue<utils::BlsCheck> m_bls_queue{4};
49+
4450
mutable Mutex minableCommitmentsCs;
4551
std::map<std::pair<Consensus::LLMQType, uint256>, uint256> minableCommitmentsByQuorum GUARDED_BY(minableCommitmentsCs);
4652
std::map<uint256, CFinalCommitment> minableCommitments GUARDED_BY(minableCommitmentsCs);
@@ -50,6 +56,7 @@ class CQuorumBlockProcessor
5056
public:
5157
explicit CQuorumBlockProcessor(CChainState& chainstate, CDeterministicMNManager& dmnman, CEvoDB& evoDb,
5258
CQuorumSnapshotManager& qsnapman);
59+
~CQuorumBlockProcessor();
5360

5461
[[nodiscard]] MessageProcessingResult ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv);
5562

src/llmq/commitment.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
#include <evo/specialtx.h>
99

1010
#include <chainparams.h>
11+
#include <checkqueue.h>
1112
#include <consensus/validation.h>
1213
#include <deploymentstatus.h>
1314
#include <llmq/options.h>
1415
#include <llmq/utils.h>
1516
#include <logging.h>
16-
#include <validation.h>
1717
#include <util/underlying.h>
18+
#include <validation.h>
1819

1920
namespace llmq
2021
{
@@ -27,8 +28,9 @@ CFinalCommitment::CFinalCommitment(const Consensus::LLMQParams& params, const ui
2728
{
2829
}
2930

30-
bool CFinalCommitment::VerifySignature(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
31-
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex) const
31+
bool CFinalCommitment::VerifySignatureAsync(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
32+
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex,
33+
CCheckQueueControl<utils::BlsCheck>* queue_control) const
3234
{
3335
auto members = utils::GetAllQuorumMembers(llmqType, dmnman, qsnapman, pQuorumBaseBlockIndex);
3436
const auto& llmq_params_opt = Params().GetLLMQ(llmqType);
@@ -63,16 +65,31 @@ bool CFinalCommitment::VerifySignature(CDeterministicMNManager& dmnman, CQuorumS
6365
}
6466
memberPubKeys.emplace_back(members[i]->pdmnState->pubKeyOperator.Get());
6567
}
66-
67-
if (!membersSig.VerifySecureAggregated(memberPubKeys, commitmentHash)) {
68-
LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid aggregated members signature\n",
69-
quorumHash.ToString());
70-
return false;
68+
std::string members_id_string{
69+
strprintf("CFinalCommitment -- q[%s] invalid aggregated members signature", quorumHash.ToString())};
70+
if (queue_control) {
71+
std::vector<utils::BlsCheck> vChecks;
72+
vChecks.emplace_back(membersSig, memberPubKeys, commitmentHash, members_id_string);
73+
queue_control->Add(vChecks);
74+
} else {
75+
if (!membersSig.VerifySecureAggregated(memberPubKeys, commitmentHash)) {
76+
LogPrint(BCLog::LLMQ, "%s\n", members_id_string);
77+
return false;
78+
}
7179
}
7280
}
73-
if (!quorumSig.VerifyInsecure(quorumPublicKey, commitmentHash)) {
74-
LogPrint(BCLog::LLMQ, "CFinalCommitment -- q[%s] invalid quorum signature\n", quorumHash.ToString());
75-
return false;
81+
std::string qsig_id_string{strprintf("CFinalCommitment -- q[%s] invalid quorum signature", quorumHash.ToString())};
82+
if (queue_control) {
83+
std::vector<utils::BlsCheck> vChecks;
84+
std::vector<CBLSPublicKey> public_keys;
85+
public_keys.push_back(quorumPublicKey);
86+
vChecks.emplace_back(quorumSig, public_keys, commitmentHash, qsig_id_string);
87+
queue_control->Add(vChecks);
88+
} else {
89+
if (!quorumSig.VerifyInsecure(quorumPublicKey, commitmentHash)) {
90+
LogPrint(BCLog::LLMQ, "%s\n", qsig_id_string);
91+
return false;
92+
}
7693
}
7794
return true;
7895
}
@@ -157,7 +174,7 @@ bool CFinalCommitment::Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotMa
157174

158175
// sigs are only checked when the block is processed
159176
if (checkSigs) {
160-
if (!VerifySignature(dmnman, qsnapman, pQuorumBaseBlockIndex)) {
177+
if (!VerifySignatureAsync(dmnman, qsnapman, pQuorumBaseBlockIndex, nullptr)) {
161178
return false;
162179
}
163180
}

src/llmq/commitment.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ class CBlockIndex;
2525
class CDeterministicMNManager;
2626
class ChainstateManager;
2727
class TxValidationState;
28+
template <typename T>
29+
class CCheckQueueControl;
2830

2931
namespace llmq
3032
{
3133
class CQuorumSnapshotManager;
3234

35+
namespace utils {
36+
struct BlsCheck;
37+
} // namespace utils
3338
// This message is an aggregation of all received premature commitments and only valid if
3439
// enough (>=threshold) premature commitments were aggregated
3540
// This is mined on-chain as part of TRANSACTION_QUORUM_COMMITMENT
@@ -67,8 +72,9 @@ class CFinalCommitment
6772
return int(std::count(validMembers.begin(), validMembers.end(), true));
6873
}
6974

70-
bool VerifySignature(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
71-
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex) const;
75+
bool VerifySignatureAsync(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
76+
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex,
77+
CCheckQueueControl<utils::BlsCheck>* queue_control) const;
7278
bool Verify(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
7379
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, bool checkSigs) const;
7480
bool VerifyNull() const;

src/llmq/options.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ enum class QvvecSyncMode {
2424
OnlyIfTypeMember = 1,
2525
};
2626

27+
/** Maximum number of dedicated script-checking threads allowed */
28+
static const int MAX_BLSCHECK_THREADS = 31;
29+
/** -parbls default (number of bls-checking threads, 0 = auto) */
30+
static const int DEFAULT_BLSCHECK_THREADS = 0;
31+
2732
static constexpr bool DEFAULT_ENABLE_QUORUM_DATA_RECOVERY{true};
2833

2934
// If true, we will connect to all new quorums and watch their communication

src/llmq/utils.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,25 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman
940940
}
941941
}
942942

943+
bool BlsCheck::operator()()
944+
{
945+
if (m_pubkeys.size() > 1) {
946+
if (!m_sig.VerifySecureAggregated(m_pubkeys, m_msg_hash)) {
947+
LogPrint(BCLog::LLMQ, "%s\n", m_id_string);
948+
return false;
949+
}
950+
} else if (m_pubkeys.size() == 1) {
951+
if (!m_sig.VerifyInsecure(m_pubkeys.back(), m_msg_hash)) {
952+
LogPrint(BCLog::LLMQ, "%s\n", m_id_string);
953+
return false;
954+
}
955+
} else {
956+
// It is supposed to be at least one public key!
957+
return false;
958+
}
959+
return true;
960+
}
961+
943962
template <typename CacheType>
944963
void InitQuorumsCache(CacheType& cache, bool limit_by_connections)
945964
{

src/llmq/utils.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef BITCOIN_LLMQ_UTILS_H
66
#define BITCOIN_LLMQ_UTILS_H
77

8+
#include <bls/bls.h>
89
#include <gsl/pointers.h>
910
#include <llmq/params.h>
1011
#include <saltedhasher.h>
@@ -56,8 +57,36 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman
5657
const CSporkManager& sporkman, const CDeterministicMNList& tip_mn_list,
5758
gsl::not_null<const CBlockIndex*> pQuorumBaseBlockIndex, const uint256& myProTxHash);
5859

60+
struct BlsCheck {
61+
CBLSSignature m_sig;
62+
std::vector<CBLSPublicKey> m_pubkeys;
63+
uint256 m_msg_hash;
64+
std::string m_id_string;
65+
66+
BlsCheck() = default;
67+
68+
BlsCheck(CBLSSignature sig, std::vector<CBLSPublicKey> pubkeys, uint256 msg_hash, std::string id_string) :
69+
m_sig(sig),
70+
m_pubkeys(pubkeys),
71+
m_msg_hash(msg_hash),
72+
m_id_string(id_string)
73+
{
74+
}
75+
76+
void swap(BlsCheck& obj)
77+
{
78+
std::swap(m_sig, obj.m_sig);
79+
std::swap(m_pubkeys, obj.m_pubkeys);
80+
std::swap(m_msg_hash, obj.m_msg_hash);
81+
std::swap(m_id_string, obj.m_id_string);
82+
}
83+
84+
bool operator()();
85+
};
86+
5987
template <typename CacheType>
6088
void InitQuorumsCache(CacheType& cache, bool limit_by_connections = true);
89+
6190
} // namespace utils
6291
} // namespace llmq
6392

0 commit comments

Comments
 (0)