diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index be7bfe2d2dcc..05638574634d 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -31,6 +31,7 @@ bench_bench_dash_SOURCES = \ bench/crypto_hash.cpp \ bench/data.cpp \ bench/data.h \ + bench/dkg_deserialize.cpp \ bench/duplicate_inputs.cpp \ bench/ecdsa.cpp \ bench/ellswift.cpp \ diff --git a/src/bench/dkg_deserialize.cpp b/src/bench/dkg_deserialize.cpp new file mode 100644 index 000000000000..a013e881a4ef --- /dev/null +++ b/src/bench/dkg_deserialize.cpp @@ -0,0 +1,179 @@ +// Copyright (c) 2026 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + +// Build a well-formed serialized QCONTRIB payload for the given quorum size / +// threshold. The ciphertext blobs are opaque bytes on the wire (only the +// enclosing IES header is a BLS pubkey), so we can synthesise them without +// running IES encryption. Vvec entries and the outer signature are real BLS +// points so the deserializer performs the same G1/G2 decompression as it would +// in production. +CDataStream BuildSerializedContribution(int quorumSize, int threshold) +{ + llmq::CDKGContribution qc; + qc.llmqType = Consensus::LLMQType::LLMQ_50_60; + qc.quorumHash = GetRandHash(); + qc.proTxHash = GetRandHash(); + + auto vvec = std::make_shared>(); + vvec->reserve(threshold); + for (int i = 0; i < threshold; ++i) { + CBLSSecretKey sk; + sk.MakeNewKey(); + vvec->emplace_back(sk.GetPublicKey()); + } + qc.vvec = std::move(vvec); + + auto contributions = std::make_shared>(); + { + CBLSSecretKey sk; + sk.MakeNewKey(); + contributions->ephemeralPubKey = sk.GetPublicKey(); + } + contributions->ivSeed = GetRandHash(); + contributions->blobs.resize(quorumSize); + // Each IES blob wraps a CBLSSecretKey (32 bytes) plus AEAD framing overhead + // (~16 bytes tag). Sixty-four bytes matches what the real DKG produces on + // the wire closely enough for deserialization cost. Blob contents are + // opaque bytes on the wire (no BLS decoding); a deterministic fill keeps + // the benchmark reproducible. + FastRandomContext rng{true}; + for (auto& blob : contributions->blobs) { + blob = rng.randbytes(64); + } + qc.contributions = std::move(contributions); + + { + CBLSSecretKey sk; + sk.MakeNewKey(); + qc.sig = sk.Sign(GetRandHash(), false); + } + + CDataStream ds(SER_NETWORK, PROTOCOL_VERSION); + ds << qc; + return ds; +} + +CDataStream BuildSerializedPrematureCommitment(int quorumSize) +{ + llmq::CDKGPrematureCommitment qc; + qc.llmqType = Consensus::LLMQType::LLMQ_50_60; + qc.quorumHash = GetRandHash(); + qc.proTxHash = GetRandHash(); + qc.validMembers.assign(quorumSize, true); + { + CBLSSecretKey sk; + sk.MakeNewKey(); + qc.quorumPublicKey = sk.GetPublicKey(); + } + qc.quorumVvecHash = GetRandHash(); + { + CBLSSecretKey sk1, sk2; + sk1.MakeNewKey(); + sk2.MakeNewKey(); + qc.quorumSig = sk1.Sign(GetRandHash(), false); + qc.sig = sk2.Sign(GetRandHash(), false); + } + CDataStream ds(SER_NETWORK, PROTOCOL_VERSION); + ds << qc; + return ds; +} + +} // namespace + +// Simulates the current intake path: deserialize a copy on the network thread +// for structural pre-validation, then deserialize again on the DKG worker to +// obtain the typed object. +static void DKG_QCONTRIB_DoubleDeserialize(benchmark::Bench& bench) +{ + const CDataStream wire = BuildSerializedContribution(50, 30); + + bench.minEpochIterations(200).run([&] { + // Structural check on a copy (mirrors CheckDKGMessageStructure). + { + CDataStream s(wire); + llmq::CDKGContribution qc; + s >> qc; + ankerl::nanobench::doNotOptimizeAway(qc.vvec->size()); + } + // Worker deserialize (mirrors PopAndDeserializeMessages, which built + // the typed object via std::make_shared()). + { + CDataStream s(wire); + auto qc = std::make_shared(); + s >> *qc; + ankerl::nanobench::doNotOptimizeAway(qc->contributions->blobs.size()); + } + }); +} + +// Simulates the proposed intake path: deserialize once at intake, retain the +// typed object, no worker-side deserialize. +static void DKG_QCONTRIB_SingleDeserialize(benchmark::Bench& bench) +{ + const CDataStream wire = BuildSerializedContribution(50, 30); + + bench.minEpochIterations(200).run([&] { + CDataStream s(wire); + auto qc = std::make_shared(); + s >> *qc; + ankerl::nanobench::doNotOptimizeAway(qc->vvec->size()); + ankerl::nanobench::doNotOptimizeAway(qc->contributions->blobs.size()); + }); +} + +static void DKG_QPCOMMITMENT_DoubleDeserialize(benchmark::Bench& bench) +{ + const CDataStream wire = BuildSerializedPrematureCommitment(50); + + bench.minEpochIterations(2000).run([&] { + // Structural check on a copy (mirrors CheckDKGMessageStructure). + { + CDataStream s(wire); + llmq::CDKGPrematureCommitment qc; + s >> qc; + ankerl::nanobench::doNotOptimizeAway(qc.validMembers.size()); + } + // Worker deserialize (mirrors PopAndDeserializeMessages, which built + // the typed object via std::make_shared()). + { + CDataStream s(wire); + auto qc = std::make_shared(); + s >> *qc; + ankerl::nanobench::doNotOptimizeAway(qc->validMembers.size()); + } + }); +} + +static void DKG_QPCOMMITMENT_SingleDeserialize(benchmark::Bench& bench) +{ + const CDataStream wire = BuildSerializedPrematureCommitment(50); + + bench.minEpochIterations(2000).run([&] { + CDataStream s(wire); + auto qc = std::make_shared(); + s >> *qc; + ankerl::nanobench::doNotOptimizeAway(qc->validMembers.size()); + }); +} + +BENCHMARK(DKG_QCONTRIB_DoubleDeserialize, benchmark::PriorityLevel::HIGH) +BENCHMARK(DKG_QCONTRIB_SingleDeserialize, benchmark::PriorityLevel::HIGH) +BENCHMARK(DKG_QPCOMMITMENT_DoubleDeserialize, benchmark::PriorityLevel::HIGH) +BENCHMARK(DKG_QPCOMMITMENT_SingleDeserialize, benchmark::PriorityLevel::HIGH) diff --git a/src/llmq/dkgsessionhandler.cpp b/src/llmq/dkgsessionhandler.cpp index c9258ff353f9..a8bf4c84110e 100644 --- a/src/llmq/dkgsessionhandler.cpp +++ b/src/llmq/dkgsessionhandler.cpp @@ -4,9 +4,6 @@ #include -#include -#include - #include namespace llmq { @@ -25,52 +22,6 @@ CDKGSessionHandler::CDKGSessionHandler(const Consensus::LLMQParams& _params) : CDKGSessionHandler::~CDKGSessionHandler() = default; -void CDKGPendingMessages::PushPendingMessage(NodeId from, std::shared_ptr pm, const uint256& hash) -{ - LOCK(cs_messages); - - if (messagesPerNode[from] >= maxMessagesPerNode) { - // TODO ban? - LogPrint(BCLog::LLMQ_DKG, "CDKGPendingMessages::%s -- too many messages, peer=%d\n", __func__, from); - return; - } - messagesPerNode[from]++; - - if (!seenMessages.emplace(hash).second) { - LogPrint(BCLog::LLMQ_DKG, "CDKGPendingMessages::%s -- already seen %s, peer=%d\n", __func__, hash.ToString(), from); - return; - } - - pendingMessages.emplace_back(std::make_pair(from, std::move(pm))); -} - -std::list CDKGPendingMessages::PopPendingMessages(size_t maxCount) -{ - LOCK(cs_messages); - - std::list ret; - while (!pendingMessages.empty() && ret.size() < maxCount) { - ret.emplace_back(std::move(pendingMessages.front())); - pendingMessages.pop_front(); - } - - return ret; -} - -bool CDKGPendingMessages::HasSeen(const uint256& hash) const -{ - LOCK(cs_messages); - return seenMessages.count(hash) != 0; -} - -void CDKGPendingMessages::Clear() -{ - LOCK(cs_messages); - pendingMessages.clear(); - messagesPerNode.clear(); - seenMessages.clear(); -} - void CDKGSessionHandler::ClearPendingMessages() { pendingContributions.Clear(); diff --git a/src/llmq/dkgsessionhandler.h b/src/llmq/dkgsessionhandler.h index be55bfcbaa8a..b3beac2917f3 100644 --- a/src/llmq/dkgsessionhandler.h +++ b/src/llmq/dkgsessionhandler.h @@ -5,19 +5,21 @@ #ifndef BITCOIN_LLMQ_DKGSESSIONHANDLER_H #define BITCOIN_LLMQ_DKGSESSIONHANDLER_H +#include #include // for NodeId #include +#include +#include #include #include #include #include #include +#include #include -class CDataStream; class CBlockIndex; -class uint256; namespace Consensus { struct LLMQParams; @@ -42,66 +44,87 @@ enum class QuorumPhase { }; /** - * Acts as a FIFO queue for incoming DKG messages. The reason we need this is that deserialization of these messages - * is too slow to be processed in the main message handler thread. So, instead of processing them directly from the - * main handler thread, we push them into a CDKGPendingMessages object and later pop+deserialize them in the DKG phase - * handler thread. + * Acts as a FIFO queue for incoming DKG messages. Deserialization of DKG + * payloads (which decompresses BLS G1/G2 points and IES blobs) is too slow + * to run on the main message handler thread, so the intake path performs + * that decode once and hands the typed object to this queue; the DKG phase + * handler thread later pops the already-deserialized message. * - * Each message type has it's own instance of this class. + * Each message type has its own instance of this class. */ +template class CDKGPendingMessages { public: - using BinaryMessage = std::pair>; + using PendingMessage = std::pair>; private: const size_t maxMessagesPerNode; mutable Mutex cs_messages; - std::list pendingMessages GUARDED_BY(cs_messages); + std::list pendingMessages GUARDED_BY(cs_messages); std::map messagesPerNode GUARDED_BY(cs_messages); Uint256HashSet seenMessages GUARDED_BY(cs_messages); public: explicit CDKGPendingMessages(size_t _maxMessagesPerNode) : - maxMessagesPerNode(_maxMessagesPerNode) {}; + maxMessagesPerNode(_maxMessagesPerNode) {} /** - * Enqueue a serialized DKG message under @p from with content hash @p hash. - * Caller is responsible for hashing the payload and (for real peers) - * routing the erase-request to PeerManager. Drops the message silently on + * Enqueue a typed DKG message under @p from with content hash @p hash. + * Caller is responsible for deserializing the payload, computing the + * inventory hash over the raw wire bytes, and (for real peers) routing + * the erase-request to PeerManager. Drops the message silently on * per-node capacity overflow or duplicate hash. */ - void PushPendingMessage(NodeId from, std::shared_ptr pm, const uint256& hash) - EXCLUSIVE_LOCKS_REQUIRED(!cs_messages); - - std::list PopPendingMessages(size_t maxCount) EXCLUSIVE_LOCKS_REQUIRED(!cs_messages); - bool HasSeen(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_messages); - void Clear() EXCLUSIVE_LOCKS_REQUIRED(!cs_messages); - - // Might return nullptr messages, which indicates that deserialization failed for some reason - template - std::vector>> PopAndDeserializeMessages(size_t maxCount) + void PushPendingMessage(NodeId from, std::shared_ptr msg, const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(!cs_messages) { - auto binaryMessages = PopPendingMessages(maxCount); - if (binaryMessages.empty()) { - return {}; + LOCK(cs_messages); + + // Check duplicates before charging the per-node quota so a peer that + // resends the same hash cannot exhaust its budget with dupes. + if (seenMessages.count(hash) != 0) { + LogPrint(BCLog::LLMQ_DKG, "CDKGPendingMessages::%s -- already seen %s, peer=%d\n", __func__, + hash.ToString(), from); + return; } - std::vector>> ret; - ret.reserve(binaryMessages.size()); - for (const auto& bm : binaryMessages) { - auto msg = std::make_shared(); - try { - *bm.second >> *msg; - } catch (...) { - msg = nullptr; - } - ret.emplace_back(std::make_pair(bm.first, std::move(msg))); + if (messagesPerNode[from] >= maxMessagesPerNode) { + // TODO ban? + LogPrint(BCLog::LLMQ_DKG, "CDKGPendingMessages::%s -- too many messages, peer=%d\n", __func__, from); + return; } + messagesPerNode[from]++; + + seenMessages.emplace(hash); + pendingMessages.emplace_back(from, std::move(msg)); + } + std::vector PopPendingMessages(size_t maxCount) EXCLUSIVE_LOCKS_REQUIRED(!cs_messages) + { + LOCK(cs_messages); + std::vector ret; + ret.reserve(std::min(maxCount, pendingMessages.size())); + while (!pendingMessages.empty() && ret.size() < maxCount) { + ret.emplace_back(std::move(pendingMessages.front())); + pendingMessages.pop_front(); + } return ret; } + + bool HasSeen(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_messages) + { + LOCK(cs_messages); + return seenMessages.count(hash) != 0; + } + + void Clear() EXCLUSIVE_LOCKS_REQUIRED(!cs_messages) + { + LOCK(cs_messages); + pendingMessages.clear(); + messagesPerNode.clear(); + seenMessages.clear(); + } }; /** @@ -113,10 +136,10 @@ class CDKGSessionHandler const Consensus::LLMQParams& params; // Do not guard these, they protect their internals themselves - CDKGPendingMessages pendingContributions; - CDKGPendingMessages pendingComplaints; - CDKGPendingMessages pendingJustifications; - CDKGPendingMessages pendingPrematureCommitments; + CDKGPendingMessages pendingContributions; + CDKGPendingMessages pendingComplaints; + CDKGPendingMessages pendingJustifications; + CDKGPendingMessages pendingPrematureCommitments; public: explicit CDKGSessionHandler(const Consensus::LLMQParams& _params); diff --git a/src/llmq/net_dkg.cpp b/src/llmq/net_dkg.cpp index 627761b454bb..2a656b2abf3f 100644 --- a/src/llmq/net_dkg.cpp +++ b/src/llmq/net_dkg.cpp @@ -71,43 +71,43 @@ size_t MaxDKGMessageSize(std::string_view msg_type, const Consensus::LLMQParams& return cap < HARD_CEILING ? cap : HARD_CEILING; } -// Cheap, param-only structural validation of a pushed DKG message, run at intake -// before retention. Deserializes a COPY of the payload (leaving the caller's bytes -// intact for the pending queue and its inventory hash) and checks only safe upper -// bounds derived from quorum params: no member-list lookup and no signature -// verification, which remain on the DKG worker thread. Deserializing the copy does -// decompress the BLS points carried in the payload, but that work is bounded by -// the size cap applied just before this check. Rejects malformed or clearly -// oversized payloads before retention. -bool CheckDKGMessageStructure(std::string_view msg_type, const CDataStream& vRecv, const Consensus::LLMQParams& params) +// Param-only structural validation of a typed DKG message: checks only safe +// upper bounds derived from quorum params (member-list lookup and signature +// verification remain on the DKG worker thread). Called at intake after the +// single wire deserialize so a subsequent PopPendingMessages hands back an +// already-validated object. +template +bool CheckDKGMessageStructure(const Message& msg, const Consensus::LLMQParams& params); + +template <> +bool CheckDKGMessageStructure(const CDKGContribution& qc, const Consensus::LLMQParams& params) { const size_t size = params.size > 0 ? static_cast(params.size) : 0; const size_t threshold = params.threshold > 0 ? static_cast(params.threshold) : 0; - try { - CDataStream s(vRecv); // copy; deserialization does not advance the caller's stream - if (msg_type == NetMsgType::QCONTRIB) { - CDKGContribution qc; - s >> qc; - return qc.vvec != nullptr && qc.vvec->size() == threshold && - qc.contributions != nullptr && qc.contributions->blobs.size() <= size; - } else if (msg_type == NetMsgType::QCOMPLAINT) { - CDKGComplaint qc; - s >> qc; - return qc.badMembers.size() == qc.complainForMembers.size() && - qc.badMembers.size() <= size; - } else if (msg_type == NetMsgType::QJUSTIFICATION) { - CDKGJustification qj; - s >> qj; - return qj.contributions.size() <= size; - } else if (msg_type == NetMsgType::QPCOMMITMENT) { - CDKGPrematureCommitment qc; - s >> qc; - return qc.validMembers.size() <= size; - } - return false; - } catch (const std::exception&) { - return false; - } + return qc.vvec != nullptr && qc.vvec->size() == threshold && + qc.contributions != nullptr && qc.contributions->blobs.size() <= size; +} + +template <> +bool CheckDKGMessageStructure(const CDKGComplaint& qc, const Consensus::LLMQParams& params) +{ + const size_t size = params.size > 0 ? static_cast(params.size) : 0; + return qc.badMembers.size() == qc.complainForMembers.size() && qc.badMembers.size() <= size; +} + +template <> +bool CheckDKGMessageStructure(const CDKGJustification& qj, const Consensus::LLMQParams& params) +{ + const size_t size = params.size > 0 ? static_cast(params.size) : 0; + return qj.contributions.size() <= size; +} + +template <> +bool CheckDKGMessageStructure(const CDKGPrematureCommitment& qc, + const Consensus::LLMQParams& params) +{ + const size_t size = params.size > 0 ? static_cast(params.size) : 0; + return qc.validMembers.size() <= size; } // returns a set of NodeIds which sent invalid messages @@ -252,21 +252,26 @@ void RelayInvToParticipants(const CDKGSession& session, const CConnman& connman, } template -void EnqueueOwn(CDKGPendingMessages& pending, const Message& msg) +void EnqueueOwn(CDKGPendingMessages& pending, const Message& msg) { + // Own messages skip the wire path but still populate the pending queue so + // the DKG worker sees them alongside peer messages. The inventory hash is + // computed over the serialized form so it matches what remote peers would + // compute for the same message. + auto pending_msg = std::make_shared(msg); CDataStream ds(SER_NETWORK, PROTOCOL_VERSION); - ds << msg; - auto pm = std::make_shared(std::move(ds)); + ds << *pending_msg; CHashWriter hw(SER_GETHASH, 0); - hw.write(AsWritableBytes(Span{*pm})); - pending.PushPendingMessage(/*from=*/-1, std::move(pm), hw.GetHash()); + hw.write(AsWritableBytes(Span{ds})); + pending.PushPendingMessage(/*from=*/-1, std::move(pending_msg), hw.GetHash()); } template -bool ProcessPendingMessageBatch(const CConnman& connman, CDKGSession& session, CDKGPendingMessages& pendingMessages, - PeerManagerInternal& peerman, size_t maxCount) +bool ProcessPendingMessageBatch(const CConnman& connman, CDKGSession& session, + CDKGPendingMessages& pendingMessages, PeerManagerInternal& peerman, + size_t maxCount) { - auto msgs = pendingMessages.PopAndDeserializeMessages(maxCount); + auto msgs = pendingMessages.PopPendingMessages(maxCount); if (msgs.empty()) { return false; } @@ -276,11 +281,9 @@ bool ProcessPendingMessageBatch(const CConnman& connman, CDKGSession& session, C for (const auto& p : msgs) { const NodeId& nodeId = p.first; - if (!p.second) { - LogPrint(BCLog::LLMQ_DKG, "%s -- failed to deserialize message, peer=%d\n", __func__, nodeId); - peerman.PeerMisbehaving(nodeId, 100); - continue; - } + // Intake deserializes once, so a null typed message never reaches the + // worker: malformed payloads are rejected before enqueue. + Assume(p.second != nullptr); bool ban = false; if (!session.PreVerifyMessage(*p.second, ban)) { if (ban) { @@ -455,49 +458,65 @@ void NetDKG::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStre return; } - // Cheap structural pre-validation before retention. Validates a copy so the - // original bytes (and their inventory hash) are preserved for the worker. - if (!CheckDKGMessageStructure(msg_type, vRecv, llmq_params)) { + // Inventory hash is computed over the raw wire bytes before we consume + // them, matching what a peer would compute for the same payload. + CHashWriter hw(SER_GETHASH, 0); + hw.write(AsWritableBytes(Span{vRecv})); + const uint256 hash = hw.GetHash(); + + // Deserialize once at intake and enforce the same param-derived structural + // bounds that the old copy-based check enforced. On failure (malformed + // wire form or bound violation) the peer is banned exactly as before. + int inv_type = 0; + std::shared_ptr qContribution; + std::shared_ptr qComplaint; + std::shared_ptr qJustification; + std::shared_ptr qPCommitment; + try { + if (msg_type == NetMsgType::QCONTRIB) { + qContribution = std::make_shared(); + vRecv >> *qContribution; + if (!CheckDKGMessageStructure(*qContribution, llmq_params)) throw std::runtime_error("bounds"); + inv_type = MSG_QUORUM_CONTRIB; + } else if (msg_type == NetMsgType::QCOMPLAINT) { + qComplaint = std::make_shared(); + vRecv >> *qComplaint; + if (!CheckDKGMessageStructure(*qComplaint, llmq_params)) throw std::runtime_error("bounds"); + inv_type = MSG_QUORUM_COMPLAINT; + } else if (msg_type == NetMsgType::QJUSTIFICATION) { + qJustification = std::make_shared(); + vRecv >> *qJustification; + if (!CheckDKGMessageStructure(*qJustification, llmq_params)) throw std::runtime_error("bounds"); + inv_type = MSG_QUORUM_JUSTIFICATION; + } else if (msg_type == NetMsgType::QPCOMMITMENT) { + qPCommitment = std::make_shared(); + vRecv >> *qPCommitment; + if (!CheckDKGMessageStructure(*qPCommitment, llmq_params)) throw std::runtime_error("bounds"); + inv_type = MSG_QUORUM_PREMATURE_COMMITMENT; + } + } catch (const std::exception&) { m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100, "malformed DKG message"); return; } - - int inv_type = 0; - if (msg_type == NetMsgType::QCONTRIB) - inv_type = MSG_QUORUM_CONTRIB; - else if (msg_type == NetMsgType::QCOMPLAINT) - inv_type = MSG_QUORUM_COMPLAINT; - else if (msg_type == NetMsgType::QJUSTIFICATION) - inv_type = MSG_QUORUM_JUSTIFICATION; - else if (msg_type == NetMsgType::QPCOMMITMENT) - inv_type = MSG_QUORUM_PREMATURE_COMMITMENT; Assume(inv_type != 0); // guarded by the early-return above - auto pm = std::make_shared(std::move(vRecv)); - CHashWriter hw(SER_GETHASH, 0); - hw.write(AsWritableBytes(Span{*pm})); - const uint256 hash = hw.GetHash(); - const NodeId from = pfrom.GetId(); const bool dispatched = m_qdkgsman.DoForHandler({llmqType, quorumIndex}, [&](CDKGSessionHandler& handler) { - CDKGPendingMessages* pending = nullptr; + WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(from, CInv{static_cast(inv_type), hash})); switch (inv_type) { case MSG_QUORUM_CONTRIB: - pending = &handler.pendingContributions; + handler.pendingContributions.PushPendingMessage(from, std::move(qContribution), hash); break; case MSG_QUORUM_COMPLAINT: - pending = &handler.pendingComplaints; + handler.pendingComplaints.PushPendingMessage(from, std::move(qComplaint), hash); break; case MSG_QUORUM_JUSTIFICATION: - pending = &handler.pendingJustifications; + handler.pendingJustifications.PushPendingMessage(from, std::move(qJustification), hash); break; case MSG_QUORUM_PREMATURE_COMMITMENT: - pending = &handler.pendingPrematureCommitments; + handler.pendingPrematureCommitments.PushPendingMessage(from, std::move(qPCommitment), hash); break; } - Assume(pending != nullptr); - WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(from, CInv{static_cast(inv_type), hash})); - pending->PushPendingMessage(from, std::move(pm), hash); }); if (!dispatched) { LogPrintf("NetDKG -- no session handlers for quorumIndex [%d]\n", quorumIndex); diff --git a/test/util/data/non-backported.txt b/test/util/data/non-backported.txt index 7b49af36a695..14b693d36d27 100644 --- a/test/util/data/non-backported.txt +++ b/test/util/data/non-backported.txt @@ -2,6 +2,7 @@ src/active/*.cpp src/active/*.h src/batchedlogger.* src/bench/bls*.cpp +src/bench/dkg_deserialize.cpp src/bls/*.cpp src/bls/*.h src/cachemap.h