Skip to content

Commit

Permalink
Track txids of new blocks and first-seen time of TXs in CChainLocksHa…
Browse files Browse the repository at this point in the history
…ndler
  • Loading branch information
codablock committed Mar 7, 2019
1 parent 7945192 commit bd7edc8
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/dsnotificationinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions src/dsnotificationinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class CDSNotificationInterface : public CValidationInterface
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);
Expand Down
82 changes: 81 additions & 1 deletion src/llmq/quorums_chainlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "net_processing.h"
#include "scheduler.h"
#include "spork.h"
#include "txmempool.h"
#include "validation.h"

namespace llmq
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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) {
Expand All @@ -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();
}

Expand Down
7 changes: 7 additions & 0 deletions src/llmq/quorums_chainlocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "chainparams.h"

#include <atomic>
#include <unordered_set>

class CBlockIndex;
class CScheduler;
Expand Down Expand Up @@ -61,6 +62,10 @@ class CChainLocksHandler : public CRecoveredSigsListener
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};
Expand All @@ -79,6 +84,8 @@ class CChainLocksHandler : public CRecoveredSigsListener
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);

Expand Down

0 comments on commit bd7edc8

Please sign in to comment.