Track txids of new blocks and first-seen time of TXs in CChainLocksHandler

This commit is contained in:
Alexander Block 2019-02-28 15:04:27 +01:00
parent 7945192ff6
commit bd7edc8ae9
4 changed files with 95 additions and 1 deletions

View File

@ -71,9 +71,15 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con
llmq::quorumDKGSessionManager->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
}
void CDSNotificationInterface::NewPoWValidBlock(const CBlockIndex* pindex, const std::shared_ptr<const CBlock>& block)
{
llmq::chainLocksHandler->NewPoWValidBlock(pindex, block);
}
void CDSNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock)
{
llmq::quorumInstantSendManager->SyncTransaction(tx, pindex, posInBlock);
llmq::chainLocksHandler->SyncTransaction(tx, pindex, posInBlock);
instantsend.SyncTransaction(tx, pindex, posInBlock);
CPrivateSend::SyncTransaction(tx, pindex, posInBlock);
}

View File

@ -21,6 +21,7 @@ protected:
void AcceptedBlockHeader(const CBlockIndex *pindexNew) override;
void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) override;
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) override;
void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) override;
void NotifyMasternodeListChanged(const CDeterministicMNList& newList) override;
void NotifyChainLock(const CBlockIndex* pindex);

View File

@ -11,6 +11,7 @@
#include "net_processing.h"
#include "scheduler.h"
#include "spork.h"
#include "txmempool.h"
#include "validation.h"
namespace llmq
@ -244,6 +245,51 @@ void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl
quorumSigningManager->AsyncSignIfMember(Params().GetConsensus().llmqChainLocks, requestId, msgHash);
}
void CChainLocksHandler::NewPoWValidBlock(const CBlockIndex* pindex, const std::shared_ptr<const CBlock>& block)
{
LOCK(cs);
if (blockTxs.count(pindex->GetBlockHash())) {
// should actually not happen (blocks are only written once to disk and this is when NewPoWValidBlock is called)
// but be extra safe here in case this behaviour changes.
return;
}
// We listen for NewPoWValidBlock so that we can collect all TX ids of all included TXs of newly received blocks
// We need this information later when we try to sign a new tip, so that we can determine if all included TXs are
// safe.
auto txs = std::make_shared<std::unordered_set<uint256, StaticSaltedHasher>>();
for (const auto& tx : block->vtx) {
if (tx->nVersion == 3) {
if (tx->nType == TRANSACTION_COINBASE ||
tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
continue;
}
}
txs->emplace(tx->GetHash());
}
blockTxs[pindex->GetBlockHash()] = txs;
int64_t curTime = GetAdjustedTime();
for (auto& tx : block->vtx) {
txFirstSeenTime.emplace(tx->GetHash(), curTime);
}
}
void CChainLocksHandler::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int posInBlock)
{
if (tx.nVersion == 3) {
if (tx.nType == TRANSACTION_COINBASE ||
tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
return;
}
}
LOCK(cs);
int64_t curTime = GetAdjustedTime();
txFirstSeenTime.emplace(tx.GetHash(), curTime);
}
// WARNING: cs_main and cs should not be held!
void CChainLocksHandler::EnforceBestChainLock()
{
@ -420,7 +466,9 @@ void CChainLocksHandler::Cleanup()
}
}
LOCK2(cs_main, cs);
// need mempool.cs due to GetTransaction calls
LOCK2(cs_main, mempool.cs);
LOCK(cs);
for (auto it = seenChainLocks.begin(); it != seenChainLocks.end(); ) {
if (GetTimeMillis() - it->second >= CLEANUP_SEEN_TIMEOUT) {
@ -430,6 +478,38 @@ void CChainLocksHandler::Cleanup()
}
}
for (auto it = blockTxs.begin(); it != blockTxs.end(); ) {
auto pindex = mapBlockIndex.at(it->first);
if (InternalHasChainLock(pindex->nHeight, pindex->GetBlockHash())) {
for (auto& txid : *it->second) {
txFirstSeenTime.erase(txid);
}
it = blockTxs.erase(it);
} else if (InternalHasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) {
it = blockTxs.erase(it);
} else {
++it;
}
}
for (auto it = txFirstSeenTime.begin(); it != txFirstSeenTime.end(); ) {
CTransactionRef tx;
uint256 hashBlock;
if (!GetTransaction(it->first, tx, Params().GetConsensus(), hashBlock)) {
// tx has vanished, probably due to conflicts
it = txFirstSeenTime.erase(it);
} else if (!hashBlock.IsNull()) {
auto pindex = mapBlockIndex.at(hashBlock);
if (chainActive.Tip()->GetAncestor(pindex->nHeight) == pindex && chainActive.Height() - pindex->nHeight >= 6) {
// tx got confirmed >= 6 times, so we can stop keeping track of it
it = txFirstSeenTime.erase(it);
} else {
++it;
}
} else {
++it;
}
}
lastCleanupTime = GetTimeMillis();
}

View File

@ -12,6 +12,7 @@
#include "chainparams.h"
#include <atomic>
#include <unordered_set>
class CBlockIndex;
class CScheduler;
@ -61,6 +62,10 @@ private:
uint256 lastSignedRequestId;
uint256 lastSignedMsgHash;
// We keep track of txids from recently received blocks so that we can check if all TXs got ixlocked
std::unordered_map<uint256, std::shared_ptr<std::unordered_set<uint256, StaticSaltedHasher>>> blockTxs;
std::unordered_map<uint256, int64_t> txFirstSeenTime;
std::map<uint256, int64_t> seenChainLocks;
int64_t lastCleanupTime{0};
@ -79,6 +84,8 @@ public:
void ProcessNewChainLock(NodeId from, const CChainLockSig& clsig, const uint256& hash);
void AcceptedBlockHeader(const CBlockIndex* pindexNew);
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork);
void NewPoWValidBlock(const CBlockIndex* pindex, const std::shared_ptr<const CBlock>& block);
void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock);
void EnforceBestChainLock();
virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig);