diff --git a/src/bls/bls.cpp b/src/bls/bls.cpp index 96a188e2ae93..1a8bab710d83 100644 --- a/src/bls/bls.cpp +++ b/src/bls/bls.cpp @@ -15,9 +15,40 @@ #include namespace bls { - std::atomic bls_legacy_scheme = std::atomic(true); +std::atomic bls_legacy_scheme = std::atomic(true); + +namespace { +//! Trivially destructible, like util/threadnames.cpp's thread-local name. +thread_local std::optional g_thread_legacy_scheme; +} // namespace + +bool EffectiveLegacyScheme() { return g_thread_legacy_scheme ? *g_thread_legacy_scheme : bls_legacy_scheme.load(); } + +void SetEffectiveLegacyScheme(bool legacy) +{ + if (g_thread_legacy_scheme) { + g_thread_legacy_scheme = legacy; + } else { + bls_legacy_scheme.store(legacy); + } } +ScopedLegacySchemeOverride::ScopedLegacySchemeOverride(bool legacy) noexcept : + m_saved{g_thread_legacy_scheme} +{ + g_thread_legacy_scheme = legacy; +} + +ScopedLegacySchemeOverride::~ScopedLegacySchemeOverride() noexcept +{ + if (!m_committed || !m_saved) { + g_thread_legacy_scheme = m_saved; + } +} + +bool ScopedLegacySchemeOverride::Active() noexcept { return g_thread_legacy_scheme.has_value(); } +} // namespace bls + static const std::unique_ptr pSchemeLegacy{std::make_unique()}; static const std::unique_ptr pScheme(std::make_unique()); @@ -145,7 +176,7 @@ void CBLSPublicKey::AggregateInsecure(const CBLSPublicKey& o) { assert(IsValid() && o.IsValid()); try { - impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate({impl, o.impl}); + impl = Scheme(bls::EffectiveLegacyScheme())->Aggregate({impl, o.impl}); } catch (...) { fValid = false; } @@ -166,7 +197,7 @@ CBLSPublicKey CBLSPublicKey::AggregateInsecure(Span pks) CBLSPublicKey ret; try { - ret.impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate(vecPublicKeys); + ret.impl = Scheme(bls::EffectiveLegacyScheme())->Aggregate(vecPublicKeys); ret.fValid = true; } catch (...) { ret.fValid = false; @@ -230,7 +261,7 @@ void CBLSSignature::AggregateInsecure(const CBLSSignature& o) { assert(IsValid() && o.IsValid()); try { - impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate({impl, o.impl}); + impl = Scheme(bls::EffectiveLegacyScheme())->Aggregate({impl, o.impl}); } catch (...) { fValid = false; } @@ -251,7 +282,7 @@ CBLSSignature CBLSSignature::AggregateInsecure(Span sigs) CBLSSignature ret; try { - ret.impl = Scheme(bls::bls_legacy_scheme.load())->Aggregate(v); + ret.impl = Scheme(bls::EffectiveLegacyScheme())->Aggregate(v); ret.fValid = true; } catch (...) { ret.fValid = false; @@ -283,7 +314,7 @@ CBLSSignature CBLSSignature::AggregateSecure(Span sigs, CBLSSignature ret; try { - ret.impl = Scheme(bls::bls_legacy_scheme.load())->AggregateSecure(vecPublicKeys, vecSignatures, bls::Bytes(hash.begin(), hash.size())); + ret.impl = Scheme(bls::EffectiveLegacyScheme())->AggregateSecure(vecPublicKeys, vecSignatures, bls::Bytes(hash.begin(), hash.size())); ret.fValid = true; } catch (...) { ret.fValid = false; @@ -322,10 +353,16 @@ bool CBLSSignature::VerifyInsecure(const CBLSPublicKey& pubKey, const uint256& h bool CBLSSignature::VerifyInsecure(const CBLSPublicKey& pubKey, const uint256& hash) const { - return VerifyInsecure(pubKey, hash, bls::bls_legacy_scheme.load()); + return VerifyInsecure(pubKey, hash, bls::EffectiveLegacyScheme()); } bool CBLSSignature::VerifyInsecureAggregated(Span pubKeys, Span hashes) const +{ + return VerifyInsecureAggregated(pubKeys, hashes, bls::EffectiveLegacyScheme()); +} + +bool CBLSSignature::VerifyInsecureAggregated(Span pubKeys, Span hashes, + const bool specificLegacyScheme) const { if (!IsValid()) { return false; @@ -346,13 +383,18 @@ bool CBLSSignature::VerifyInsecureAggregated(Span pubKeys, SpanAggregateVerify(pubKeyVec, hashes2, impl); + return Scheme(specificLegacyScheme)->AggregateVerify(pubKeyVec, hashes2, impl); } catch (...) { return false; } } bool CBLSSignature::VerifySecureAggregated(Span pks, const uint256& hash) const +{ + return VerifySecureAggregated(pks, hash, bls::EffectiveLegacyScheme()); +} + +bool CBLSSignature::VerifySecureAggregated(Span pks, const uint256& hash, const bool specificLegacyScheme) const { if (pks.empty()) { return false; @@ -365,7 +407,7 @@ bool CBLSSignature::VerifySecureAggregated(Span pks, const uint25 } try { - return Scheme(bls::bls_legacy_scheme.load())->VerifySecure(vecPublicKeys, impl, bls::Bytes(hash.begin(), hash.size())); + return Scheme(specificLegacyScheme)->VerifySecure(vecPublicKeys, impl, bls::Bytes(hash.begin(), hash.size())); } catch (...) { return false; } diff --git a/src/bls/bls.h b/src/bls/bls.h index 82abc2c6de04..023b927312cb 100644 --- a/src/bls/bls.h +++ b/src/bls/bls.h @@ -24,11 +24,47 @@ #include #include #include +#include #include namespace bls { - extern std::atomic bls_legacy_scheme; -} +//! Process-wide default scheme of BLS operations that are not given one. It +//! follows the active chainstate's tip only: other threads read it outside +//! cs_main, so work for any other chain context (a background chainstate, a dry +//! run) sets a ScopedLegacySchemeOverride instead. +extern std::atomic bls_legacy_scheme; + +//! The scheme of BLS operations on this thread that are not given one: the +//! innermost ScopedLegacySchemeOverride if one is set, else bls_legacy_scheme. +bool EffectiveLegacyScheme(); + +//! Switches EffectiveLegacyScheme(): this thread's override if one is set, +//! else bls_legacy_scheme. +void SetEffectiveLegacyScheme(bool legacy); + +//! Sets EffectiveLegacyScheme() on this thread only, for the object's lifetime. +//! Work handed to another thread does not see it and must capture the scheme. +class ScopedLegacySchemeOverride +{ +public: + explicit ScopedLegacySchemeOverride(bool legacy) noexcept; + ~ScopedLegacySchemeOverride() noexcept; + + ScopedLegacySchemeOverride(const ScopedLegacySchemeOverride&) = delete; + ScopedLegacySchemeOverride& operator=(const ScopedLegacySchemeOverride&) = delete; + + //! Leaves the scheme in force at scope exit to the enclosing override. The + //! outermost override always ends with its scope. + void Commit() noexcept { m_committed = true; } + + //! Whether an override is set on this thread. + static bool Active() noexcept; + +private: + const std::optional m_saved; + bool m_committed{false}; +}; +} // namespace bls // reversed BLS12-381 constexpr int BLS_CURVE_ID_SIZE{32}; @@ -177,7 +213,7 @@ class CBLSWrapper template inline void Serialize(Stream& s) const { - Serialize(s, bls::bls_legacy_scheme.load()); + Serialize(s, bls::EffectiveLegacyScheme()); } template @@ -205,7 +241,7 @@ class CBLSWrapper template inline void Unserialize(Stream& s) { - Unserialize(s, bls::bls_legacy_scheme.load()); + Unserialize(s, bls::EffectiveLegacyScheme()); } inline bool CheckMalleable(Span vecBytes, const bool specificLegacyScheme) const @@ -228,7 +264,7 @@ class CBLSWrapper inline std::string ToString() const { - return ToString(bls::bls_legacy_scheme.load()); + return ToString(bls::EffectiveLegacyScheme()); } }; @@ -365,8 +401,12 @@ class CBLSSignature : public CBLSWrapper pubKeys, Span hashes, + const bool specificLegacyScheme) const; [[nodiscard]] bool VerifyInsecureAggregated(Span pubKeys, Span hashes) const; + [[nodiscard]] bool VerifySecureAggregated(Span pks, const uint256& hash, + const bool specificLegacyScheme) const; [[nodiscard]] bool VerifySecureAggregated(Span pks, const uint256& hash) const; bool Recover(Span sigs, Span ids); @@ -410,7 +450,7 @@ class CBLSLazyWrapper public: CBLSLazyWrapper() : - bufLegacyScheme(bls::bls_legacy_scheme.load()) + bufLegacyScheme(bls::EffectiveLegacyScheme()) {} explicit CBLSLazyWrapper(const CBLSLazyWrapper& r) diff --git a/src/bls/bls_batchverifier.h b/src/bls/bls_batchverifier.h index 647d38e675e3..843fe85cfcbf 100644 --- a/src/bls/bls_batchverifier.h +++ b/src/bls/bls_batchverifier.h @@ -47,6 +47,8 @@ class CBLSBatchVerifier bool secureVerification; bool perMessageFallback; size_t subBatchSize; + //! Taken from the constructing thread, so a batch verifies under one scheme wherever Verify() runs + const bool legacyScheme; MessageMap messages; MessagesBySourceMap messagesBySource; @@ -61,7 +63,8 @@ class CBLSBatchVerifier CBLSBatchVerifier(bool _secureVerification, bool _perMessageFallback, size_t _subBatchSize = 0) : secureVerification(_secureVerification), perMessageFallback(_perMessageFallback), - subBatchSize(_subBatchSize) + subBatchSize(_subBatchSize), + legacyScheme(bls::EffectiveLegacyScheme()) { } @@ -135,7 +138,7 @@ class CBLSBatchVerifier } const auto& msg = msgIt->second; - if (!msg.sig.VerifyInsecure(msg.pubKey, msg.msgHash)) { + if (!msg.sig.VerifyInsecure(msg.pubKey, msg.msgHash, legacyScheme)) { badMessages.emplace(msg.msgId); } } @@ -201,7 +204,7 @@ class CBLSBatchVerifier } CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigsToAggregate); - return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes); + return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes, legacyScheme); } bool VerifyBatchSecure(std::map>& byMessageHash) @@ -251,7 +254,7 @@ class CBLSBatchVerifier assert(!msgHashes.empty()); CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigsToAggregate); - return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes); + return aggSig.VerifyInsecureAggregated(pubKeys, msgHashes, legacyScheme); } }; diff --git a/src/bls/bls_worker.cpp b/src/bls/bls_worker.cpp index 7e383a644ba3..a387670d7141 100644 --- a/src/bls/bls_worker.cpp +++ b/src/bls/bls_worker.cpp @@ -825,8 +825,8 @@ std::set CBLSWorker::FindVerificationVectorsWithSharedCoefficients(Span< void CBLSWorker::AsyncSign(const CBLSSecretKey& secKey, const uint256& msgHash, const CBLSWorker::SignDoneCallback& doneCallback) { - workerPool.push([secKey, msgHash, doneCallback](int threadId) { - doneCallback(secKey.Sign(msgHash, bls::bls_legacy_scheme.load())); + workerPool.push([secKey, msgHash, doneCallback, legacy = bls::EffectiveLegacyScheme()](int threadId) { + doneCallback(secKey.Sign(msgHash, legacy)); }); } @@ -838,18 +838,19 @@ void CBLSWorker::AsyncVerifySig(const CBLSSignature& sig, const CBLSPublicKey& p return; } + const bool legacy{bls::EffectiveLegacyScheme()}; std::unique_lock l(sigVerifyMutex); bool foundDuplicate = std::ranges::any_of(sigVerifyQueue, [&msgHash](const auto& job) { return job.msgHash == msgHash; }); - if (foundDuplicate) { - // batched/aggregated verification does not allow duplicate hashes, so we push what we currently have and start - // with a fresh batch + if (foundDuplicate || (!sigVerifyQueue.empty() && sigVerifyQueue.front().legacyScheme != legacy)) { + // batched/aggregated verification does not allow duplicate hashes or mixed schemes, so we push what we + // currently have and start with a fresh batch PushSigVerifyBatch(); } - sigVerifyQueue.emplace_back(std::move(doneCallback), std::move(cancelCond), sig, pubKey, msgHash); + sigVerifyQueue.emplace_back(std::move(doneCallback), std::move(cancelCond), sig, pubKey, msgHash, legacy); if (sigVerifyBatchesInProgress == 0 || sigVerifyQueue.size() >= SIG_VERIFY_BATCH_SIZE) { PushSigVerifyBatch(); } @@ -876,7 +877,7 @@ void CBLSWorker::PushSigVerifyBatch() if (jobs.size() == 1) { const auto& job = jobs[0]; if (!job.cancelCond()) { - bool valid = job.sig.VerifyInsecure(job.pubKey, job.msgHash); + bool valid = job.sig.VerifyInsecure(job.pubKey, job.msgHash, job.legacyScheme); job.doneCallback(valid); } std::unique_lock l(sigVerifyMutex); @@ -910,7 +911,7 @@ void CBLSWorker::PushSigVerifyBatch() } if (!pubKeys.empty()) { - bool allValid = aggSig.VerifyInsecureAggregated(pubKeys, msgHashes); + bool allValid = aggSig.VerifyInsecureAggregated(pubKeys, msgHashes, jobs.front().legacyScheme); if (allValid) { for (size_t i = 0; i < pubKeys.size(); i++) { jobs[indexes[i]].doneCallback(true); @@ -920,7 +921,7 @@ void CBLSWorker::PushSigVerifyBatch() // TODO this could be improved if we would cache pairing results in some way as the previous aggregated verification already calculated all the pairings for the hashes for (size_t i = 0; i < pubKeys.size(); i++) { const auto& job = jobs[indexes[i]]; - bool valid = job.sig.VerifyInsecure(job.pubKey, job.msgHash); + bool valid = job.sig.VerifyInsecure(job.pubKey, job.msgHash, job.legacyScheme); job.doneCallback(valid); } } diff --git a/src/bls/bls_worker.h b/src/bls/bls_worker.h index 74c7ffe67d9b..fe3fc71410b6 100644 --- a/src/bls/bls_worker.h +++ b/src/bls/bls_worker.h @@ -35,12 +35,16 @@ class CBLSWorker CBLSSignature sig; CBLSPublicKey pubKey; uint256 msgHash; - SigVerifyJob(SigVerifyDoneCallback&& _doneCallback, CancelCond&& _cancelCond, const CBLSSignature& _sig, CBLSPublicKey _pubKey, const uint256& _msgHash) : + //! The submitting thread's scheme; the job runs on a worker thread + bool legacyScheme; + SigVerifyJob(SigVerifyDoneCallback&& _doneCallback, CancelCond&& _cancelCond, const CBLSSignature& _sig, + CBLSPublicKey _pubKey, const uint256& _msgHash, bool _legacyScheme) : doneCallback(_doneCallback), cancelCond(_cancelCond), sig(_sig), pubKey(std::move(_pubKey)), - msgHash(_msgHash) + msgHash(_msgHash), + legacyScheme(_legacyScheme) { } }; diff --git a/src/chainlock/clsig.cpp b/src/chainlock/clsig.cpp index 9313824eb007..8b1dc44491a7 100644 --- a/src/chainlock/clsig.cpp +++ b/src/chainlock/clsig.cpp @@ -86,9 +86,9 @@ class DecodedSignatureCache CBLSSignature Decode(const std::array& bytes) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { // Decode exactly as the coinbase payload was always decoded: under the - // process-wide scheme flag, including its opposite-scheme rejection. The - // flag is part of the key so a transient value cannot leak into later calls. - const bool legacy = bls::bls_legacy_scheme.load(); + // effective scheme, including its opposite-scheme rejection. The scheme is + // part of the key so another context's value cannot leak into later calls. + const bool legacy = bls::EffectiveLegacyScheme(); const uint256 key = (CHashWriter(SER_GETHASH, 0) << Span{bytes} << legacy).GetHash(); CBLSSignature sig; { diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index 1a2555cd3628..a113e487604f 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -387,10 +387,10 @@ bool CMNHFManager::ForceSignalDBUpdate(const CBlockIndex* tip) // force ehf signals db update auto dbTx = m_evoDb.BeginTransaction(); - const bool last_legacy = bls::bls_legacy_scheme.load(); - bls::bls_legacy_scheme.store(false); - GetSignalsStage(tip); - bls::bls_legacy_scheme.store(last_legacy); + { + const bls::ScopedLegacySchemeOverride basic_scheme{/*legacy=*/false}; + GetSignalsStage(tip); + } dbTx->Commit(); // flush it to disk diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index eb2f68cb730a..fb2bd6b890cf 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -1092,11 +1092,11 @@ bool CSpecialTxProcessor::ProcessSpecialTxsInBlock(Chainstate& chainstate, const LogPrint(BCLog::BENCHMARK, " - m_mnhfman->ProcessBlock: %.2fms [%.2fs]\n", Ticks(nTime8 - nTime7), Ticks(nTimeMnehf)); - if (DeploymentActiveAfter(pindex, m_consensus_params, Consensus::DEPLOYMENT_V19) && bls::bls_legacy_scheme.load()) { + if (DeploymentActiveAfter(pindex, m_consensus_params, Consensus::DEPLOYMENT_V19) && bls::EffectiveLegacyScheme()) { // NOTE: The block next to the activation is the one that is using new rules. // V19 activated just activated, so we must switch to the new rules here. - bls::bls_legacy_scheme.store(false); - LogPrintf("CSpecialTxProcessor::%s -- bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load()); + bls::SetEffectiveLegacyScheme(false); + LogPrintf("CSpecialTxProcessor::%s -- bls_legacy_scheme=%d\n", __func__, bls::EffectiveLegacyScheme()); } } catch (const EvoDbInconsistencyError& e) { // Local EvoDB corruption detected below (the node is already @@ -1114,14 +1114,14 @@ bool CSpecialTxProcessor::UndoSpecialTxsInBlock(const Chainstate& chainstate, co { AssertLockHeld(::cs_main); - auto bls_legacy_scheme = bls::bls_legacy_scheme.load(); + const bool bls_legacy_scheme{bls::EffectiveLegacyScheme()}; try { if (!DeploymentActiveAt(*pindex, m_consensus_params, Consensus::DEPLOYMENT_V19) && !bls_legacy_scheme) { // NOTE: The block next to the activation is the one that is using new rules. // Removing the activation block here, so we must switch back to the old rules. - bls::bls_legacy_scheme.store(true); - LogPrintf("CSpecialTxProcessor::%s -- bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load()); + bls::SetEffectiveLegacyScheme(true); + LogPrintf("CSpecialTxProcessor::%s -- bls_legacy_scheme=%d\n", __func__, bls::EffectiveLegacyScheme()); } if (!m_mnhfman->UndoBlock(block, pindex)) { @@ -1136,8 +1136,8 @@ bool CSpecialTxProcessor::UndoSpecialTxsInBlock(const Chainstate& chainstate, co return false; } } catch (const std::exception& e) { - bls::bls_legacy_scheme.store(bls_legacy_scheme); - LogPrintf("CSpecialTxProcessor::%s -- bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load()); + bls::SetEffectiveLegacyScheme(bls_legacy_scheme); + LogPrintf("CSpecialTxProcessor::%s -- bls_legacy_scheme=%d\n", __func__, bls::EffectiveLegacyScheme()); LogError("CSpecialTxProcessor::%s -- FAILURE! %s\n", __func__, e.what()); return false; } diff --git a/src/llmq/dkgmessages.h b/src/llmq/dkgmessages.h index 7080779abf2f..6ddba6a752a2 100644 --- a/src/llmq/dkgmessages.h +++ b/src/llmq/dkgmessages.h @@ -55,7 +55,7 @@ class CDKGContribution s >> quorumHash; s >> proTxHash; // Decode the whole vvec under one scheme, so that vvecLegacyScheme describes every point in it - vvecLegacyScheme = bls::bls_legacy_scheme.load(); + vvecLegacyScheme = bls::EffectiveLegacyScheme(); for (uint64_t i = 0, size = ReadCompactSize(s); i < size; i++) { s >> CBLSPublicKeyVersionWrapper(tmp1.emplace_back(), vvecLegacyScheme); } diff --git a/src/llmq/signing.h b/src/llmq/signing.h index b2ee2d22ba00..b11cba7379c8 100644 --- a/src/llmq/signing.h +++ b/src/llmq/signing.h @@ -82,7 +82,7 @@ class CRecoveredSig : virtual public CSigBase CRecoveredSig(Consensus::LLMQType _llmqType, const uint256& _quorumHash, const uint256& _id, const uint256& _msgHash, const CBLSLazySignature& _sig) : CSigBase(_llmqType, _quorumHash, _id, _msgHash), sig(_sig) {UpdateHash();}; CRecoveredSig(Consensus::LLMQType _llmqType, const uint256& _quorumHash, const uint256& _id, const uint256& _msgHash, const CBLSSignature& _sig) : - CSigBase(_llmqType, _quorumHash, _id, _msgHash) {const_cast(sig).Set(_sig, bls::bls_legacy_scheme.load()); UpdateHash();}; + CSigBase(_llmqType, _quorumHash, _id, _msgHash) {const_cast(sig).Set(_sig, bls::EffectiveLegacyScheme()); UpdateHash();}; private: // only in-memory diff --git a/src/llmq/signing_shares.cpp b/src/llmq/signing_shares.cpp index 5dd6ce91a3bc..566bccf8a361 100644 --- a/src/llmq/signing_shares.cpp +++ b/src/llmq/signing_shares.cpp @@ -1569,7 +1569,7 @@ std::optional CSigSharesManager::CreateSigShareForSingleMember(const // TODO: This one should be SIGN by QUORUM key, not by OPERATOR key // see TODO in CDKGSession::FinalizeSingleCommitment for details - auto bls_scheme = bls::bls_legacy_scheme.load(); + auto bls_scheme = bls::EffectiveLegacyScheme(); sigShare.sigShare.Set(m_mn_activeman.Sign(signHash, bls_scheme), bls_scheme); if (!sigShare.sigShare.Get().IsValid()) { @@ -1624,7 +1624,7 @@ std::optional CSigSharesManager::CreateSigShare(const CQuorum& quorum CSigShare sigShare(quorum.params.type, quorum.qc->quorumHash, id, msgHash, static_cast(memberIdx), {}); uint256 signHash = sigShare.buildSignHash().Get(); - auto bls_scheme = bls::bls_legacy_scheme.load(); + auto bls_scheme = bls::EffectiveLegacyScheme(); sigShare.sigShare.Set(skShare.Sign(signHash, bls_scheme), bls_scheme); if (!sigShare.sigShare.Get().IsValid()) { LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", __func__, diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 0d34b0c43dcf..20a8c0ec3bd8 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -563,12 +563,12 @@ BlsCheck::~BlsCheck() = default; bool BlsCheck::operator()() { if (m_pubkeys.size() > 1) { - if (!m_sig.VerifySecureAggregated(m_pubkeys, m_msg_hash)) { + if (!m_sig.VerifySecureAggregated(m_pubkeys, m_msg_hash, m_legacy_scheme)) { LogPrint(BCLog::LLMQ, "%s\n", m_id_string); return false; } } else if (m_pubkeys.size() == 1) { - if (!m_sig.VerifyInsecure(m_pubkeys.back(), m_msg_hash)) { + if (!m_sig.VerifyInsecure(m_pubkeys.back(), m_msg_hash, m_legacy_scheme)) { LogPrint(BCLog::LLMQ, "%s\n", m_id_string); return false; } @@ -586,6 +586,7 @@ void BlsCheck::swap(BlsCheck& obj) noexcept std::swap(m_pubkeys, obj.m_pubkeys); std::swap(m_msg_hash, obj.m_msg_hash); std::swap(m_id_string, obj.m_id_string); + std::swap(m_legacy_scheme, obj.m_legacy_scheme); } std::optional> ComputeQuorumMembersFromWorkBlock( diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 65c4c2682808..fe45ecf195d1 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -48,6 +48,8 @@ struct BlsCheck { std::vector m_pubkeys; uint256 m_msg_hash; std::string m_id_string; + //! The building thread's scheme; CCheckQueue runs the check on another thread + bool m_legacy_scheme{bls::EffectiveLegacyScheme()}; public: BlsCheck(); diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index ea001791d571..13ecf5e54839 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -437,13 +437,6 @@ ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const C break; } // no default case, so the compiler can warn about missing cases - // VerifyDB() disconnects blocks which might result in us switching back to legacy. - // Make sure we use the right scheme. - if (v19active && bls::bls_legacy_scheme.load()) { - bls::bls_legacy_scheme.store(false); - if (notify_bls_state) notify_bls_state(bls::bls_legacy_scheme.load()); - } - if (options.check_level >= 3) { chainstate->ResetBlockFailureFlags(nullptr); } diff --git a/src/node/miner.cpp b/src/node/miner.cpp index ca84a4b531da..aa3373b449a3 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -356,7 +356,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc if (fV20Active_context) { CBLSSignature best_cl_sig; const bool has_best_cl{CalcCbTxBestChainlock(m_chainlocks, m_chainstate.m_blockman, pindexPrev, cbTx.bestCLHeightDiff, best_cl_sig)}; - cbTx.bestCLSignature.Set(best_cl_sig, bls::bls_legacy_scheme.load()); + cbTx.bestCLSignature.Set(best_cl_sig, bls::EffectiveLegacyScheme()); if (has_best_cl) { LogPrintf("CreateNewBlock() h[%d] CbTx bestCLHeightDiff[%d] CLSig[%s]\n", nHeight, cbTx.bestCLHeightDiff, cbTx.bestCLSignature.ToString()); } else { diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index 3d211138d3ea..90691979bfc6 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -702,7 +702,7 @@ static RPCHelpMan quorum_verify() const uint256 id(ParseHashV(request.params[1], "id")); const uint256 msgHash(ParseHashV(request.params[2], "msgHash")); - const bool use_bls_legacy = bls::bls_legacy_scheme.load(); + const bool use_bls_legacy = bls::EffectiveLegacyScheme(); CBLSSignature sig; if (!sig.SetHexStr(request.params[3].get_str(), use_bls_legacy)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid signature format"); diff --git a/src/test/bls_tests.cpp b/src/test/bls_tests.cpp index 83715e84f296..9becd1b6f4df 100644 --- a/src/test/bls_tests.cpp +++ b/src/test/bls_tests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include