11
11
#include " net_processing.h"
12
12
#include " scheduler.h"
13
13
#include " spork.h"
14
+ #include " txmempool.h"
14
15
#include " validation.h"
15
16
16
17
namespace llmq
@@ -244,6 +245,51 @@ void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
244
245
quorumSigningManager->AsyncSignIfMember (Params ().GetConsensus ().llmqChainLocks , requestId, msgHash);
245
246
}
246
247
248
+ void CChainLocksHandler::NewPoWValidBlock (const CBlockIndex* pindex, const std::shared_ptr<const CBlock>& block)
249
+ {
250
+ LOCK (cs);
251
+ if (blockTxs.count (pindex->GetBlockHash ())) {
252
+ // should actually not happen (blocks are only written once to disk and this is when NewPoWValidBlock is called)
253
+ // but be extra safe here in case this behaviour changes.
254
+ return ;
255
+ }
256
+
257
+ // We listen for NewPoWValidBlock so that we can collect all TX ids of all included TXs of newly received blocks
258
+ // We need this information later when we try to sign a new tip, so that we can determine if all included TXs are
259
+ // safe.
260
+
261
+ auto txs = std::make_shared<std::unordered_set<uint256, StaticSaltedHasher>>();
262
+ for (const auto & tx : block->vtx ) {
263
+ if (tx->nVersion == 3 ) {
264
+ if (tx->nType == TRANSACTION_COINBASE ||
265
+ tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
266
+ continue ;
267
+ }
268
+ }
269
+ txs->emplace (tx->GetHash ());
270
+ }
271
+ blockTxs[pindex->GetBlockHash ()] = txs;
272
+
273
+ int64_t curTime = GetAdjustedTime ();
274
+ for (auto & tx : block->vtx ) {
275
+ txFirstSeenTime.emplace (tx->GetHash (), curTime);
276
+ }
277
+ }
278
+
279
+ void CChainLocksHandler::SyncTransaction (const CTransaction& tx, const CBlockIndex* pindex, int posInBlock)
280
+ {
281
+ if (tx.nVersion == 3 ) {
282
+ if (tx.nType == TRANSACTION_COINBASE ||
283
+ tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
284
+ return ;
285
+ }
286
+ }
287
+
288
+ LOCK (cs);
289
+ int64_t curTime = GetAdjustedTime ();
290
+ txFirstSeenTime.emplace (tx.GetHash (), curTime);
291
+ }
292
+
247
293
// WARNING: cs_main and cs should not be held!
248
294
void CChainLocksHandler::EnforceBestChainLock ()
249
295
{
@@ -420,7 +466,9 @@ void CChainLocksHandler::Cleanup()
420
466
}
421
467
}
422
468
423
- LOCK2 (cs_main, cs);
469
+ // need mempool.cs due to GetTransaction calls
470
+ LOCK2 (cs_main, mempool.cs );
471
+ LOCK (cs);
424
472
425
473
for (auto it = seenChainLocks.begin (); it != seenChainLocks.end (); ) {
426
474
if (GetTimeMillis () - it->second >= CLEANUP_SEEN_TIMEOUT) {
@@ -430,6 +478,38 @@ void CChainLocksHandler::Cleanup()
430
478
}
431
479
}
432
480
481
+ for (auto it = blockTxs.begin (); it != blockTxs.end (); ) {
482
+ auto pindex = mapBlockIndex.at (it->first );
483
+ if (InternalHasChainLock (pindex->nHeight , pindex->GetBlockHash ())) {
484
+ for (auto & txid : *it->second ) {
485
+ txFirstSeenTime.erase (txid);
486
+ }
487
+ it = blockTxs.erase (it);
488
+ } else if (InternalHasConflictingChainLock (pindex->nHeight , pindex->GetBlockHash ())) {
489
+ it = blockTxs.erase (it);
490
+ } else {
491
+ ++it;
492
+ }
493
+ }
494
+ for (auto it = txFirstSeenTime.begin (); it != txFirstSeenTime.end (); ) {
495
+ CTransactionRef tx;
496
+ uint256 hashBlock;
497
+ if (!GetTransaction (it->first , tx, Params ().GetConsensus (), hashBlock)) {
498
+ // tx has vanished, probably due to conflicts
499
+ it = txFirstSeenTime.erase (it);
500
+ } else if (!hashBlock.IsNull ()) {
501
+ auto pindex = mapBlockIndex.at (hashBlock);
502
+ if (chainActive.Tip ()->GetAncestor (pindex->nHeight ) == pindex && chainActive.Height () - pindex->nHeight >= 6 ) {
503
+ // tx got confirmed >= 6 times, so we can stop keeping track of it
504
+ it = txFirstSeenTime.erase (it);
505
+ } else {
506
+ ++it;
507
+ }
508
+ } else {
509
+ ++it;
510
+ }
511
+ }
512
+
433
513
lastCleanupTime = GetTimeMillis ();
434
514
}
435
515
0 commit comments