Line data Source code
1 : // Copyright (c) 2023-2025 The Dash Core developers 2 : // Distributed under the MIT/X11 software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : 5 : #include <llmq/ehf_signals.h> 6 : 7 : #include <chainparams.h> 8 : #include <consensus/validation.h> 9 : #include <deploymentstatus.h> 10 : #include <evo/chainhelper.h> 11 : #include <evo/mnhftx.h> 12 : #include <index/txindex.h> // g_txindex 13 : #include <llmq/commitment.h> 14 : #include <llmq/quorumsman.h> 15 : #include <llmq/signing_shares.h> 16 : #include <primitives/transaction.h> 17 : #include <validation.h> 18 : #include <versionbits.h> 19 : 20 : namespace llmq { 21 1980 : CEHFSignalsHandler::CEHFSignalsHandler(ChainstateManager& chainman, CSigningManager& sigman, 22 : CSigSharesManager& shareman, const CQuorumManager& qman) : 23 660 : m_chainman(chainman), 24 660 : sigman(sigman), 25 660 : shareman(shareman), 26 660 : qman(qman) 27 1320 : { 28 660 : sigman.RegisterRecoveredSigsListener(this); 29 1320 : } 30 : 31 1980 : CEHFSignalsHandler::~CEHFSignalsHandler() 32 1980 : { 33 660 : sigman.UnregisterRecoveredSigsListener(this); 34 1980 : } 35 : 36 81273 : void CEHFSignalsHandler::UpdatedBlockTip(const CBlockIndex* const pindexNew) 37 : { 38 81273 : if (!DeploymentActiveAfter(pindexNew, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return; 39 : 40 52399 : const auto ehfSignals = m_chainman.ActiveChainstate().ChainHelper().ehf_manager->GetSignalsStage(pindexNew); 41 157197 : for (const auto& deployment : Params().GetConsensus().vDeployments) { 42 : // Skip deployments that do not use dip0023 43 104798 : if (!deployment.useEHF) continue; 44 : // Try to sign only activable deployments that haven't been mined yet 45 77549 : if (ehfSignals.find(deployment.bit) == ehfSignals.end() && Params().IsValidMNActivation(deployment.bit, pindexNew->GetMedianTimePast())) { 46 24244 : trySignEHFSignal(deployment.bit, pindexNew); 47 24244 : } 48 : } 49 81273 : } 50 : 51 24244 : void CEHFSignalsHandler::trySignEHFSignal(int bit, const CBlockIndex* const pindex) 52 : { 53 24244 : MNHFTxPayload mnhfPayload; 54 24244 : mnhfPayload.signal.versionBit = bit; 55 24244 : const uint256 requestId = mnhfPayload.GetRequestId(); 56 : 57 24244 : const Consensus::LLMQType& llmqType = Params().GetConsensus().llmqTypeMnhf; 58 24244 : const auto& llmq_params_opt = Params().GetLLMQ(llmqType); 59 24244 : if (!llmq_params_opt.has_value()) { 60 0 : return; 61 : } 62 24244 : if (sigman.HasRecoveredSigForId(llmqType, requestId)) { 63 7894 : WITH_LOCK(cs, ids.insert(requestId)); 64 : 65 3947 : LogPrint(BCLog::EHF, "CEHFSignalsHandler::trySignEHFSignal: already signed bit=%d at height=%d id=%s\n", bit, pindex->nHeight, requestId.ToString()); 66 : // no need to sign same message one more time 67 3947 : return; 68 : } 69 : 70 20297 : const auto quorum = llmq::SelectQuorumForSigning(llmq_params_opt.value(), m_chainman.ActiveChain(), qman, requestId); 71 20297 : if (!quorum) { 72 16743 : LogPrintf("CEHFSignalsHandler::trySignEHFSignal no quorum for id=%s\n", requestId.ToString()); 73 16743 : return; 74 : } 75 : 76 3554 : LogPrint(BCLog::EHF, "CEHFSignalsHandler::trySignEHFSignal: bit=%d at height=%d id=%s\n", bit, pindex->nHeight, requestId.ToString()); 77 3554 : mnhfPayload.signal.quorumHash = quorum->qc->quorumHash; 78 3554 : const uint256 msgHash = mnhfPayload.PrepareTx().GetHash(); 79 : 80 7108 : WITH_LOCK(cs, ids.insert(requestId)); 81 3554 : shareman.AsyncSignIfMember(llmqType, sigman, requestId, msgHash, quorum->qc->quorumHash, false, true); 82 24244 : } 83 : 84 26973 : RecoveredSigResult CEHFSignalsHandler::HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) 85 : { 86 26973 : if (g_txindex) { 87 26973 : g_txindex->BlockUntilSyncedToCurrentChain(); 88 26973 : } 89 : 90 53946 : if (WITH_LOCK(cs, return ids.find(recoveredSig.getId()) == ids.end())) { 91 : // Do nothing, it's not for this handler 92 26742 : return std::monostate{}; 93 : } 94 : 95 462 : const auto ehfSignals = m_chainman.ActiveChainstate().ChainHelper().ehf_manager->GetSignalsStage( 96 462 : WITH_LOCK(::cs_main, return m_chainman.ActiveTip())); 97 231 : MNHFTxPayload mnhfPayload; 98 450 : for (const auto& deployment : Params().GetConsensus().vDeployments) { 99 : // skip deployments that do not use dip0023 or that have already been mined 100 450 : if (!deployment.useEHF || ehfSignals.find(deployment.bit) != ehfSignals.end()) continue; 101 : 102 237 : mnhfPayload.signal.versionBit = deployment.bit; 103 237 : const uint256 expectedId = mnhfPayload.GetRequestId(); 104 237 : LogPrint(BCLog::EHF, "CEHFSignalsHandler::HandleNewRecoveredSig expecting ID=%s received=%s\n", expectedId.ToString(), recoveredSig.getId().ToString()); 105 237 : if (recoveredSig.getId() != expectedId) { 106 : // wrong deployment! Check the next one 107 6 : continue; 108 : } 109 : 110 231 : mnhfPayload.signal.quorumHash = recoveredSig.getQuorumHash(); 111 231 : mnhfPayload.signal.sig = recoveredSig.sig.Get(); 112 : 113 231 : CMutableTransaction tx = mnhfPayload.PrepareTx(); 114 : 115 231 : CTransactionRef tx_to_sent = MakeTransactionRef(std::move(tx)); 116 231 : LogPrintf("CEHFSignalsHandler::HandleNewRecoveredSig Special EHF TX is created hash=%s\n", 117 : tx_to_sent->GetHash().ToString()); 118 231 : LOCK(::cs_main); 119 231 : const MempoolAcceptResult result = m_chainman.ProcessTransaction(tx_to_sent); 120 231 : if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { 121 188 : return tx_to_sent; 122 : } 123 43 : LogPrintf("CEHFSignalsHandler::HandleNewRecoveredSig -- AcceptToMemoryPool failed: %s\n", 124 : result.m_state.ToString()); 125 43 : return std::monostate{}; 126 231 : } 127 0 : return std::monostate{}; 128 26973 : } 129 : } // namespace llmq