20 #include <ripple/app/consensus/RCLConsensus.h>
21 #include <ripple/app/consensus/RCLValidations.h>
22 #include <ripple/app/ledger/BuildLedger.h>
23 #include <ripple/app/ledger/InboundLedgers.h>
24 #include <ripple/app/ledger/InboundTransactions.h>
25 #include <ripple/app/ledger/LedgerMaster.h>
26 #include <ripple/app/ledger/LocalTxs.h>
27 #include <ripple/app/ledger/OpenLedger.h>
28 #include <ripple/app/misc/AmendmentTable.h>
29 #include <ripple/app/misc/HashRouter.h>
30 #include <ripple/app/misc/LoadFeeTrack.h>
31 #include <ripple/app/misc/NetworkOPs.h>
32 #include <ripple/app/misc/TxQ.h>
33 #include <ripple/app/misc/ValidatorKeys.h>
34 #include <ripple/app/misc/ValidatorList.h>
35 #include <ripple/beast/core/LexicalCast.h>
36 #include <ripple/consensus/LedgerTiming.h>
37 #include <ripple/nodestore/DatabaseShard.h>
38 #include <ripple/overlay/Overlay.h>
39 #include <ripple/overlay/predicates.h>
40 #include <ripple/protocol/Feature.h>
41 #include <ripple/protocol/digest.h>
65 , consensus_(clock, adaptor_, journal)
80 , feeVote_(
std::move(feeVote))
83 , inboundTransactions_{inboundTransactions}
85 , nodeID_{validatorKeys.nodeID}
86 , valPublic_{validatorKeys.publicKey}
87 , valSecret_{validatorKeys.secretKey}
91 boost::optional<RCLCxLedger>
95 auto built = ledgerMaster_.getLedgerByHash(hash);
98 if (acquiringLedger_ != hash)
101 JLOG(
j_.
warn()) <<
"Need consensus ledger " << hash;
104 acquiringLedger_ = hash;
106 app_.getJobQueue().addJob(
jtADVANCE,
"getConsensusLedger",
107 [
id = hash, &app = app_](
Job&)
109 app.getInboundLedgers().acquire(
id, 0,
116 assert(!built->open() && built->isImmutable());
117 assert(built->info().hash == hash);
120 inboundTransactions_.newRound(built->info().seq);
128 protocol::TMProposeSet prop;
132 prop.set_proposeseq(
proposal.proposeSeq());
133 prop.set_closetime(
proposal.closeTime().time_since_epoch().count());
135 prop.set_currenttxhash(
137 prop.set_previousledger(
141 prop.set_nodepubkey(pk.data(), pk.size());
144 prop.set_signature(sig.data(), sig.size());
153 if (app_.getHashRouter().shouldRelay(tx.
id()))
155 JLOG(
j_.
debug()) <<
"Relaying disputed tx " << tx.
id();
157 protocol::TMTransaction msg;
158 msg.set_rawtransaction(slice.data(), slice.size());
159 msg.set_status(protocol::tsNEW);
160 msg.set_receivetimestamp(
161 app_.timeKeeper().now().time_since_epoch().count());
163 std::make_shared<Message>(msg, protocol::mtTRANSACTION)));
167 JLOG(
j_.
debug()) <<
"Not relaying disputed tx " << tx.
id();
173 JLOG(
j_.
trace()) <<
"We propose: "
178 protocol::TMProposeSet prop;
180 prop.set_currenttxhash(
182 prop.set_previousledger(
184 prop.set_proposeseq(
proposal.proposeSeq());
185 prop.set_closetime(
proposal.closeTime().time_since_epoch().count());
187 prop.set_nodepubkey(valPublic_.data(), valPublic_.size());
192 proposal.closeTime().time_since_epoch().count(),
196 auto sig =
signDigest(valPublic_, valSecret_, signingHash);
198 prop.set_signature(sig.data(), sig.size());
208 app_.getHashRouter ().addSuppression (suppression);
210 app_.overlay().send(prop);
216 inboundTransactions_.giveSet(txns.
id(), txns.
map_,
false);
219 boost::optional<RCLTxSet>
222 if (
auto txns = inboundTransactions_.getSet(setId,
true))
232 return !app_.openLedger().empty();
238 return app_.getValidations().numTrustedForLedger(h);
260 ledgerMaster_.getValidLedgerIndex());
262 if (netLgr != ledgerID)
265 app_.getOPs().consensusViewChange();
282 notify(protocol::neCLOSING_LEDGER, ledger, !wrongLCL);
284 auto const& prevLedger = ledger.ledger_;
286 ledgerMaster_.applyHeldTransactions();
288 ledgerMaster_.setBuildingLedger(prevLedger->info().seq + 1);
290 auto initialLedger = app_.openLedger().current();
292 auto initialSet = std::make_shared<SHAMap>(
294 initialSet->setUnbacked();
297 for (
auto const& tx : initialLedger->txs)
299 JLOG(
j_.
trace()) <<
"Adding open ledger TX " <<
300 tx.first->getTransactionID();
304 SHAMapItem(tx.first->getTransactionID(), std::move(s)),
310 if ((app_.config().standalone() || (
proposing && !wrongLCL)) &&
311 ((prevLedger->info().seq % 256) == 0))
314 auto const validations =
315 app_.getValidations().getTrustedForLedger (
316 prevLedger->info().parentHash);
318 if (validations.size() >= app_.validators ().quorum ())
320 feeVote_->doVoting(prevLedger, validations, initialSet);
321 app_.getAmendmentTable().doVoting(
322 prevLedger, validations, initialSet);
327 initialSet = initialSet->snapShot(
false);
331 LedgerIndex const seq = prevLedger->info().seq + 1;
334 initialSet->visitLeaves(
340 censorshipDetector_.propose(std::move(proposed));
344 auto const setHash = initialSet->getHash().as_uint256();
347 std::move(initialSet),
349 initialLedger->info().parentHash,
353 app_.timeKeeper().closeTime(),
372 std::move(consensusJson));
384 app_.getJobQueue().addJob(
387 [=, cj = std::move(consensusJson) ](
auto&)
mutable {
400 this->app_.getOPs().endConsensus();
416 bool closeTimeCorrect;
427 using namespace std::chrono_literals;
428 consensusCloseTime = prevLedger.
closeTime() + 1s;
429 closeTimeCorrect =
false;
435 consensusCloseTime, closeResolution, prevLedger.
closeTime());
436 closeTimeCorrect =
true;
440 <<
" val=" << (validating_ ?
"yes" :
"no")
441 <<
" corLCL=" << (haveCorrectLCL ?
"yes" :
"no")
442 <<
" fail=" << (consensusFail ?
"yes" :
"no");
443 JLOG(
j_.
debug()) <<
"Report: Prev = " << prevLedger.
id() <<
":"
455 JLOG(
j_.
debug()) <<
"Building canonical tx set: " << retriableTxs.key();
457 for (
auto const& item : *result.
txns.map_)
461 retriableTxs.insert(std::make_shared<STTx const>(
SerialIter{item.slice()}));
462 JLOG(
j_.
debug()) <<
" Tx: " << item.key();
466 failed.
insert(item.key());
467 JLOG(
j_.
warn()) <<
" Tx: " << item.key() <<
" throws!";
471 auto built = buildLCL(prevLedger, retriableTxs, consensusCloseTime,
472 closeTimeCorrect, closeResolution, result.
roundTime.
read(), failed);
474 auto const newLCLHash = built.id();
475 JLOG(
j_.
debug()) <<
"Built ledger #" << built.seq() <<
": " << newLCLHash;
478 notify(protocol::neACCEPTED_LEDGER, built, haveCorrectLCL);
487 result.
txns.map_->visitLeaves (
494 for (
auto const& r : retriableTxs)
495 failed.
insert (r.first.getTXID());
497 censorshipDetector_.check(std::move(
accepted),
498 [curr = built.seq(), j = app_.journal(
"CensorshipDetector"), &failed]
501 if (failed.count(id))
504 auto const wait = curr - seq;
506 if (wait && (wait % censorshipWarnInternal == 0))
508 std::ostringstream ss;
509 ss <<
"Potential Censorship: Eligible tx " << id
510 <<
", which we are tracking since ledger " << seq
511 <<
" has not been included as of ledger " << curr
514 JLOG(j.warn()) << ss.str();
522 validating_ = ledgerMaster_.isCompatible(
523 *built.ledger_,
j_.
warn(),
"Not validating");
525 if (validating_ && !consensusFail &&
526 app_.getValidations().canValidateSeq(built.seq()))
528 validate(built, result.txns, proposing);
529 JLOG(
j_.
info()) <<
"CNF Val " << newLCLHash;
532 JLOG(
j_.
info()) <<
"CNF buildLCL " << newLCLHash;
535 ledgerMaster_.consensusBuilt(
536 built.ledger_, result.txns.id(), std::move(consensusJson));
551 bool anyDisputes =
false;
552 for (
auto const& [_, dispute] : result.disputes)
555 if (!dispute.getOurVote())
561 <<
"Test applying disputed transaction that did"
562 <<
" not get in " << dispute.tx().id();
565 auto txn = std::make_shared<STTx const>(sit);
572 retriableTxs.insert(txn);
579 <<
"Failed to apply transaction we voted NO on";
589 auto const lastVal = ledgerMaster_.getValidatedLedger();
590 boost::optional<Rules> rules;
592 rules.emplace(*lastVal, app_.config().features);
594 rules.emplace(app_.config().features);
595 app_.openLedger().accept(
599 localTxs_.getTxSet(),
606 return app_.getTxQ().accept(app_, view);
611 app_.getOPs().reportFeeChange();
616 ledgerMaster_.switchLCL(built.ledger_);
619 assert(ledgerMaster_.getClosedLedger()->info().hash == built.id());
621 app_.openLedger().current()->info().parentHash == built.id());
630 auto closeTime = rawCloseTimes.self;
632 JLOG(
j_.
info()) <<
"We closed at "
633 << closeTime.time_since_epoch().count();
635 usec64_t closeTotal =
636 std::chrono::duration_cast<usec64_t>(closeTime.time_since_epoch());
639 for (
auto const& [t, v] : rawCloseTimes.peers)
646 std::chrono::duration_cast<usec64_t>(t.time_since_epoch()) * v;
649 closeTotal += usec64_t(closeCount / 2);
650 closeTotal /= closeCount;
655 auto offset = time_point{closeTotal} -
656 std::chrono::time_point_cast<duration>(closeTime);
657 JLOG(
j_.
info()) <<
"Our close offset is estimated at " << offset.count()
658 <<
" (" << closeCount <<
")";
660 app_.timeKeeper().adjustCloseTime(offset);
666 protocol::NodeEvent ne,
670 protocol::TMStatusChange s;
673 s.set_newevent(protocol::neLOST_SYNC);
677 s.set_ledgerseq(ledger.
seq());
678 s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
679 s.set_ledgerhashprevious(
686 if (!ledgerMaster_.getFullValidatedRange(uMin, uMax))
694 uMin =
std::max(uMin, ledgerMaster_.getEarliestFetch());
696 s.set_firstseq(uMin);
699 std::make_shared <Message> (
700 s, protocol::mtSTATUS_CHANGE)));
701 JLOG (
j_.
trace()) <<
"send status change to peer";
709 bool closeTimeCorrect,
716 if (
auto const replayData = ledgerMaster_.releaseReplay())
718 assert(replayData->parent()->info().hash == previousLedger.
id());
722 closeResolution, app_, retriableTxs, failedTxs,
j_);
726 using namespace std::chrono_literals;
727 app_.getTxQ().processClosedLedger(app_, *built, roundTime > 5s);
730 if (ledgerMaster_.storeLedger(built))
731 JLOG(
j_.
debug()) <<
"Consensus built ledger we already had";
732 else if (app_.getInboundLedgers().find(built->info().hash))
733 JLOG(
j_.
debug()) <<
"Consensus built ledger we were acquiring";
735 JLOG(
j_.
debug()) <<
"Consensus built new ledger";
744 using namespace std::chrono_literals;
745 auto validationTime = app_.timeKeeper().closeTime();
746 if (validationTime <= lastValidationTime_)
747 validationTime = lastValidationTime_ + 1s;
748 lastValidationTime_ = validationTime;
753 auto const& feeTrack = app_.getFeeTrack();
755 std::max(feeTrack.getLocalFee(), feeTrack.getClusterFee());
757 if (fee > feeTrack.getLoadBase())
761 if (((ledger.
seq() + 1) % 256) == 0)
764 feeVote_->doValidation(ledger.
ledger_, fees);
768 auto v = std::make_shared<STValidation>(
781 app_.getHashRouter().addSuppression(
785 protocol::TMValidation val;
788 app_.overlay().send(val);
796 JLOG(
j_.
info()) <<
"Consensus mode change before=" <<
to_string(before)
802 censorshipDetector_.reset();
830 JLOG(
j_.
error()) <<
"During consensus timerEntry: " << mn.
what();
846 JLOG(
j_.
error()) <<
"During consensus gotTxSet: " << mn.
what();
857 boost::optional<std::chrono::milliseconds> consensusDelay)
869 return consensus_.peerProposal(now, newProposal);
877 validating_ = valPublic_.size() != 0 &&
878 prevLgr.
seq() >= app_.getMaxDisallowedLedger() &&
879 !app_.getOPs().isAmendmentBlocked();
883 if (validating_ && !app_.config().standalone() && app_.validators().count())
885 auto const when = app_.validators().expires();
887 if (!when || *when < app_.timeKeeper().now())
889 JLOG(
j_.
error()) <<
"Voluntarily bowing out of consensus process "
890 "because of an expired validator list.";
895 const bool synced = app_.getOPs().getOperatingMode() ==
900 JLOG(
j_.
info()) <<
"Entering consensus process, validating, synced="
901 << (synced ?
"yes" :
"no");
906 JLOG(
j_.
info()) <<
"Entering consensus process, watching, synced="
907 << (synced ?
"yes" :
"no");
911 inboundTransactions_.newRound(prevLgr.
seq());
914 return validating_ && synced;
920 return ledgerMaster_.haveValidated();
926 return ledgerMaster_.getValidLedgerIndex();
932 return app_.validators().getQuorumKeys();
939 return app_.getValidations().laggards(seq, trustedKeys);
945 return !valPublic_.empty();
951 if (! positions && app_.getOPs().isFull())