diff --git a/src/chainlock/chainlock.cpp b/src/chainlock/chainlock.cpp index ea1d179dbd312..15e235dea0938 100644 --- a/src/chainlock/chainlock.cpp +++ b/src/chainlock/chainlock.cpp @@ -32,10 +32,10 @@ using node::GetTransaction; namespace llmq { namespace { -static constexpr int64_t CLEANUP_INTERVAL{1000 * 30}; -static constexpr int64_t CLEANUP_SEEN_TIMEOUT{24 * 60 * 60 * 1000}; +static constexpr auto CLEANUP_INTERVAL{30s}; +static constexpr auto CLEANUP_SEEN_TIMEOUT{24h}; //! How long to wait for islocks until we consider a block with non-islocked TXs to be safe to sign -static constexpr int64_t WAIT_FOR_ISLOCK_TIMEOUT{10 * 60}; +static constexpr auto WAIT_FOR_ISLOCK_TIMEOUT{10min}; } // anonymous namespace bool AreChainLocksEnabled(const CSporkManager& sporkman) @@ -71,15 +71,17 @@ void CChainLocksHandler::Start(const llmq::CInstantSendManager& isman) if (m_signer) { m_signer->Start(); } - scheduler->scheduleEvery([&]() { - CheckActiveState(); - EnforceBestChainLock(); - Cleanup(); - // regularly retry signing the current chaintip as it might have failed before due to missing islocks - if (m_signer) { - m_signer->TrySignChainTip(isman); - } - }, std::chrono::seconds{5}); + scheduler->scheduleEvery( + [&]() { + CheckActiveState(); + EnforceBestChainLock(); + Cleanup(); + // regularly retry signing the current chaintip as it might have failed before due to missing islocks + if (m_signer) { + m_signer->TrySignChainTip(isman); + } + }, + std::chrono::seconds{5}); } void CChainLocksHandler::Stop() @@ -131,7 +133,7 @@ MessageProcessingResult CChainLocksHandler::ProcessNewChainLock(const NodeId fro { LOCK(cs); - if (!seenChainLocks.emplace(hash, TicksSinceEpoch(SystemClock::now())).second) { + if (!seenChainLocks.emplace(hash, GetTime()).second) { return {}; } @@ -142,7 +144,8 @@ MessageProcessingResult CChainLocksHandler::ProcessNewChainLock(const NodeId fro } if (const auto ret = VerifyChainLock(clsig); ret != VerifyRecSigStatus::Valid) { - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- invalid CLSIG (%s), status=%d peer=%d\n", __func__, clsig.ToString(), ToUnderlying(ret), from); + LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- invalid CLSIG (%s), status=%d peer=%d\n", __func__, + clsig.ToString(), ToUnderlying(ret), from); if (from != -1) { return MisbehavingError{10}; } @@ -150,45 +153,41 @@ MessageProcessingResult CChainLocksHandler::ProcessNewChainLock(const NodeId fro } const CBlockIndex* pindex = WITH_LOCK(::cs_main, return m_chainstate.m_blockman.LookupBlockIndex(clsig.getBlockHash())); + const CInv clsig_inv(MSG_CLSIG, hash); { LOCK(cs); bestChainLockHash = hash; bestChainLock = clsig; - if (pindex != nullptr) { - + if (pindex) { if (pindex->nHeight != clsig.getHeight()) { // Should not happen, same as the conflict check from above. LogPrintf("CChainLocksHandler::%s -- height of CLSIG (%s) does not match the specified block's height (%d)\n", - __func__, clsig.ToString(), pindex->nHeight); + __func__, clsig.ToString(), pindex->nHeight); // Note: not relaying clsig here return {}; } - bestChainLockWithKnownBlock = bestChainLock; bestChainLockBlockIndex = pindex; + } else { + // We don't know the block/header for this CLSIG yet, so bail out for now and when the + // block/header later comes in, we will enforce the correct chain. We still relay further. + return clsig_inv; } - // else if (pindex == nullptr) - // Note: make sure to still relay clsig further. } - CInv clsigInv(MSG_CLSIG, hash); - - if (pindex == nullptr) { - // we don't know the block/header for this CLSIG yet, so bail out for now - // when the block or the header later comes in, we will enforce the correct chain - return clsigInv; - } + scheduler->scheduleFromNow( + [&]() { + CheckActiveState(); + EnforceBestChainLock(); + }, + std::chrono::seconds{0}); - scheduler->scheduleFromNow([&]() { - CheckActiveState(); - EnforceBestChainLock(); - }, std::chrono::seconds{0}); + LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- processed new CLSIG (%s), peer=%d\n", __func__, + clsig.ToString(), from); - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- processed new CLSIG (%s), peer=%d\n", - __func__, clsig.ToString(), from); - return clsigInv; + return clsig_inv; } void CChainLocksHandler::AcceptedBlockHeader(gsl::not_null pindexNew) @@ -196,7 +195,8 @@ void CChainLocksHandler::AcceptedBlockHeader(gsl::not_null p LOCK(cs); if (pindexNew->GetBlockHash() == bestChainLock.getBlockHash()) { - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- block header %s came in late, updating and enforcing\n", __func__, pindexNew->GetBlockHash().ToString()); + LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- block header %s came in late, updating and enforcing\n", + __func__, pindexNew->GetBlockHash().ToString()); if (bestChainLock.getHeight() != pindexNew->nHeight) { // Should not happen, same as the conflict check from ProcessNewChainLock. @@ -220,15 +220,17 @@ void CChainLocksHandler::UpdatedBlockTip(const llmq::CInstantSendManager& isman) // EnforceBestChainLock switching chains. // atomic[If tryLockChainTipScheduled is false, do (set it to true] and schedule signing). if (bool expected = false; tryLockChainTipScheduled.compare_exchange_strong(expected, true)) { - scheduler->scheduleFromNow([&]() { - CheckActiveState(); - EnforceBestChainLock(); - Cleanup(); - if (m_signer) { - m_signer->TrySignChainTip(isman); - } - tryLockChainTipScheduled = false; - }, std::chrono::seconds{0}); + scheduler->scheduleFromNow( + [&]() { + CheckActiveState(); + EnforceBestChainLock(); + Cleanup(); + if (m_signer) { + m_signer->TrySignChainTip(isman); + } + tryLockChainTipScheduled = false; + }, + std::chrono::seconds{0}); } } @@ -281,7 +283,8 @@ void CChainLocksHandler::BlockConnected(const std::shared_ptr& pbl } } -void CChainLocksHandler::BlockDisconnected(const std::shared_ptr& pblock, gsl::not_null pindexDisconnected) +void CChainLocksHandler::BlockDisconnected(const std::shared_ptr& pblock, + gsl::not_null pindexDisconnected) { if (m_signer) { m_signer->EraseFromBlockHashTxidMap(pindexDisconnected->GetBlockHash()); @@ -297,16 +300,16 @@ int32_t CChainLocksHandler::GetBestChainLockHeight() const bool CChainLocksHandler::IsTxSafeForMining(const uint256& txid) const { - int64_t txAge = 0; + auto tx_age{0s}; { LOCK(cs); auto it = txFirstSeenTime.find(txid); if (it != txFirstSeenTime.end()) { - txAge = GetTime().count() - it->second; + tx_age = GetTime() - it->second; } } - return txAge >= WAIT_FOR_ISLOCK_TIMEOUT; + return tx_age >= WAIT_FOR_ISLOCK_TIMEOUT; } // WARNING: cs_main and cs should not be held! @@ -340,17 +343,21 @@ void CChainLocksHandler::EnforceBestChainLock() // Go backwards through the chain referenced by clsig until we find a block that is part of the main chain. // For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig // and mark all of them as conflicting. - LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, pindex->GetBlockHash().ToString(), clsig->ToString()); + LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, + pindex->GetBlockHash().ToString(), clsig->ToString()); m_chainstate.EnforceBlock(dummy_state, pindex); - if (/*activateNeeded =*/ WITH_LOCK(::cs_main, return m_chainstate.m_chain.Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex) { + if (/*activateNeeded =*/WITH_LOCK(::cs_main, return m_chainstate.m_chain.Tip()->GetAncestor( + currentBestChainLockBlockIndex->nHeight)) != + currentBestChainLockBlockIndex) { if (!m_chainstate.ActivateBestChain(dummy_state)) { LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, dummy_state.ToString()); return; } LOCK(::cs_main); - if (m_chainstate.m_chain.Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight) != currentBestChainLockBlockIndex) { + if (m_chainstate.m_chain.Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight) != + currentBestChainLockBlockIndex) { return; } } @@ -369,9 +376,10 @@ void CChainLocksHandler::EnforceBestChainLock() VerifyRecSigStatus CChainLocksHandler::VerifyChainLock(const chainlock::ChainLockSig& clsig) const { const auto llmqType = Params().GetConsensus().llmqTypeChainLocks; - const uint256 nRequestId = ::SerializeHash(std::make_pair(chainlock::CLSIG_REQUESTID_PREFIX, clsig.getHeight())); + const uint256 nRequestId = chainlock::GenSigRequestId(clsig.getHeight()); - return llmq::VerifyRecoveredSig(llmqType, m_chainstate.m_chain, qman, clsig.getHeight(), nRequestId, clsig.getBlockHash(), clsig.getSig()); + return llmq::VerifyRecoveredSig(llmqType, m_chainstate.m_chain, qman, clsig.getHeight(), nRequestId, + clsig.getBlockHash(), clsig.getSig()); } bool CChainLocksHandler::HasChainLock(int nHeight, const uint256& blockHash) const @@ -431,15 +439,15 @@ void CChainLocksHandler::Cleanup() return; } - if (TicksSinceEpoch(SystemClock::now()) - lastCleanupTime < CLEANUP_INTERVAL) { + if (GetTime() - lastCleanupTime.load() < CLEANUP_INTERVAL) { return; } - lastCleanupTime = TicksSinceEpoch(SystemClock::now()); + lastCleanupTime = GetTime(); { LOCK(cs); - for (auto it = seenChainLocks.begin(); it != seenChainLocks.end(); ) { - if (TicksSinceEpoch(SystemClock::now()) - it->second >= CLEANUP_SEEN_TIMEOUT) { + for (auto it = seenChainLocks.begin(); it != seenChainLocks.end();) { + if (GetTime() - it->second >= CLEANUP_SEEN_TIMEOUT) { it = seenChainLocks.erase(it); } else { ++it; @@ -459,15 +467,17 @@ void CChainLocksHandler::Cleanup() LOCK(::cs_main); LOCK2(mempool.cs, cs); // need mempool.cs due to GetTransaction calls - for (auto it = txFirstSeenTime.begin(); it != txFirstSeenTime.end(); ) { + for (auto it = txFirstSeenTime.begin(); it != txFirstSeenTime.end();) { uint256 hashBlock; if (auto tx = GetTransaction(nullptr, &mempool, it->first, Params().GetConsensus(), hashBlock); !tx) { // tx has vanished, probably due to conflicts it = txFirstSeenTime.erase(it); } else if (!hashBlock.IsNull()) { const auto* pindex = m_chainstate.m_blockman.LookupBlockIndex(hashBlock); - if (m_chainstate.m_chain.Tip()->GetAncestor(pindex->nHeight) == pindex && m_chainstate.m_chain.Height() - pindex->nHeight >= 6) { - // tx got confirmed >= 6 times, so we can stop keeping track of it + assert(pindex); // GetTransaction gave us that hashBlock, it should resolve to a valid block index + if (m_chainstate.m_chain.Tip()->GetAncestor(pindex->nHeight) == pindex && + m_chainstate.m_chain.Height() - pindex->nHeight > chainlock::TX_CONFIRM_THRESHOLD) { + // tx is sufficiently deep, we can stop tracking it it = txFirstSeenTime.erase(it); } else { ++it; diff --git a/src/chainlock/chainlock.h b/src/chainlock/chainlock.h index 69ba8130ae75b..391463f0a76df 100644 --- a/src/chainlock/chainlock.h +++ b/src/chainlock/chainlock.h @@ -58,14 +58,14 @@ class CChainLocksHandler final : public chainlock::ChainLockSignerParent chainlock::ChainLockSig bestChainLock GUARDED_BY(cs); chainlock::ChainLockSig bestChainLockWithKnownBlock GUARDED_BY(cs); - const CBlockIndex* bestChainLockBlockIndex GUARDED_BY(cs) {nullptr}; - const CBlockIndex* lastNotifyChainLockBlockIndex GUARDED_BY(cs) {nullptr}; + const CBlockIndex* bestChainLockBlockIndex GUARDED_BY(cs){nullptr}; + const CBlockIndex* lastNotifyChainLockBlockIndex GUARDED_BY(cs){nullptr}; - std::unordered_map txFirstSeenTime GUARDED_BY(cs); + std::unordered_map txFirstSeenTime GUARDED_BY(cs); - std::map seenChainLocks GUARDED_BY(cs); + std::map seenChainLocks GUARDED_BY(cs); - std::atomic lastCleanupTime{0}; + std::atomic lastCleanupTime{0s}; public: explicit CChainLocksHandler(CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman, @@ -76,9 +76,12 @@ class CChainLocksHandler final : public chainlock::ChainLockSignerParent void Start(const llmq::CInstantSendManager& isman); void Stop(); - bool AlreadyHave(const CInv& inv) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - bool GetChainLockByHash(const uint256& hash, chainlock::ChainLockSig& ret) const EXCLUSIVE_LOCKS_REQUIRED(!cs); - chainlock::ChainLockSig GetBestChainLock() const EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool AlreadyHave(const CInv& inv) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); + bool GetChainLockByHash(const uint256& hash, chainlock::ChainLockSig& ret) const + EXCLUSIVE_LOCKS_REQUIRED(!cs); + chainlock::ChainLockSig GetBestChainLock() const + EXCLUSIVE_LOCKS_REQUIRED(!cs); void UpdateTxFirstSeenMap(const std::unordered_set& tx, const int64_t& time) override EXCLUSIVE_LOCKS_REQUIRED(!cs); @@ -86,13 +89,19 @@ class CChainLocksHandler final : public chainlock::ChainLockSignerParent const uint256& hash) override EXCLUSIVE_LOCKS_REQUIRED(!cs); - void AcceptedBlockHeader(gsl::not_null pindexNew) EXCLUSIVE_LOCKS_REQUIRED(!cs); + void AcceptedBlockHeader(gsl::not_null pindexNew) + EXCLUSIVE_LOCKS_REQUIRED(!cs); void UpdatedBlockTip(const llmq::CInstantSendManager& isman); - void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) EXCLUSIVE_LOCKS_REQUIRED(!cs); - void BlockConnected(const std::shared_ptr& pblock, gsl::not_null pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs); - void BlockDisconnected(const std::shared_ptr& pblock, gsl::not_null pindexDisconnected) EXCLUSIVE_LOCKS_REQUIRED(!cs); - void CheckActiveState() EXCLUSIVE_LOCKS_REQUIRED(!cs); - void EnforceBestChainLock() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) + EXCLUSIVE_LOCKS_REQUIRED(!cs); + void BlockConnected(const std::shared_ptr& pblock, gsl::not_null pindex) + EXCLUSIVE_LOCKS_REQUIRED(!cs); + void BlockDisconnected(const std::shared_ptr& pblock, gsl::not_null pindexDisconnected) + EXCLUSIVE_LOCKS_REQUIRED(!cs); + void CheckActiveState() + EXCLUSIVE_LOCKS_REQUIRED(!cs); + void EnforceBestChainLock() + EXCLUSIVE_LOCKS_REQUIRED(!cs); bool HasChainLock(int nHeight, const uint256& blockHash) const override EXCLUSIVE_LOCKS_REQUIRED(!cs); @@ -107,7 +116,8 @@ class CChainLocksHandler final : public chainlock::ChainLockSignerParent [[nodiscard]] bool IsEnabled() const override { return isEnabled; } private: - void Cleanup() EXCLUSIVE_LOCKS_REQUIRED(!cs); + void Cleanup() + EXCLUSIVE_LOCKS_REQUIRED(!cs); }; bool AreChainLocksEnabled(const CSporkManager& sporkman); diff --git a/src/chainlock/clsig.cpp b/src/chainlock/clsig.cpp index 163c8bad52715..e781a2eb10ac3 100644 --- a/src/chainlock/clsig.cpp +++ b/src/chainlock/clsig.cpp @@ -6,8 +6,10 @@ #include +#include + namespace chainlock { -const std::string CLSIG_REQUESTID_PREFIX = "clsig"; +static constexpr std::string_view CLSIG_REQUESTID_PREFIX{"clsig"}; ChainLockSig::ChainLockSig() = default; ChainLockSig::~ChainLockSig() = default; @@ -23,4 +25,9 @@ std::string ChainLockSig::ToString() const { return strprintf("ChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString()); } + +uint256 GenSigRequestId(const int32_t nHeight) +{ + return ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, nHeight)); +} } // namespace chainlock diff --git a/src/chainlock/clsig.h b/src/chainlock/clsig.h index 9efd399c27899..6cd532ce62488 100644 --- a/src/chainlock/clsig.h +++ b/src/chainlock/clsig.h @@ -13,8 +13,6 @@ #include namespace chainlock { -extern const std::string CLSIG_REQUESTID_PREFIX; - struct ChainLockSig { private: int32_t nHeight{-1}; @@ -38,6 +36,9 @@ struct ChainLockSig { READWRITE(obj.nHeight, obj.blockHash, obj.sig); } }; + +//! Generate clsig request ID with block height +uint256 GenSigRequestId(const int32_t nHeight); } // namespace chainlock #endif // BITCOIN_CHAINLOCK_CLSIG_H diff --git a/src/chainlock/signing.cpp b/src/chainlock/signing.cpp index 0ef9aa550dfb2..ef5a3513f9901 100644 --- a/src/chainlock/signing.cpp +++ b/src/chainlock/signing.cpp @@ -15,9 +15,9 @@ using node::ReadBlockFromDisk; namespace chainlock { -ChainLockSigner::ChainLockSigner(CChainState& chainstate, ChainLockSignerParent& clhandler, llmq::CSigningManager& sigman, - llmq::CSigSharesManager& shareman, CSporkManager& sporkman, - const CMasternodeSync& mn_sync) : +ChainLockSigner::ChainLockSigner(CChainState& chainstate, ChainLockSignerParent& clhandler, + llmq::CSigningManager& sigman, llmq::CSigSharesManager& shareman, + CSporkManager& sporkman, const CMasternodeSync& mn_sync) : m_chainstate{chainstate}, m_clhandler{clhandler}, m_sigman{sigman}, @@ -56,7 +56,7 @@ void ChainLockSigner::TrySignChainTip(const llmq::CInstantSendManager& isman) const CBlockIndex* pindex = WITH_LOCK(::cs_main, return m_chainstate.m_chain.Tip()); - if (pindex->pprev == nullptr) { + if (!pindex || !pindex->pprev) { return; } @@ -85,7 +85,8 @@ void ChainLockSigner::TrySignChainTip(const llmq::CInstantSendManager& isman) return; } - LogPrint(BCLog::CHAINLOCKS, "%s -- trying to sign %s, height=%d\n", __func__, pindex->GetBlockHash().ToString(), pindex->nHeight); + LogPrint(BCLog::CHAINLOCKS, "%s -- trying to sign %s, height=%d\n", __func__, pindex->GetBlockHash().ToString(), + pindex->nHeight); // When the new IX system is activated, we only try to ChainLock blocks which include safe transactions. A TX is // considered safe when it is islocked or at least known since 10 minutes (from mempool or block). These checks are @@ -94,10 +95,10 @@ void ChainLockSigner::TrySignChainTip(const llmq::CInstantSendManager& isman) if (isman.IsInstantSendEnabled() && isman.RejectConflictingBlocks()) { const auto* pindexWalk = pindex; while (pindexWalk != nullptr) { - if (pindex->nHeight - pindexWalk->nHeight > 5) { - // no need to check further down, 6 confs is safe to assume that TXs below this height won't be + if (pindex->nHeight - pindexWalk->nHeight > TX_CONFIRM_THRESHOLD) { + // no need to check further down, safe to assume that TXs below this height won't be // islocked anymore if they aren't already - LogPrint(BCLog::CHAINLOCKS, "%s -- tip and previous 5 blocks all safe\n", __func__); + LogPrint(BCLog::CHAINLOCKS, "%s -- tip and previous %d blocks all safe\n", __func__, TX_CONFIRM_THRESHOLD); break; } if (m_clhandler.HasChainLock(pindexWalk->nHeight, pindexWalk->GetBlockHash())) { @@ -114,8 +115,9 @@ void ChainLockSigner::TrySignChainTip(const llmq::CInstantSendManager& isman) for (const auto& txid : *txids) { if (!m_clhandler.IsTxSafeForMining(txid) && !isman.IsLocked(txid)) { - LogPrint(BCLog::CHAINLOCKS, "%s -- not signing block %s due to TX %s not being islocked and not old enough.\n", __func__, - pindexWalk->GetBlockHash().ToString(), txid.ToString()); + LogPrint(BCLog::CHAINLOCKS, /* Continued */ + "%s -- not signing block %s due to TX %s not being islocked and not old enough.\n", + __func__, pindexWalk->GetBlockHash().ToString(), txid.ToString()); return; } } @@ -124,7 +126,7 @@ void ChainLockSigner::TrySignChainTip(const llmq::CInstantSendManager& isman) } } - uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindex->nHeight)); + uint256 requestId = GenSigRequestId(pindex->nHeight); uint256 msgHash = pindex->GetBlockHash(); if (m_clhandler.GetBestChainLockHeight() >= pindex->nHeight) { @@ -190,6 +192,9 @@ ChainLockSigner::BlockTxs::mapped_type ChainLockSigner::GetBlockTxs(const uint25 { LOCK(::cs_main); const auto* pindex = m_chainstate.m_blockman.LookupBlockIndex(blockHash); + if (!pindex) { + return nullptr; + } CBlock block; if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { return nullptr; @@ -243,9 +248,11 @@ std::vector>> Ch AssertLockNotHeld(cs_signer); std::vector>> removed; LOCK2(::cs_main, cs_signer); - for (auto it = blockTxs.begin(); it != blockTxs.end(); ) { + for (auto it = blockTxs.begin(); it != blockTxs.end();) { const auto* pindex = m_chainstate.m_blockman.LookupBlockIndex(it->first); - if (m_clhandler.HasChainLock(pindex->nHeight, pindex->GetBlockHash())) { + if (!pindex) { + it = blockTxs.erase(it); + } else if (m_clhandler.HasChainLock(pindex->nHeight, pindex->GetBlockHash())) { removed.push_back(it->second); it = blockTxs.erase(it); } else if (m_clhandler.HasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { diff --git a/src/chainlock/signing.h b/src/chainlock/signing.h index a07df18265cd8..6f301334f15c0 100644 --- a/src/chainlock/signing.h +++ b/src/chainlock/signing.h @@ -20,6 +20,9 @@ class CSigSharesManager; } // namespace llmq namespace chainlock { +//! Depth of block including transactions before it's considered safe +static constexpr int32_t TX_CONFIRM_THRESHOLD{5}; + class ChainLockSignerParent { public: diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index ea182b3dfb604..3206f59b2c5ab 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -34,8 +34,6 @@ using node::fReindex; using node::GetTransaction; namespace llmq { -static constexpr std::string_view INPUTLOCK_REQUESTID_PREFIX{"inlock"}; - namespace { template requires std::same_as || std::same_as @@ -45,7 +43,7 @@ std::unordered_set GetIdsFromLockable(const std::ve if (vec.empty()) return ret; ret.reserve(vec.size()); for (const auto& in : vec) { - ret.emplace(::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in))); + ret.emplace(instantsend::GenInputLockRequestId(in)); } return ret; } diff --git a/src/instantsend/lock.cpp b/src/instantsend/lock.cpp index dc627ed9a0a1f..10ef0afc3c2d9 100644 --- a/src/instantsend/lock.cpp +++ b/src/instantsend/lock.cpp @@ -8,9 +8,10 @@ #include #include -#include +#include #include +static constexpr std::string_view INPUTLOCK_REQUESTID_PREFIX{"inlock"}; static constexpr std::string_view ISLOCK_REQUESTID_PREFIX{"islock"}; namespace instantsend { @@ -36,4 +37,12 @@ bool InstantSendLock::TriviallyValid() const const std::unordered_set inputs_set{inputs.begin(), inputs.end()}; return inputs_set.size() == inputs.size(); } + +template +uint256 GenInputLockRequestId(const T& val) +{ + return ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, val)); +} +template uint256 GenInputLockRequestId(const COutPoint& val); +template uint256 GenInputLockRequestId(const CTxIn& val); } // namespace instantsend diff --git a/src/instantsend/lock.h b/src/instantsend/lock.h index 5223ce5f9a767..2786ba1ff7cf9 100644 --- a/src/instantsend/lock.h +++ b/src/instantsend/lock.h @@ -40,6 +40,9 @@ struct InstantSendLock { bool TriviallyValid() const; }; +template +uint256 GenInputLockRequestId(const T& val); + using InstantSendLockPtr = std::shared_ptr; } // namespace instantsend diff --git a/src/instantsend/signing.cpp b/src/instantsend/signing.cpp index 46ea06702de64..e76730ec98be8 100644 --- a/src/instantsend/signing.cpp +++ b/src/instantsend/signing.cpp @@ -27,8 +27,6 @@ using node::fReindex; using node::GetTransaction; namespace instantsend { -static constexpr std::string_view INPUTLOCK_REQUESTID_PREFIX{"inlock"}; - InstantSendSigner::InstantSendSigner(CChainState& chainstate, llmq::CChainLocksHandler& clhandler, InstantSendSignerParent& isman, llmq::CSigningManager& sigman, llmq::CSigSharesManager& shareman, llmq::CQuorumManager& qman, @@ -113,8 +111,7 @@ void InstantSendSigner::HandleNewInputLockRecoveredSig(const llmq::CRecoveredSig if (LogAcceptDebug(BCLog::INSTANTSEND)) { for (const auto& in : tx->vin) { - auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); - if (id == recoveredSig.getId()) { + if (GenInputLockRequestId(in.prevout) == recoveredSig.getId()) { LogPrint(BCLog::INSTANTSEND, "%s -- txid=%s: got recovered sig for input %s\n", __func__, txid.ToString(), in.prevout.ToStringShort()); break; @@ -298,7 +295,7 @@ bool InstantSendSigner::TrySignInputLocks(const CTransaction& tx, bool fRetroact size_t alreadyVotedCount = 0; for (const auto& in : tx.vin) { - auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); + auto id = GenInputLockRequestId(in); ids.emplace_back(id); uint256 otherTxHash; @@ -347,7 +344,7 @@ void InstantSendSigner::TrySignInstantSendLock(const CTransaction& tx) const auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; for (const auto& in : tx.vin) { - auto id = ::SerializeHash(std::make_pair(INPUTLOCK_REQUESTID_PREFIX, in.prevout)); + auto id = GenInputLockRequestId(in); if (!m_sigman.HasRecoveredSig(llmqType, id, tx.GetHash())) { return; } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 02b4d347d4889..70f0ba4ea4967 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -645,7 +645,6 @@ class PeerManagerImpl final : public PeerManager void RequestObject(NodeId nodeid, const CInv& inv, std::chrono::microseconds current_time, bool is_masternode, bool fForce = false) override EXCLUSIVE_LOCKS_REQUIRED(::cs_main); size_t GetRequestedObjectCount(NodeId nodeid) const override EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - bool IsInvInFilter(NodeId nodeid, const uint256& hash) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void AskPeersForTransaction(const uint256& txid, bool is_masternode) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); private: void _RelayTransaction(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -2317,14 +2316,6 @@ void PeerManagerImpl::AskPeersForTransaction(const uint256& txid, bool is_master } } -bool PeerManagerImpl::IsInvInFilter(NodeId nodeid, const uint256& hash) const -{ - PeerRef peer = GetPeerRef(nodeid); - if (peer == nullptr) - return false; - return IsInvInFilter(*peer, hash); -} - bool PeerManagerImpl::IsInvInFilter(const Peer& peer, const uint256& hash) const { if (auto tx_relay = peer.GetTxRelay(); tx_relay != nullptr) { diff --git a/src/net_processing.h b/src/net_processing.h index be19716117bdd..6059e31021f47 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -85,9 +85,6 @@ class PeerManager : public CValidationInterface, public NetEventsInterface /** Send ping message to all peers */ virtual void SendPings() = 0; - /** Is an inventory in the known inventory filter. Used by InstantSend. */ - virtual bool IsInvInFilter(NodeId nodeid, const uint256& hash) const = 0; - /** Ask a number of our peers, which have a transaction in their inventory, for the transaction. */ virtual void AskPeersForTransaction(const uint256& txid, bool is_masternode) = 0;