1616#include < validation.h>
1717#include < validationinterface.h>
1818
19+ #include < chainlock/signing.h>
1920#include < instantsend/instantsend.h>
2021#include < llmq/quorums.h>
2122#include < masternode/sync.h>
@@ -34,17 +35,18 @@ namespace llmq {
3435CChainLocksHandler::CChainLocksHandler (CChainState& chainstate, CQuorumManager& _qman, CSigningManager& _sigman,
3536 CSigSharesManager& _shareman, CSporkManager& sporkman, CTxMemPool& _mempool,
3637 const CMasternodeSync& mn_sync, bool is_masternode) :
37- m_chainstate (chainstate),
38- qman (_qman),
39- sigman (_sigman),
40- shareman (_shareman),
41- spork_manager (sporkman),
42- mempool (_mempool),
43- m_mn_sync (mn_sync),
44- m_is_masternode{is_masternode},
45- scheduler (std::make_unique<CScheduler>()),
46- scheduler_thread (
47- std::make_unique<std::thread>(std::thread(util::TraceThread, " cl-schdlr" , [&] { scheduler->serviceQueue (); })))
38+ m_chainstate{chainstate},
39+ qman{_qman},
40+ sigman{_sigman},
41+ spork_manager{sporkman},
42+ mempool{_mempool},
43+ m_mn_sync{mn_sync},
44+ scheduler{std::make_unique<CScheduler>()},
45+ scheduler_thread{
46+ std::make_unique<std::thread>(std::thread (util::TraceThread, " cl-schdlr" , [&] { scheduler->serviceQueue (); }))},
47+ m_signer{is_masternode
48+ ? std::make_unique<chainlock::ChainLockSigner>(chainstate, *this , _sigman, _shareman, sporkman, mn_sync)
49+ : nullptr }
4850{
4951}
5052
@@ -56,19 +58,26 @@ CChainLocksHandler::~CChainLocksHandler()
5658
5759void CChainLocksHandler::Start (const llmq::CInstantSendManager& isman)
5860{
59- sigman.RegisterRecoveredSigsListener (this );
61+ if (m_signer) {
62+ sigman.RegisterRecoveredSigsListener (m_signer.get ());
63+ }
6064 scheduler->scheduleEvery ([&]() {
6165 CheckActiveState ();
6266 EnforceBestChainLock ();
67+ Cleanup ();
6368 // regularly retry signing the current chaintip as it might have failed before due to missing islocks
64- TrySignChainTip (isman);
69+ if (m_signer) {
70+ m_signer->TrySignChainTip (isman);
71+ }
6572 }, std::chrono::seconds{5 });
6673}
6774
6875void CChainLocksHandler::Stop ()
6976{
7077 scheduler->stop ();
71- sigman.UnregisterRecoveredSigsListener (this );
78+ if (m_signer) {
79+ sigman.UnregisterRecoveredSigsListener (m_signer.get ());
80+ }
7281}
7382
7483bool CChainLocksHandler::AlreadyHave (const CInv& inv) const
@@ -195,7 +204,10 @@ void CChainLocksHandler::UpdatedBlockTip(const llmq::CInstantSendManager& isman)
195204 scheduler->scheduleFromNow ([&]() {
196205 CheckActiveState ();
197206 EnforceBestChainLock ();
198- TrySignChainTip (isman);
207+ Cleanup ();
208+ if (m_signer) {
209+ m_signer->TrySignChainTip (isman);
210+ }
199211 tryLockChainTipScheduled = false ;
200212 }, std::chrono::seconds{0 });
201213 }
@@ -234,36 +246,40 @@ void CChainLocksHandler::BlockConnected(const std::shared_ptr<const CBlock>& pbl
234246 }
235247
236248 // We listen for BlockConnected so that we can collect all TX ids of all included TXs of newly received blocks
237- // We need this information later when we try to sign a new tip, so that we can determine if all included TXs are
238- // safe.
239-
240- LOCK (cs);
241-
242- auto it = blockTxs.find (pindex->GetBlockHash ());
243- if (it == blockTxs.end ()) {
244- // we must create this entry even if there are no lockable transactions in the block, so that TrySignChainTip
245- // later knows about this block
246- it = blockTxs.emplace (pindex->GetBlockHash (), std::make_shared<std::unordered_set<uint256, StaticSaltedHasher>>()).first ;
247- }
248- auto & txids = *it->second ;
249-
250249 int64_t curTime = GetTime<std::chrono::seconds>().count ();
251-
252- for (const auto & tx : pblock->vtx ) {
253- if (tx->IsCoinBase () || tx->vin .empty ()) {
254- continue ;
250+ {
251+ LOCK (cs);
252+ for (const auto & tx : pblock->vtx ) {
253+ if (!tx->IsCoinBase () && !tx->vin .empty ()) {
254+ txFirstSeenTime.emplace (tx->GetHash (), curTime);
255+ }
255256 }
256-
257- txids.emplace (tx->GetHash ());
258- txFirstSeenTime.emplace (tx->GetHash (), curTime);
259257 }
260258
259+ // We need this information later when we try to sign a new tip, so that we can determine if all included TXs are safe.
260+ if (m_signer) {
261+ LOCK (m_signer->cs_signer );
262+ auto it = m_signer->blockTxs .find (pindex->GetBlockHash ());
263+ if (it == m_signer->blockTxs .end ()) {
264+ // We must create this entry even if there are no lockable transactions in the block, so that TrySignChainTip
265+ // later knows about this block
266+ it = m_signer->blockTxs .emplace (pindex->GetBlockHash (), std::make_shared<std::unordered_set<uint256, StaticSaltedHasher>>()).first ;
267+ }
268+ auto & txids = *it->second ;
269+ for (const auto & tx : pblock->vtx ) {
270+ if (!tx->IsCoinBase () && !tx->vin .empty ()) {
271+ txids.emplace (tx->GetHash ());
272+ }
273+ }
274+ }
261275}
262276
263277void CChainLocksHandler::BlockDisconnected (const std::shared_ptr<const CBlock>& pblock, gsl::not_null<const CBlockIndex*> pindexDisconnected)
264278{
265- LOCK (cs);
266- blockTxs.erase (pindexDisconnected->GetBlockHash ());
279+ if (m_signer) {
280+ LOCK (m_signer->cs_signer );
281+ m_signer->blockTxs .erase (pindexDisconnected->GetBlockHash ());
282+ }
267283}
268284
269285bool CChainLocksHandler::IsTxSafeForMining (const uint256& txid) const
@@ -428,15 +444,18 @@ void CChainLocksHandler::Cleanup()
428444 }
429445 }
430446
431- LOCK (cs);
432- for (const auto & tx : CleanupSigner ()) {
433- for (const auto & txid : *tx) {
434- txFirstSeenTime.erase (txid);
447+ if (m_signer) {
448+ const auto cleanup_txes{m_signer->Cleanup ()};
449+ LOCK (cs);
450+ for (const auto & tx : cleanup_txes) {
451+ for (const auto & txid : *tx) {
452+ txFirstSeenTime.erase (txid);
453+ }
435454 }
436455 }
437456
438- // need mempool.cs due to GetTransaction calls
439- LOCK2 (::cs_main, mempool.cs );
457+ LOCK (::cs_main);
458+ LOCK2 (mempool.cs , cs); // need mempool.cs due to GetTransaction calls
440459 for (auto it = txFirstSeenTime.begin (); it != txFirstSeenTime.end (); ) {
441460 uint256 hashBlock;
442461 if (auto tx = GetTransaction (nullptr , &mempool, it->first , Params ().GetConsensus (), hashBlock); !tx) {
0 commit comments