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 0 : CEHFSignalsHandler::CEHFSignalsHandler(ChainstateManager& chainman, CSigningManager& sigman, 22 : CSigSharesManager& shareman, const CQuorumManager& qman) : 23 0 : m_chainman(chainman), 24 0 : sigman(sigman), 25 0 : shareman(shareman), 26 0 : qman(qman) 27 0 : { 28 0 : sigman.RegisterRecoveredSigsListener(this); 29 0 : } 30 : 31 0 : CEHFSignalsHandler::~CEHFSignalsHandler() 32 0 : { 33 0 : sigman.UnregisterRecoveredSigsListener(this); 34 0 : } 35 : 36 0 : void CEHFSignalsHandler::UpdatedBlockTip(const CBlockIndex* const pindexNew) 37 : { 38 0 : if (!DeploymentActiveAfter(pindexNew, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return; 39 : 40 0 : const auto ehfSignals = m_chainman.ActiveChainstate().ChainHelper().ehf_manager->GetSignalsStage(pindexNew); 41 0 : for (const auto& deployment : Params().GetConsensus().vDeployments) { 42 : // Skip deployments that do not use dip0023 43 0 : if (!deployment.useEHF) continue; 44 : // Try to sign only activable deployments that haven't been mined yet 45 0 : if (ehfSignals.find(deployment.bit) == ehfSignals.end() && Params().IsValidMNActivation(deployment.bit, pindexNew->GetMedianTimePast())) { 46 0 : trySignEHFSignal(deployment.bit, pindexNew); 47 0 : } 48 : } 49 0 : } 50 : 51 0 : void CEHFSignalsHandler::trySignEHFSignal(int bit, const CBlockIndex* const pindex) 52 : { 53 0 : MNHFTxPayload mnhfPayload; 54 0 : mnhfPayload.signal.versionBit = bit; 55 0 : const uint256 requestId = mnhfPayload.GetRequestId(); 56 : 57 0 : const Consensus::LLMQType& llmqType = Params().GetConsensus().llmqTypeMnhf; 58 0 : const auto& llmq_params_opt = Params().GetLLMQ(llmqType); 59 0 : if (!llmq_params_opt.has_value()) { 60 0 : return; 61 : } 62 0 : if (sigman.HasRecoveredSigForId(llmqType, requestId)) { 63 0 : WITH_LOCK(cs, ids.insert(requestId)); 64 : 65 0 : 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 0 : return; 68 : } 69 : 70 0 : const auto quorum = llmq::SelectQuorumForSigning(llmq_params_opt.value(), m_chainman.ActiveChain(), qman, requestId); 71 0 : if (!quorum) { 72 0 : LogPrintf("CEHFSignalsHandler::trySignEHFSignal no quorum for id=%s\n", requestId.ToString()); 73 0 : return; 74 : } 75 : 76 0 : LogPrint(BCLog::EHF, "CEHFSignalsHandler::trySignEHFSignal: bit=%d at height=%d id=%s\n", bit, pindex->nHeight, requestId.ToString()); 77 0 : mnhfPayload.signal.quorumHash = quorum->qc->quorumHash; 78 0 : const uint256 msgHash = mnhfPayload.PrepareTx().GetHash(); 79 : 80 0 : WITH_LOCK(cs, ids.insert(requestId)); 81 0 : shareman.AsyncSignIfMember(llmqType, sigman, requestId, msgHash, quorum->qc->quorumHash, false, true); 82 0 : } 83 : 84 0 : RecoveredSigResult CEHFSignalsHandler::HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) 85 : { 86 0 : if (g_txindex) { 87 0 : g_txindex->BlockUntilSyncedToCurrentChain(); 88 0 : } 89 : 90 0 : if (WITH_LOCK(cs, return ids.find(recoveredSig.getId()) == ids.end())) { 91 : // Do nothing, it's not for this handler 92 0 : return std::monostate{}; 93 : } 94 : 95 0 : const auto ehfSignals = m_chainman.ActiveChainstate().ChainHelper().ehf_manager->GetSignalsStage( 96 0 : WITH_LOCK(::cs_main, return m_chainman.ActiveTip())); 97 0 : MNHFTxPayload mnhfPayload; 98 0 : for (const auto& deployment : Params().GetConsensus().vDeployments) { 99 : // skip deployments that do not use dip0023 or that have already been mined 100 0 : if (!deployment.useEHF || ehfSignals.find(deployment.bit) != ehfSignals.end()) continue; 101 : 102 0 : mnhfPayload.signal.versionBit = deployment.bit; 103 0 : const uint256 expectedId = mnhfPayload.GetRequestId(); 104 0 : LogPrint(BCLog::EHF, "CEHFSignalsHandler::HandleNewRecoveredSig expecting ID=%s received=%s\n", expectedId.ToString(), recoveredSig.getId().ToString()); 105 0 : if (recoveredSig.getId() != expectedId) { 106 : // wrong deployment! Check the next one 107 0 : continue; 108 : } 109 : 110 0 : mnhfPayload.signal.quorumHash = recoveredSig.getQuorumHash(); 111 0 : mnhfPayload.signal.sig = recoveredSig.sig.Get(); 112 : 113 0 : CMutableTransaction tx = mnhfPayload.PrepareTx(); 114 : 115 0 : CTransactionRef tx_to_sent = MakeTransactionRef(std::move(tx)); 116 0 : LogPrintf("CEHFSignalsHandler::HandleNewRecoveredSig Special EHF TX is created hash=%s\n", 117 : tx_to_sent->GetHash().ToString()); 118 0 : LOCK(::cs_main); 119 0 : const MempoolAcceptResult result = m_chainman.ProcessTransaction(tx_to_sent); 120 0 : if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { 121 0 : return tx_to_sent; 122 : } 123 0 : LogPrintf("CEHFSignalsHandler::HandleNewRecoveredSig -- AcceptToMemoryPool failed: %s\n", 124 : result.m_state.ToString()); 125 0 : return std::monostate{}; 126 0 : } 127 0 : return std::monostate{}; 128 0 : } 129 : } // namespace llmq