#include <xrpld/app/consensus/RCLConsensus.h>

#include <xrpld/app/consensus/RCLValidations.h>

#include <xrpld/app/ledger/BuildLedger.h>

#include <xrpld/app/ledger/InboundLedgers.h>

#include <xrpld/app/ledger/InboundTransactions.h>

#include <xrpld/app/ledger/Ledger.h>

#include <xrpld/app/ledger/LedgerMaster.h>

#include <xrpld/app/ledger/LocalTxs.h>

#include <xrpld/app/ledger/OpenLedger.h>

#include <xrpld/app/misc/AmendmentTable.h>

#include <xrpld/app/misc/HashRouter.h>

#include <xrpld/app/misc/LoadFeeTrack.h>

#include <xrpld/app/misc/NegativeUNLVote.h>

#include <xrpld/app/misc/NetworkOPs.h>

#include <xrpld/app/misc/TxQ.h>

#include <xrpld/app/misc/ValidatorKeys.h>

#include <xrpld/app/misc/ValidatorList.h>

#include <xrpld/consensus/LedgerTiming.h>

#include <xrpld/overlay/Overlay.h>

#include <xrpld/overlay/predicates.h>

#include <xrpl/basics/random.h>

#include <xrpl/beast/core/LexicalCast.h>

#include <xrpl/beast/utility/instrumentation.h>

#include <xrpl/protocol/BuildInfo.h>

#include <xrpl/protocol/Feature.h>

#include <xrpl/protocol/digest.h>

#include <algorithm>

#include <mutex>

namespace ripple {

RCLConsensus::RCLConsensus(

Application& app,

std::unique_ptr<FeeVote>&& feeVote,

LedgerMaster& ledgerMaster,

LocalTxs& localTxs,

InboundTransactions& inboundTransactions,

Consensus<Adaptor>::clock_type const& clock,

ValidatorKeys const& validatorKeys,

beast::Journal journal)

: adaptor_(

app,

std::move(feeVote),

ledgerMaster,

localTxs,

inboundTransactions,

validatorKeys,

journal)

, consensus_(clock, adaptor_, journal)

, j_(journal)

{

}

RCLConsensus::Adaptor::Adaptor( Application& app, std::unique_ptr<FeeVote>&& feeVote, LedgerMaster& ledgerMaster, LocalTxs& localTxs, InboundTransactions& inboundTransactions, ValidatorKeys const& validatorKeys, beast::Journal journal) : app_(app) , feeVote_(std::move(feeVote)) , ledgerMaster_(ledgerMaster) , localTxs_(localTxs) , inboundTransactions_{inboundTransactions} , j_(journal) , validatorKeys_(validatorKeys) , valCookie_( 1 + rand_int( crypto_prng(), std::numeric_limits<std::uint64_t>::max() - 1)) , nUnlVote_(validatorKeys_.nodeID, j_) { XRPL_ASSERT( valCookie_, "ripple::RCLConsensus::Adaptor::Adaptor : nonzero cookie");

JLOG(j_.info()) << "Consensus engine started (cookie: " + std::to_string(valCookie_) + ")";

if (validatorKeys_.nodeID != beast::zero && validatorKeys_.keys) { std::stringstream ss;

JLOG(j_.info()) << "Validator identity: " << toBase58( TokenType::NodePublic, validatorKeys_.keys->masterPublicKey);

if (validatorKeys_.keys->masterPublicKey != validatorKeys_.keys->publicKey) { JLOG(j_.debug()) << "Validator ephemeral signing key: " << toBase58( TokenType::NodePublic, validatorKeys_.keys->publicKey) << " (seq: " << std::to_string(validatorKeys_.sequence) << ")"; } } }

std::optional<RCLCxLedger>

RCLConsensus::Adaptor::acquireLedger(LedgerHash const& hash)

{

auto built = ledgerMaster_.getLedgerByHash(hash);

if (!built)

{

if (acquiringLedger_ != hash)

{

JLOG(j_.warn()) << "Need consensus ledger " << hash;

acquiringLedger_ = hash;

app_.getJobQueue().addJob( jtADVANCE, "getConsensusLedger1", [id = hash, &app = app_, this]() { JLOG(j_.debug()) << "JOB advanceLedger getConsensusLedger1 started"; app.getInboundLedgers().acquireAsync( id, 0, InboundLedger::Reason::CONSENSUS); }); } return std::nullopt; }

XRPL_ASSERT( !built->open() && built->isImmutable(), "ripple::RCLConsensus::Adaptor::acquireLedger : valid ledger state"); XRPL_ASSERT( built->info().hash == hash, "ripple::RCLConsensus::Adaptor::acquireLedger : ledger hash match");

inboundTransactions_.newRound(built



>info().seq);

return RCLCxLedger(built);

}

void

RCLConsensus::Adaptor::share(RCLCxPeerPos const& peerPos)

{

protocol::TMProposeSet prop;

auto const& proposal = peerPos.proposal();

prop.set_proposeseq(proposal.proposeSeq());

prop.set_closetime(proposal.closeTime().time_since_epoch().count());

prop.set_currenttxhash(

proposal.position().begin(), proposal.position().size());

prop.set_previousledger(

proposal.prevLedger().begin(), proposal.position().size());

auto const pk = peerPos.publicKey().slice(); prop.set_nodepubkey(pk.data(), pk.size());

auto const sig = peerPos.signature(); prop.set_signature(sig.data(), sig.size());

app_.overlay().relay(prop, peerPos.suppressionID(), peerPos.publicKey());

}

void

RCLConsensus::Adaptor::share(RCLCxTx const& tx)

{

if (app_.getHashRouter().shouldRelay(tx.id())) { JLOG(j_.debug()) << "Relaying disputed tx " << tx.id(); auto const slice = tx.tx_->slice(); protocol::TMTransaction msg; msg.set_rawtransaction(slice.data(), slice.size()); msg.set_status(protocol::tsNEW); msg.set_receivetimestamp( app_.timeKeeper().now().time_since_epoch().count()); static std::set<Peer::id_t> skip{}; app_.overlay().relay(tx.id(), msg, skip); } else { JLOG(j_.debug()) << "Not relaying disputed tx " << tx.id(); } } void RCLConsensus::Adaptor::propose(RCLCxPeerPos::Proposal const& proposal) { JLOG(j_.trace()) << (proposal.isBowOut() ? "We bow out: " : "We propose: ") << ripple::to_string(proposal.prevLedger()) << " -> " << ripple::to_string(proposal.position());

protocol::TMProposeSet prop;

prop.set_currenttxhash(

proposal.position().begin(), proposal.position().size());

prop.set_previousledger(

proposal.prevLedger().begin(), proposal.prevLedger().size());

prop.set_proposeseq(proposal.proposeSeq());

prop.set_closetime(proposal.closeTime().time_since_epoch().count());