Skip to content

Commit bd7edc8

Browse files
committed
Track txids of new blocks and first-seen time of TXs in CChainLocksHandler
1 parent 7945192 commit bd7edc8

File tree

4 files changed

+95
-1
lines changed

4 files changed

+95
-1
lines changed

src/dsnotificationinterface.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,15 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con
7171
llmq::quorumDKGSessionManager->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
7272
}
7373

74+
void CDSNotificationInterface::NewPoWValidBlock(const CBlockIndex* pindex, const std::shared_ptr<const CBlock>& block)
75+
{
76+
llmq::chainLocksHandler->NewPoWValidBlock(pindex, block);
77+
}
78+
7479
void CDSNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock)
7580
{
7681
llmq::quorumInstantSendManager->SyncTransaction(tx, pindex, posInBlock);
82+
llmq::chainLocksHandler->SyncTransaction(tx, pindex, posInBlock);
7783
instantsend.SyncTransaction(tx, pindex, posInBlock);
7884
CPrivateSend::SyncTransaction(tx, pindex, posInBlock);
7985
}

src/dsnotificationinterface.h

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class CDSNotificationInterface : public CValidationInterface
2121
void AcceptedBlockHeader(const CBlockIndex *pindexNew) override;
2222
void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) override;
2323
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
24+
void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) override;
2425
void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) override;
2526
void NotifyMasternodeListChanged(const CDeterministicMNList& newList) override;
2627
void NotifyChainLock(const CBlockIndex* pindex);

src/llmq/quorums_chainlocks.cpp

+81-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "net_processing.h"
1212
#include "scheduler.h"
1313
#include "spork.h"
14+
#include "txmempool.h"
1415
#include "validation.h"
1516

1617
namespace llmq
@@ -244,6 +245,51 @@ void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
244245
quorumSigningManager->AsyncSignIfMember(Params().GetConsensus().llmqChainLocks, requestId, msgHash);
245246
}
246247

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+
247293
// WARNING: cs_main and cs should not be held!
248294
void CChainLocksHandler::EnforceBestChainLock()
249295
{
@@ -420,7 +466,9 @@ void CChainLocksHandler::Cleanup()
420466
}
421467
}
422468

423-
LOCK2(cs_main, cs);
469+
// need mempool.cs due to GetTransaction calls
470+
LOCK2(cs_main, mempool.cs);
471+
LOCK(cs);
424472

425473
for (auto it = seenChainLocks.begin(); it != seenChainLocks.end(); ) {
426474
if (GetTimeMillis() - it->second >= CLEANUP_SEEN_TIMEOUT) {
@@ -430,6 +478,38 @@ void CChainLocksHandler::Cleanup()
430478
}
431479
}
432480

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+
433513
lastCleanupTime = GetTimeMillis();
434514
}
435515

src/llmq/quorums_chainlocks.h

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "chainparams.h"
1313

1414
#include <atomic>
15+
#include <unordered_set>
1516

1617
class CBlockIndex;
1718
class CScheduler;
@@ -61,6 +62,10 @@ class CChainLocksHandler : public CRecoveredSigsListener
6162
uint256 lastSignedRequestId;
6263
uint256 lastSignedMsgHash;
6364

65+
// We keep track of txids from recently received blocks so that we can check if all TXs got ixlocked
66+
std::unordered_map<uint256, std::shared_ptr<std::unordered_set<uint256, StaticSaltedHasher>>> blockTxs;
67+
std::unordered_map<uint256, int64_t> txFirstSeenTime;
68+
6469
std::map<uint256, int64_t> seenChainLocks;
6570

6671
int64_t lastCleanupTime{0};
@@ -79,6 +84,8 @@ class CChainLocksHandler : public CRecoveredSigsListener
7984
void ProcessNewChainLock(NodeId from, const CChainLockSig& clsig, const uint256& hash);
8085
void AcceptedBlockHeader(const CBlockIndex* pindexNew);
8186
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork);
87+
void NewPoWValidBlock(const CBlockIndex* pindex, const std::shared_ptr<const CBlock>& block);
88+
void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock);
8289
void EnforceBestChainLock();
8390
virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig);
8491

0 commit comments

Comments
 (0)