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(
108 "getConsensusLedger",
109 [
id = hash, &app = app_](
Job&) {
110 app.getInboundLedgers().acquire(
117 assert(!built->open() && built->isImmutable());
118 assert(built->info().hash == hash);
121 inboundTransactions_.newRound(built->info().seq);
129 protocol::TMProposeSet prop;
133 prop.set_proposeseq(
proposal.proposeSeq());
134 prop.set_closetime(
proposal.closeTime().time_since_epoch().count());
136 prop.set_currenttxhash(
138 prop.set_previousledger(
142 prop.set_nodepubkey(pk.data(), pk.size());
145 prop.set_signature(sig.data(), sig.size());
154 if (app_.getHashRouter().shouldRelay(tx.
id()))
156 JLOG(
j_.
debug()) <<
"Relaying disputed tx " << tx.
id();
158 protocol::TMTransaction msg;
159 msg.set_rawtransaction(slice.data(), slice.size());
160 msg.set_status(protocol::tsNEW);
161 msg.set_receivetimestamp(
162 app_.timeKeeper().now().time_since_epoch().count());
164 std::make_shared<Message>(msg, protocol::mtTRANSACTION)));
168 JLOG(
j_.
debug()) <<
"Not relaying disputed tx " << tx.
id();
174 JLOG(
j_.
trace()) <<
"We propose: "
179 protocol::TMProposeSet prop;
181 prop.set_currenttxhash(
183 prop.set_previousledger(
185 prop.set_proposeseq(
proposal.proposeSeq());
186 prop.set_closetime(
proposal.closeTime().time_since_epoch().count());
188 prop.set_nodepubkey(valPublic_.data(), valPublic_.size());
193 proposal.closeTime().time_since_epoch().count(),
197 auto sig =
signDigest(valPublic_, valSecret_, signingHash);
199 prop.set_signature(sig.data(), sig.size());
209 app_.getHashRouter().addSuppression(suppression);
211 app_.overlay().send(prop);
217 inboundTransactions_.giveSet(txns.
id(), txns.
map_,
false);
220 boost::optional<RCLTxSet>
223 if (
auto txns = inboundTransactions_.getSet(setId,
true))
233 return !app_.openLedger().empty();
239 return app_.getValidations().numTrustedForLedger(h);
261 ledgerMaster_.getValidLedgerIndex());
263 if (netLgr != ledgerID)
266 app_.getOPs().consensusViewChange();
283 notify(protocol::neCLOSING_LEDGER, ledger, !wrongLCL);
285 auto const& prevLedger = ledger.ledger_;
287 ledgerMaster_.applyHeldTransactions();
289 ledgerMaster_.setBuildingLedger(prevLedger->info().seq + 1);
291 auto initialLedger = app_.openLedger().current();
295 initialSet->setUnbacked();
298 for (
auto const& tx : initialLedger->txs)
300 JLOG(
j_.
trace()) <<
"Adding open ledger TX "
301 << tx.first->getTransactionID();
305 SHAMapItem(tx.first->getTransactionID(), std::move(s)),
311 if ((app_.config().standalone() || (
proposing && !wrongLCL)) &&
312 ((prevLedger->info().seq % 256) == 0))
315 auto const validations = 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(
339 censorshipDetector_.propose(std::move(proposed));
343 auto const setHash = initialSet->getHash().as_uint256();
346 std::move(initialSet),
348 initialLedger->info().parentHash,
352 app_.timeKeeper().closeTime(),
371 std::move(consensusJson));
383 app_.getJobQueue().addJob(
386 [=, cj = std::move(consensusJson)](
auto&)
mutable {
399 this->app_.getOPs().endConsensus();
415 bool closeTimeCorrect;
426 using namespace std::chrono_literals;
427 consensusCloseTime = prevLedger.
closeTime() + 1s;
428 closeTimeCorrect =
false;
434 consensusCloseTime, closeResolution, prevLedger.
closeTime());
435 closeTimeCorrect =
true;
439 <<
" val=" << (validating_ ?
"yes" :
"no")
440 <<
" corLCL=" << (haveCorrectLCL ?
"yes" :
"no")
441 <<
" fail=" << (consensusFail ?
"yes" :
"no");
442 JLOG(
j_.
debug()) <<
"Report: Prev = " << prevLedger.
id() <<
":"
454 JLOG(
j_.
debug()) <<
"Building canonical tx set: " << retriableTxs.key();
456 for (
auto const& item : *result.
txns.map_)
461 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(
480 auto const newLCLHash = built.id();
481 JLOG(
j_.
debug()) <<
"Built ledger #" << built.seq() <<
": " << newLCLHash;
484 notify(protocol::neACCEPTED_LEDGER, built, haveCorrectLCL);
493 result.
txns.map_->visitLeaves(
499 for (
auto const& r : retriableTxs)
500 failed.
insert(r.first.getTXID());
502 censorshipDetector_.check(
505 j = app_.journal(
"CensorshipDetector"),
507 if (failed.count(id))
510 auto const wait = curr - seq;
512 if (wait && (wait % censorshipWarnInternal == 0))
514 std::ostringstream ss;
515 ss <<
"Potential Censorship: Eligible tx " << id
516 <<
", which we are tracking since ledger " << seq
517 <<
" has not been included as of ledger " << curr <<
".";
519 JLOG(j.warn()) << ss.str();
527 validating_ = ledgerMaster_.isCompatible(
528 *built.ledger_,
j_.
warn(),
"Not validating");
530 if (validating_ && !consensusFail &&
531 app_.getValidations().canValidateSeq(built.seq()))
533 validate(built, result.txns, proposing);
534 JLOG(
j_.
info()) <<
"CNF Val " << newLCLHash;
537 JLOG(
j_.
info()) <<
"CNF buildLCL " << newLCLHash;
540 ledgerMaster_.consensusBuilt(
541 built.ledger_, result.txns.id(), std::move(consensusJson));
556 bool anyDisputes =
false;
557 for (
auto const& [_, dispute] : result.disputes)
560 if (!dispute.getOurVote())
566 <<
"Test applying disputed transaction that did"
567 <<
" not get in " << dispute.tx().id();
570 auto txn = std::make_shared<STTx const>(sit);
577 retriableTxs.insert(txn);
584 <<
"Failed to apply transaction we voted NO on";
594 auto const lastVal = ledgerMaster_.getValidatedLedger();
595 boost::optional<Rules> rules;
597 rules.emplace(*lastVal, app_.config().features);
599 rules.emplace(app_.config().features);
600 app_.openLedger().accept(
604 localTxs_.getTxSet(),
611 return app_.getTxQ().accept(app_, view);
616 app_.getOPs().reportFeeChange();
621 ledgerMaster_.switchLCL(built.ledger_);
624 assert(ledgerMaster_.getClosedLedger()->info().hash == built.id());
625 assert(app_.openLedger().current()->info().parentHash == built.id());
636 auto closeTime = rawCloseTimes.self;
638 JLOG(
j_.
info()) <<
"We closed at "
639 << closeTime.time_since_epoch().count();
641 usec64_t closeTotal =
642 std::chrono::duration_cast<usec64_t>(closeTime.time_since_epoch());
645 for (
auto const& [t, v] : rawCloseTimes.peers)
651 std::chrono::duration_cast<usec64_t>(t.time_since_epoch()) * v;
654 closeTotal += usec64_t(closeCount / 2);
655 closeTotal /= closeCount;
660 auto offset = time_point{closeTotal} -
661 std::chrono::time_point_cast<duration>(closeTime);
662 JLOG(
j_.
info()) <<
"Our close offset is estimated at " << offset.count()
663 <<
" (" << closeCount <<
")";
665 app_.timeKeeper().adjustCloseTime(offset);
671 protocol::NodeEvent ne,
675 protocol::TMStatusChange s;
678 s.set_newevent(protocol::neLOST_SYNC);
682 s.set_ledgerseq(ledger.
seq());
683 s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
684 s.set_ledgerhashprevious(
691 if (!ledgerMaster_.getFullValidatedRange(uMin, uMax))
699 uMin =
std::max(uMin, ledgerMaster_.getEarliestFetch());
701 s.set_firstseq(uMin);
703 app_.overlay().foreach (
704 send_always(std::make_shared<Message>(s, protocol::mtSTATUS_CHANGE)));
705 JLOG(
j_.
trace()) <<
"send status change to peer";
713 bool closeTimeCorrect,
719 if (
auto const replayData = ledgerMaster_.releaseReplay())
721 assert(replayData->parent()->info().hash == previousLedger.
id());
736 using namespace std::chrono_literals;
737 app_.getTxQ().processClosedLedger(app_, *built, roundTime > 5s);
740 if (ledgerMaster_.storeLedger(built))
741 JLOG(
j_.
debug()) <<
"Consensus built ledger we already had";
742 else if (app_.getInboundLedgers().find(built->info().hash))
743 JLOG(
j_.
debug()) <<
"Consensus built ledger we were acquiring";
745 JLOG(
j_.
debug()) <<
"Consensus built new ledger";
755 using namespace std::chrono_literals;
756 auto validationTime = app_.timeKeeper().closeTime();
757 if (validationTime <= lastValidationTime_)
758 validationTime = lastValidationTime_ + 1s;
759 lastValidationTime_ = validationTime;
764 auto const& feeTrack = app_.getFeeTrack();
766 std::max(feeTrack.getLocalFee(), feeTrack.getClusterFee());
768 if (fee > feeTrack.getLoadBase())
772 if (((ledger.
seq() + 1) % 256) == 0)
775 feeVote_->doValidation(ledger.
ledger_, fees);
776 amendments = app_.getAmendmentTable().doValidation(
780 auto v = std::make_shared<STValidation>(
793 app_.getHashRouter().addSuppression(
797 protocol::TMValidation val;
800 app_.overlay().send(val);
806 JLOG(
j_.
info()) <<
"Consensus mode change before=" <<
to_string(before)
814 censorshipDetector_.reset();
842 JLOG(
j_.
error()) <<
"During consensus timerEntry: " << mn.
what();
858 JLOG(
j_.
error()) <<
"During consensus gotTxSet: " << mn.
what();
868 boost::optional<std::chrono::milliseconds> consensusDelay)
880 return consensus_.peerProposal(now, newProposal);
888 validating_ = valPublic_.size() != 0 &&
889 prevLgr.
seq() >= app_.getMaxDisallowedLedger() &&
890 !app_.getOPs().isAmendmentBlocked();
894 if (validating_ && !app_.config().standalone() && app_.validators().count())
896 auto const when = app_.validators().expires();
898 if (!when || *when < app_.timeKeeper().now())
900 JLOG(
j_.
error()) <<
"Voluntarily bowing out of consensus process "
901 "because of an expired validator list.";
910 JLOG(
j_.
info()) <<
"Entering consensus process, validating, synced="
911 << (synced ?
"yes" :
"no");
916 JLOG(
j_.
info()) <<
"Entering consensus process, watching, synced="
917 << (synced ?
"yes" :
"no");
921 inboundTransactions_.newRound(prevLgr.
seq());
924 return validating_ && synced;
930 return ledgerMaster_.haveValidated();
936 return ledgerMaster_.getValidLedgerIndex();
942 return app_.validators().getQuorumKeys();
950 return app_.getValidations().laggards(seq, trustedKeys);
956 return !valPublic_.empty();
962 if (!positions && app_.getOPs().isFull())