PIVX Core  5.6.99
P2P Digital Currency
quorums_blockprocessor.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018-2021 The Dash Core developers
2 // Copyright (c) 2021-2022 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
7 
8 #include "bls/key_io.h"
9 #include "chain.h"
10 #include "chainparams.h"
11 #include "consensus/validation.h"
12 #include "evo/evodb.h"
14 #include "llmq/quorums_utils.h"
15 #include "net.h"
16 #include "primitives/block.h"
17 #include "quorums_debug.h"
18 #include "spork.h"
19 #include "validation.h"
20 
21 namespace llmq
22 {
23 std::unique_ptr<CQuorumBlockProcessor> quorumBlockProcessor{nullptr};
24 
25 static const std::string DB_MINED_COMMITMENT = "q_mc";
26 static const std::string DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT = "q_mcih";
27 
29  evoDb(_evoDb)
30 {
31  utils::InitQuorumsCache(mapHasMinedCommitmentCache);
32 }
33 
34 template<typename... Args>
35 static int LogMisbehaving(CNode* pfrom, int nDoS, const char* fmt, const Args&... args)
36 {
37  try {
38  LogPrint(BCLog::LLMQ, "Invalid QFCOMMITMENT message from peer=%d (reason: %s)\n",
39  pfrom->GetId(), tfm::format(fmt, args...));
40  } catch (tinyformat::format_error &e) {
41  LogPrintf("Error (%s) while formatting message %s\n", std::string(e.what()), fmt);
42  }
43  return nDoS;
44 }
45 
46 void CQuorumBlockProcessor::ProcessMessage(CNode* pfrom, CDataStream& vRecv, int& retMisbehavingScore)
47 {
50  vRecv >> qc;
51 
52  uint256 qfc_hash{::SerializeHash(qc)};
53  {
54  LOCK(cs_main);
55  g_connman->RemoveAskFor(qfc_hash, MSG_QUORUM_FINAL_COMMITMENT);
56  }
57 
58  if (qc.IsNull()) {
59  retMisbehavingScore = LogMisbehaving(pfrom, 100, "null commitment");
60  return;
61  }
62 
63  // Check if we already got a better one locally
64  // We do this before verifying the commitment to avoid DoS
66  return;
67  }
68 
69  CValidationState state;
70  if (!WITH_LOCK(cs_main, return VerifyLLMQCommitment(qc, chainActive.Tip(), state); )) {
71  // Not punishable reject reasons
72  static std::set<std::string> not_punishable_reasons = {
73  // can't really punish the node for "bad-qc-quorum-hash" here, as we might simply be
74  // the one that is on the wrong chain or not fully synced
75  "bad-qc-quorum-hash-not-found", "bad-qc-quorum-hash-not-active-chain"
76  };
77 
78  int dos = (not_punishable_reasons.count(state.GetRejectReason()) ? 0 : state.GetDoSScore());
79  retMisbehavingScore = LogMisbehaving(pfrom, dos, "invalid commtiment for quorum %s: %s",
80  qc.quorumHash.ToString(), state.GetRejectReason());
81  return;
82  }
83 
84  LogPrintf("%s :received commitment for quorum %s:%d, validMembers=%d, signers=%d, peer=%d\n", __func__,
85  qc.quorumHash.ToString(), qc.llmqType, qc.CountValidMembers(), qc.CountSigners(), pfrom->GetId());
86 
87  AddAndRelayMinableCommitment(qc, &qfc_hash);
88 }
89 
90 bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool fJustCheck)
91 {
92  LOCK(cs_main);
93  const auto& consensus = Params().GetConsensus();
94 
95  bool fDIP3Active = consensus.NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_V6_0);
96  if (!fDIP3Active) {
97  return true;
98  }
99 
100  std::map<Consensus::LLMQType, CFinalCommitment> qcs;
101  if (!GetCommitmentsFromBlock(block, pindex, qcs, state)) {
102  return false;
103  }
104 
105  // The following checks make sure that there is always a (possibly null) commitment while in the mining phase
106  // until the first non-null commitment has been mined. After the non-null commitment, no other commitments are
107  // allowed, including null commitments.
108  // Note: must only check quorums that were enabled at the _previous_ block height to match mining logic
109  for (const auto& llmq : consensus.llmqs) {
110  // skip these checks when replaying blocks after the crash
111  if (WITH_LOCK(cs_main, return chainActive.Tip(); ) == nullptr) {
112  break;
113  }
114 
115  // does the currently processed block contain a (possibly null) commitment for the current session?
116  Consensus::LLMQType type = llmq.first;
117  bool hasCommitmentInNewBlock = qcs.count(type) != 0;
118  bool isCommitmentRequired = IsCommitmentRequired(type, pindex->nHeight);
119 
120  if (hasCommitmentInNewBlock && !isCommitmentRequired) {
121  // If we're either not in the mining phase or a non-null commitment was mined already, reject the block
122  return state.DoS(100, false, REJECT_INVALID, "bad-qc-not-allowed");
123  }
124 
125  if (!hasCommitmentInNewBlock && isCommitmentRequired) {
126  // If no non-null commitment was mined for the mining phase yet and the new block does not include
127  // a (possibly null) commitment, the block should be rejected.
128  return state.DoS(100, false, REJECT_INVALID, "bad-qc-missing");
129  }
130  }
131 
132  const uint256& blockHash = block.GetHash();
133 
134  for (const auto& p : qcs) {
135  const auto& qc = p.second;
136  if (!ProcessCommitment(pindex->nHeight, blockHash, qc, state, fJustCheck)) {
137  return false;
138  }
139  }
140 
141  return true;
142 }
143 
144 // We store a mapping from minedHeight->quorumHeight in the DB
145 // minedHeight is inversed so that entries are traversable in reversed order
146 static std::tuple<std::string, uint8_t, uint32_t> BuildInversedHeightKey(Consensus::LLMQType llmqType, int nMinedHeight)
147 {
148  // nMinedHeight must be converted to big endian to make it comparable when serialized
149  return std::make_tuple(DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT, static_cast<uint8_t>(llmqType), htobe32(std::numeric_limits<uint32_t>::max() - nMinedHeight));
150 }
151 
152 bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockHash, const CFinalCommitment& qc, CValidationState& state, bool fJustCheck)
153 {
154  // skip `bad-qc-block` checks below when replaying blocks after a crash
155  const uint256& quorumHash = WITH_LOCK(cs_main, return chainActive.Tip(); ) != nullptr
157  : qc.quorumHash;
158 
159  if (quorumHash.IsNull()) {
160  return state.DoS(100, false, REJECT_INVALID, "bad-qc-null-quorumhash");
161  }
162  if (quorumHash != qc.quorumHash) {
163  return state.DoS(100, false, REJECT_INVALID, "bad-qc-block");
164  }
165 
166  // index of quorumHash (and commitment signature) already checked
167  const CBlockIndex* quorumIndex = mapBlockIndex.at(quorumHash);
168 
169  if (fJustCheck || qc.IsNull()) {
170  return true;
171  }
172 
173  // Store commitment in DB
174  auto cacheKey = std::make_pair(qc.llmqType, quorumHash);
175  evoDb.Write(std::make_pair(DB_MINED_COMMITMENT, cacheKey), std::make_pair(qc, blockHash));
176  evoDb.Write(BuildInversedHeightKey((Consensus::LLMQType)qc.llmqType, nHeight), quorumIndex->nHeight);
177 
178  {
180  mapHasMinedCommitmentCache.at((Consensus::LLMQType)qc.llmqType).erase(qc.quorumHash);
181  minableCommitmentsByQuorum.erase(cacheKey);
182  minableCommitments.erase(::SerializeHash(qc));
183  }
184 
185  LogPrintf("%s: processed commitment from block. type=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s\n", __func__,
187 
188  return true;
189 }
190 
191 bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pindex)
192 {
193  std::map<Consensus::LLMQType, CFinalCommitment> qcs;
194  CValidationState dummy;
195  if (!GetCommitmentsFromBlock(block, pindex, qcs, dummy)) {
196  return false;
197  }
198 
199  for (const auto& p : qcs) {
200  const auto& qc = p.second;
201  if (qc.IsNull()) {
202  continue;
203  }
204 
205  evoDb.Erase(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(static_cast<uint8_t>(qc.llmqType), qc.quorumHash)));
206  evoDb.Erase(BuildInversedHeightKey((Consensus::LLMQType)qc.llmqType, pindex->nHeight));
207  {
209  mapHasMinedCommitmentCache.at((Consensus::LLMQType)qc.llmqType).erase(qc.quorumHash);
210  }
211 
212  // if a reorg happened, we should allow to mine this commitment later
213  if (!HasBetterMinableCommitment(qc)) {
215  }
216  }
217 
218  return true;
219 }
220 
221 bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindex, std::map<Consensus::LLMQType, CFinalCommitment>& ret, CValidationState& state)
222 {
223  ret.clear();
224 
225  for (const auto& tx : block.vtx) {
226  if (!tx->IsQuorumCommitmentTx()) {
227  continue;
228  }
229  LLMQCommPL pl;
230  if (!GetTxPayload(*tx, pl)) {
231  // should not happen as it was verified before processing the block
232  return state.DoS(100, false, REJECT_INVALID, "bad-qc-payload");
233  }
234 
235  // only allow one commitment per type and per block
236  if (ret.count((Consensus::LLMQType)pl.commitment.llmqType)) {
237  return state.DoS(100, false, REJECT_INVALID, "bad-qc-dup");
238  }
239 
240  ret.emplace((Consensus::LLMQType)pl.commitment.llmqType, std::move(pl.commitment));
241  }
242 
243  return true;
244 }
245 
247 {
248  const auto& params = Params().GetConsensus().llmqs.at(llmqType);
249  int phaseIndex = nHeight % params.dkgInterval;
250  return phaseIndex >= params.dkgMiningWindowStart && phaseIndex <= params.dkgMiningWindowEnd;
251 }
252 
254 {
255  const uint256& quorumHash = GetQuorumBlockHash(llmqType, nHeight);
256 
257  // perform extra check for quorumHash.IsNull as the quorum hash is unknown for the first block of a session
258  // this is because the currently processed block's hash will be the quorumHash of this session
259  bool isMiningPhase = !quorumHash.IsNull() && IsMiningPhase(llmqType, nHeight);
260 
261  // did we already mine a non-null commitment for this session?
262  bool hasMinedCommitment = !quorumHash.IsNull() && HasMinedCommitment(llmqType, quorumHash);
263 
264  return isMiningPhase && !hasMinedCommitment;
265 }
266 
267 // This method returns UINT256_ZERO on the first block of the DKG interval (because the block hash is not known yet)
269 {
270  auto& params = Params().GetConsensus().llmqs.at(llmqType);
271  int quorumStartHeight = nHeight - (nHeight % params.dkgInterval);
272 
273  LOCK(cs_main);
274  if (quorumStartHeight > chainActive.Height()) {
275  return UINT256_ZERO;
276  }
277  return chainActive[quorumStartHeight]->GetBlockHash();
278 }
279 
281 {
282  bool fExists;
283  {
285  if (mapHasMinedCommitmentCache.at((Consensus::LLMQType)llmqType).get(quorumHash, fExists)) {
286  return fExists;
287  }
288  }
289 
290  fExists = evoDb.Exists(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(static_cast<uint8_t>(llmqType), quorumHash)));
291 
293  mapHasMinedCommitmentCache.at((Consensus::LLMQType)llmqType).insert(quorumHash, fExists);
294 
295  return fExists;
296 }
297 
298 bool CQuorumBlockProcessor::GetMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash, CFinalCommitment& retQc, uint256& retMinedBlockHash)
299 {
300  auto key = std::make_pair(DB_MINED_COMMITMENT, std::make_pair(static_cast<uint8_t>(llmqType), quorumHash));
301  std::pair<CFinalCommitment, uint256> p;
302  if (!evoDb.Read(key, p)) {
303  return false;
304  }
305  retQc = std::move(p.first);
306  retMinedBlockHash = p.second;
307  return true;
308 }
309 
310 // The returned quorums are in reversed order, so the most recent one is at index 0
311 std::vector<const CBlockIndex*> CQuorumBlockProcessor::GetMinedCommitmentsUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t maxCount)
312 {
313  LOCK(evoDb.cs);
314 
316 
317  auto firstKey = BuildInversedHeightKey(llmqType, pindex->nHeight);
318  auto lastKey = BuildInversedHeightKey(llmqType, 0);
319 
320  dbIt->Seek(firstKey);
321 
322  std::vector<const CBlockIndex*> ret;
323  ret.reserve(maxCount);
324 
325  while (dbIt->Valid() && ret.size() < maxCount) {
326  decltype(firstKey) curKey;
327  int quorumHeight;
328  if (!dbIt->GetKey(curKey) || curKey >= lastKey) {
329  break;
330  }
331  if (std::get<0>(curKey) != DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT || std::get<1>(curKey) != static_cast<uint8_t>(llmqType)) {
332  break;
333  }
334 
335  uint32_t nMinedHeight = std::numeric_limits<uint32_t>::max() - be32toh(std::get<2>(curKey));
336  if (nMinedHeight > (uint32_t) pindex->nHeight) {
337  break;
338  }
339 
340  if (!dbIt->GetValue(quorumHeight)) {
341  break;
342  }
343 
344  auto quorumIndex = pindex->GetAncestor(quorumHeight);
345  assert(quorumIndex);
346  ret.emplace_back(quorumIndex);
347 
348  dbIt->Next();
349  }
350 
351  return ret;
352 }
353 
354 // The returned quorums are in reversed order, so the most recent one is at index 0
355 std::map<Consensus::LLMQType, std::vector<const CBlockIndex*>> CQuorumBlockProcessor::GetMinedAndActiveCommitmentsUntilBlock(const CBlockIndex* pindex)
356 {
357  std::map<Consensus::LLMQType, std::vector<const CBlockIndex*>> ret;
358 
359  for (const auto& p : Params().GetConsensus().llmqs) {
360  auto& v = ret[p.second.type];
361  v.reserve(p.second.signingActiveQuorumCount);
362  auto commitments = GetMinedCommitmentsUntilBlock(p.second.type, pindex, p.second.signingActiveQuorumCount);
363  for (auto& c : commitments) {
364  v.emplace_back(c);
365  }
366  }
367 
368  return ret;
369 }
370 
372 {
374  return minableCommitments.count(hash) != 0;
375 }
376 
378 {
380  auto it = minableCommitmentsByQuorum.find(std::make_pair(qc.llmqType, qc.quorumHash));
381  if (it != minableCommitmentsByQuorum.end()) {
382  auto jt = minableCommitments.find(it->second);
383  return jt != minableCommitments.end() && jt->second.CountSigners() >= qc.CountSigners();
384  }
385  return false;
386 }
387 
389 {
390  const uint256& commitmentHash = cached_fqc_hash ? *cached_fqc_hash : ::SerializeHash(fqc);
391  {
393  auto k = std::make_pair(fqc.llmqType, fqc.quorumHash);
394  auto ins = minableCommitmentsByQuorum.emplace(k, commitmentHash);
395  if (!ins.second) {
396  // remove old commitment
397  minableCommitments.erase(ins.first->second);
398  // update commitment hash to the new one
399  ins.first->second = commitmentHash;
400  }
401  // add new commitment
402  minableCommitments.emplace(commitmentHash, fqc);
403  quorumDKGDebugManager->UpdateLocalSessionStatus((Consensus::LLMQType)fqc.llmqType, [&](CDKGDebugSessionStatus& status) {
404  if (status.quorumHash != fqc.quorumHash || status.receivedFinalCommitment) {
405  return false;
406  }
407  status.receivedFinalCommitment = true;
408  return true;
409  });
410  }
411  // relay commitment inv (if DKG is not in maintenance)
413  CInv inv(MSG_QUORUM_FINAL_COMMITMENT, commitmentHash);
414  g_connman->RelayInv(inv);
415  }
416 }
417 
418 bool CQuorumBlockProcessor::GetMinableCommitmentByHash(const uint256& commitmentHash, llmq::CFinalCommitment& ret)
419 {
420  LOCK(minableCommitmentsCs);
421  auto it = minableCommitments.find(commitmentHash);
422  if (it == minableCommitments.end()) {
423  return false;
424  }
425  ret = it->second;
426  return true;
427 }
428 
429 // Will return false if no commitment should be mined
430 // Will return true and a null commitment if no minable commitment is known and none was mined yet
431 bool CQuorumBlockProcessor::GetMinableCommitment(Consensus::LLMQType llmqType, int nHeight, CFinalCommitment& ret)
432 {
433  if (!IsCommitmentRequired(llmqType, nHeight)) {
434  // no commitment required
435  return false;
436  }
437 
438  uint256 quorumHash = GetQuorumBlockHash(llmqType, nHeight);
439  if (quorumHash.IsNull()) {
440  return false;
441  }
442 
444  // null commitment required
445  ret = CFinalCommitment(Params().GetConsensus().llmqs.at(llmqType), quorumHash);
446  return true;
447  }
448 
449  LOCK(minableCommitmentsCs);
450 
451  auto k = std::make_pair(static_cast<uint8_t>(llmqType), quorumHash);
452  auto it = minableCommitmentsByQuorum.find(k);
453  if (it == minableCommitmentsByQuorum.end()) {
454  // null commitment required
455  ret = CFinalCommitment(Params().GetConsensus().llmqs.at(llmqType), quorumHash);
456  return true;
457  }
458 
459  ret = minableCommitments.at(it->second);
460 
461  return true;
462 }
463 
464 bool CQuorumBlockProcessor::GetMinableCommitmentTx(Consensus::LLMQType llmqType, int nHeight, CTransactionRef& ret)
465 {
466  LLMQCommPL pl;
467  if (!GetMinableCommitment(llmqType, nHeight, pl.commitment)) {
468  return false;
469  }
470 
471  pl.nHeight = nHeight;
472 
475  tx.nType = CTransaction::TxType::LLMQCOMM;
476  SetTxPayload(tx, pl);
477 
478  ret = MakeTransactionRef(tx);
479 
480  return true;
481 }
482 
483 } // namespace llmq
const CChainParams & Params()
Return the currently selected parameters.
uint256 GetHash() const
Definition: block.cpp:15
Definition: block.h:80
std::vector< CTransactionRef > vtx
Definition: block.h:83
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:113
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
CBlockIndex * Tip(bool fProofOfStake=false) const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:405
int Height() const
Return the maximal height in the chain.
Definition: chain.h:450
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
std::unique_ptr< CDBTransactionIterator< CDBTransaction > > NewIteratorUniquePtr()
Definition: dbwrapper.h:716
Definition: evodb.h:32
bool Exists(const K &key)
Definition: evodb.h:76
CurTransaction & GetCurTransaction()
Definition: evodb.h:55
void Erase(const K &key)
Definition: evodb.h:83
void Write(const K &key, const V &value)
Definition: evodb.h:69
bool Read(const K &key, V &value)
Definition: evodb.h:62
RecursiveMutex cs
Definition: evodb.h:34
inv message data
Definition: protocol.h:466
Information about a peer.
Definition: net.h:669
NodeId GetId() const
Definition: net.h:825
bool IsSporkActive(SporkId nSporkID)
Definition: spork.cpp:220
Capture information about block/transaction validation.
Definition: validation.h:24
int GetDoSScore() const
Definition: validation.h:96
bool DoS(int level, bool ret=false, unsigned int chRejectCodeIn=0, std::string strRejectReasonIn="", bool corruptionIn=false, const std::string &strDebugMessageIn="")
Definition: validation.h:39
std::string GetRejectReason() const
Definition: validation.h:94
std::string ToString() const
Definition: uint256.cpp:65
bool IsNull() const
Definition: uint256.h:36
bool IsCommitmentRequired(Consensus::LLMQType llmqType, int nHeight)
bool ProcessCommitment(int nHeight, const uint256 &blockHash, const CFinalCommitment &qc, CValidationState &state, bool fJustCheck)
std::map< uint256, CFinalCommitment > minableCommitments
bool HasBetterMinableCommitment(const CFinalCommitment &qc)
bool HasMinableCommitment(const uint256 &hash)
bool UndoBlock(const CBlock &block, const CBlockIndex *pindex)
static uint256 GetQuorumBlockHash(Consensus::LLMQType llmqType, int nHeight)
std::map< std::pair< uint8_t, uint256 >, uint256 > minableCommitmentsByQuorum
bool ProcessBlock(const CBlock &block, const CBlockIndex *pindex, CValidationState &state, bool fJustCheck)
std::map< Consensus::LLMQType, std::vector< const CBlockIndex * > > GetMinedAndActiveCommitmentsUntilBlock(const CBlockIndex *pindex)
std::vector< const CBlockIndex * > GetMinedCommitmentsUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex *pindex, size_t maxCount)
bool GetMinedCommitment(Consensus::LLMQType llmqType, const uint256 &quorumHash, CFinalCommitment &ret, uint256 &retMinedBlockHash)
static bool GetCommitmentsFromBlock(const CBlock &block, const CBlockIndex *pindex, std::map< Consensus::LLMQType, CFinalCommitment > &ret, CValidationState &state)
bool HasMinedCommitment(Consensus::LLMQType llmqType, const uint256 &quorumHash)
static bool IsMiningPhase(Consensus::LLMQType llmqType, int nHeight)
void AddAndRelayMinableCommitment(const CFinalCommitment &fqc, uint256 *cached_fqc_hash=nullptr)
void ProcessMessage(CNode *pfrom, CDataStream &vRecv, int &retMisbehavingScore)
CFinalCommitment commitment
256-bit opaque blob.
Definition: uint256.h:138
uint32_t htobe32(uint32_t host_32bits)
Definition: endian.h:184
uint32_t be32toh(uint32_t big_endian_32bits)
Definition: endian.h:198
std::unique_ptr< CEvoDB > evoDb
Definition: evodb.cpp:10
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
Definition: hash.h:289
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:90
@ LOCK
Definition: lockunlock.h:16
#define LogPrint(category,...)
Definition: logging.h:163
@ LLMQ
Definition: logging.h:66
@ SAPLING
Definition: logging.h:63
@ UPGRADE_V6_0
Definition: params.h:41
LLMQType
Definition: params.h:90
std::string EncodePublic(const CChainParams &params, const CBLSPublicKey &pk)
Definition: key_io.cpp:55
void InitQuorumsCache(CacheType &cache)
Definition: quorums.cpp:26
std::unique_ptr< CQuorumBlockProcessor > quorumBlockProcessor
std::unique_ptr< CDKGDebugManager > quorumDKGDebugManager
void format(std::ostream &out, const char *fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:958
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
@ MSG_QUORUM_FINAL_COMMITMENT
Definition: protocol.h:454
bool VerifyLLMQCommitment(const llmq::CFinalCommitment &qfc, const CBlockIndex *pindexPrev, CValidationState &state)
CSporkManager sporkManager
Definition: spork.cpp:29
@ SPORK_22_LLMQ_DKG_MAINTENANCE
Definition: sporkid.h:29
A mutable version of CTransaction.
Definition: transaction.h:409
bool NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const
Returns true if the given network upgrade is active as of the given block height.
Definition: params.cpp:12
std::map< LLMQType, LLMQParams > llmqs
Definition: params.h:279
#define AssertLockNotHeld(cs)
Definition: sync.h:76
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:247
void SetTxPayload(CMutableTransaction &tx, const T &payload)
Definition: transaction.h:486
bool GetTxPayload(const std::vector< unsigned char > &payload, T &obj)
Definition: transaction.h:464
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:456
const uint256 UINT256_ZERO
constant uint256 instances
Definition: uint256.h:175
BlockMap mapBlockIndex
Definition: validation.cpp:82
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:84