rippled
RCLConsensus.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
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>
42 
43 #include <algorithm>
44 #include <mutex>
45 
46 namespace ripple {
47 
49  Application& app,
50  std::unique_ptr<FeeVote>&& feeVote,
51  LedgerMaster& ledgerMaster,
52  LocalTxs& localTxs,
53  InboundTransactions& inboundTransactions,
54  Consensus<Adaptor>::clock_type const& clock,
55  ValidatorKeys const& validatorKeys,
56  beast::Journal journal)
57  : adaptor_(
58  app,
59  std::move(feeVote),
61  localTxs,
62  inboundTransactions,
63  validatorKeys,
64  journal)
65  , consensus_(clock, adaptor_, journal)
66  , j_(journal)
67 
68 {
69 }
70 
72  Application& app,
73  std::unique_ptr<FeeVote>&& feeVote,
74  LedgerMaster& ledgerMaster,
75  LocalTxs& localTxs,
76  InboundTransactions& inboundTransactions,
77  ValidatorKeys const& validatorKeys,
78  beast::Journal journal)
79  : app_(app)
80  , feeVote_(std::move(feeVote))
81  , ledgerMaster_(ledgerMaster)
82  , localTxs_(localTxs)
83  , inboundTransactions_{inboundTransactions}
84  , j_(journal)
85  , nodeID_{validatorKeys.nodeID}
86  , valPublic_{validatorKeys.publicKey}
87  , valSecret_{validatorKeys.secretKey}
88 {
89 }
90 
91 boost::optional<RCLCxLedger>
93 {
94  // we need to switch the ledger we're working from
95  auto built = ledgerMaster_.getLedgerByHash(hash);
96  if (!built)
97  {
98  if (acquiringLedger_ != hash)
99  {
100  // need to start acquiring the correct consensus LCL
101  JLOG(j_.warn()) << "Need consensus ledger " << hash;
102 
103  // Tell the ledger acquire system that we need the consensus ledger
104  acquiringLedger_ = hash;
105 
106  app_.getJobQueue().addJob(
107  jtADVANCE,
108  "getConsensusLedger",
109  [id = hash, &app = app_](Job&) {
110  app.getInboundLedgers().acquire(
112  });
113  }
114  return boost::none;
115  }
116 
117  assert(!built->open() && built->isImmutable());
118  assert(built->info().hash == hash);
119 
120  // Notify inbound transactions of the new ledger sequence number
121  inboundTransactions_.newRound(built->info().seq);
122 
123  return RCLCxLedger(built);
124 }
125 
126 void
128 {
129  protocol::TMProposeSet prop;
130 
131  auto const& proposal = peerPos.proposal();
132 
133  prop.set_proposeseq(proposal.proposeSeq());
134  prop.set_closetime(proposal.closeTime().time_since_epoch().count());
135 
136  prop.set_currenttxhash(
137  proposal.position().begin(), proposal.position().size());
138  prop.set_previousledger(
139  proposal.prevLedger().begin(), proposal.position().size());
140 
141  auto const pk = peerPos.publicKey().slice();
142  prop.set_nodepubkey(pk.data(), pk.size());
143 
144  auto const sig = peerPos.signature();
145  prop.set_signature(sig.data(), sig.size());
146 
147  app_.overlay().relay(prop, peerPos.suppressionID());
148 }
149 
150 void
152 {
153  // If we didn't relay this transaction recently, relay it to all peers
154  if (app_.getHashRouter().shouldRelay(tx.id()))
155  {
156  JLOG(j_.debug()) << "Relaying disputed tx " << tx.id();
157  auto const slice = tx.tx_.slice();
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());
163  app_.overlay().foreach (send_always(
164  std::make_shared<Message>(msg, protocol::mtTRANSACTION)));
165  }
166  else
167  {
168  JLOG(j_.debug()) << "Not relaying disputed tx " << tx.id();
169  }
170 }
171 void
173 {
174  JLOG(j_.trace()) << "We propose: "
175  << (proposal.isBowOut()
176  ? std::string("bowOut")
177  : ripple::to_string(proposal.position()));
178 
179  protocol::TMProposeSet prop;
180 
181  prop.set_currenttxhash(
182  proposal.position().begin(), proposal.position().size());
183  prop.set_previousledger(
184  proposal.prevLedger().begin(), proposal.position().size());
185  prop.set_proposeseq(proposal.proposeSeq());
186  prop.set_closetime(proposal.closeTime().time_since_epoch().count());
187 
188  prop.set_nodepubkey(valPublic_.data(), valPublic_.size());
189 
190  auto signingHash = sha512Half(
192  std::uint32_t(proposal.proposeSeq()),
193  proposal.closeTime().time_since_epoch().count(),
194  proposal.prevLedger(),
195  proposal.position());
196 
197  auto sig = signDigest(valPublic_, valSecret_, signingHash);
198 
199  prop.set_signature(sig.data(), sig.size());
200 
201  auto const suppression = proposalUniqueId(
202  proposal.position(),
203  proposal.prevLedger(),
204  proposal.proposeSeq(),
205  proposal.closeTime(),
206  valPublic_,
207  sig);
208 
209  app_.getHashRouter().addSuppression(suppression);
210 
211  app_.overlay().send(prop);
212 }
213 
214 void
216 {
217  inboundTransactions_.giveSet(txns.id(), txns.map_, false);
218 }
219 
220 boost::optional<RCLTxSet>
222 {
223  if (auto txns = inboundTransactions_.getSet(setId, true))
224  {
225  return RCLTxSet{std::move(txns)};
226  }
227  return boost::none;
228 }
229 
230 bool
232 {
233  return !app_.openLedger().empty();
234 }
235 
238 {
239  return app_.getValidations().numTrustedForLedger(h);
240 }
241 
244  RCLCxLedger const& ledger,
245  LedgerHash const& h) const
246 {
247  RCLValidations& vals = app_.getValidations();
248  return vals.getNodesAfter(
249  RCLValidatedLedger(ledger.ledger_, vals.adaptor().journal()), h);
250 }
251 
252 uint256
254  uint256 ledgerID,
255  RCLCxLedger const& ledger,
257 {
258  RCLValidations& vals = app_.getValidations();
259  uint256 netLgr = vals.getPreferred(
260  RCLValidatedLedger{ledger.ledger_, vals.adaptor().journal()},
261  ledgerMaster_.getValidLedgerIndex());
262 
263  if (netLgr != ledgerID)
264  {
266  app_.getOPs().consensusViewChange();
267 
268  JLOG(j_.debug()) << Json::Compact(app_.getValidations().getJsonTrie());
269  }
270 
271  return netLgr;
272 }
273 
274 auto
276  RCLCxLedger const& ledger,
277  NetClock::time_point const& closeTime,
279 {
280  const bool wrongLCL = mode == ConsensusMode::wrongLedger;
281  const bool proposing = mode == ConsensusMode::proposing;
282 
283  notify(protocol::neCLOSING_LEDGER, ledger, !wrongLCL);
284 
285  auto const& prevLedger = ledger.ledger_;
286 
287  ledgerMaster_.applyHeldTransactions();
288  // Tell the ledger master not to acquire the ledger we're probably building
289  ledgerMaster_.setBuildingLedger(prevLedger->info().seq + 1);
290 
291  auto initialLedger = app_.openLedger().current();
292 
293  auto initialSet =
294  std::make_shared<SHAMap>(SHAMapType::TRANSACTION, app_.family());
295  initialSet->setUnbacked();
296 
297  // Build SHAMap containing all transactions in our open ledger
298  for (auto const& tx : initialLedger->txs)
299  {
300  JLOG(j_.trace()) << "Adding open ledger TX "
301  << tx.first->getTransactionID();
302  Serializer s(2048);
303  tx.first->add(s);
304  initialSet->addItem(
305  SHAMapItem(tx.first->getTransactionID(), std::move(s)),
306  true,
307  false);
308  }
309 
310  // Add pseudo-transactions to the set
311  if ((app_.config().standalone() || (proposing && !wrongLCL)) &&
312  ((prevLedger->info().seq % 256) == 0))
313  {
314  // previous ledger was flag ledger, add pseudo-transactions
315  auto const validations = app_.getValidations().getTrustedForLedger(
316  prevLedger->info().parentHash);
317 
318  if (validations.size() >= app_.validators().quorum())
319  {
320  feeVote_->doVoting(prevLedger, validations, initialSet);
321  app_.getAmendmentTable().doVoting(
322  prevLedger, validations, initialSet);
323  }
324  }
325 
326  // Now we need an immutable snapshot
327  initialSet = initialSet->snapShot(false);
328 
329  if (!wrongLCL)
330  {
331  LedgerIndex const seq = prevLedger->info().seq + 1;
333 
334  initialSet->visitLeaves(
335  [&proposed, seq](std::shared_ptr<SHAMapItem const> const& item) {
336  proposed.emplace_back(item->key(), seq);
337  });
338 
339  censorshipDetector_.propose(std::move(proposed));
340  }
341 
342  // Needed because of the move below.
343  auto const setHash = initialSet->getHash().as_uint256();
344 
345  return Result{
346  std::move(initialSet),
348  initialLedger->info().parentHash,
350  setHash,
351  closeTime,
352  app_.timeKeeper().closeTime(),
353  nodeID_}};
354 }
355 
356 void
358  Result const& result,
359  RCLCxLedger const& prevLedger,
360  NetClock::duration const& closeResolution,
361  ConsensusCloseTimes const& rawCloseTimes,
362  ConsensusMode const& mode,
363  Json::Value&& consensusJson)
364 {
365  doAccept(
366  result,
367  prevLedger,
368  closeResolution,
369  rawCloseTimes,
370  mode,
371  std::move(consensusJson));
372 }
373 
374 void
376  Result const& result,
377  RCLCxLedger const& prevLedger,
378  NetClock::duration const& closeResolution,
379  ConsensusCloseTimes const& rawCloseTimes,
380  ConsensusMode const& mode,
381  Json::Value&& consensusJson)
382 {
383  app_.getJobQueue().addJob(
384  jtACCEPT,
385  "acceptLedger",
386  [=, cj = std::move(consensusJson)](auto&) mutable {
387  // Note that no lock is held or acquired during this job.
388  // This is because generic Consensus guarantees that once a ledger
389  // is accepted, the consensus results and capture by reference state
390  // will not change until startRound is called (which happens via
391  // endConsensus).
392  this->doAccept(
393  result,
394  prevLedger,
395  closeResolution,
396  rawCloseTimes,
397  mode,
398  std::move(cj));
399  this->app_.getOPs().endConsensus();
400  });
401 }
402 
403 void
405  Result const& result,
406  RCLCxLedger const& prevLedger,
407  NetClock::duration closeResolution,
408  ConsensusCloseTimes const& rawCloseTimes,
409  ConsensusMode const& mode,
410  Json::Value&& consensusJson)
411 {
412  prevProposers_ = result.proposers;
413  prevRoundTime_ = result.roundTime.read();
414 
415  bool closeTimeCorrect;
416 
417  const bool proposing = mode == ConsensusMode::proposing;
418  const bool haveCorrectLCL = mode != ConsensusMode::wrongLedger;
419  const bool consensusFail = result.state == ConsensusState::MovedOn;
420 
421  auto consensusCloseTime = result.position.closeTime();
422 
423  if (consensusCloseTime == NetClock::time_point{})
424  {
425  // We agreed to disagree on the close time
426  using namespace std::chrono_literals;
427  consensusCloseTime = prevLedger.closeTime() + 1s;
428  closeTimeCorrect = false;
429  }
430  else
431  {
432  // We agreed on a close time
433  consensusCloseTime = effCloseTime(
434  consensusCloseTime, closeResolution, prevLedger.closeTime());
435  closeTimeCorrect = true;
436  }
437 
438  JLOG(j_.debug()) << "Report: Prop=" << (proposing ? "yes" : "no")
439  << " val=" << (validating_ ? "yes" : "no")
440  << " corLCL=" << (haveCorrectLCL ? "yes" : "no")
441  << " fail=" << (consensusFail ? "yes" : "no");
442  JLOG(j_.debug()) << "Report: Prev = " << prevLedger.id() << ":"
443  << prevLedger.seq();
444 
445  //--------------------------------------------------------------------------
446  std::set<TxID> failed;
447 
448  // We want to put transactions in an unpredictable but deterministic order:
449  // we use the hash of the set.
450  //
451  // FIXME: Use a std::vector and a custom sorter instead of CanonicalTXSet?
452  CanonicalTXSet retriableTxs{result.txns.map_->getHash().as_uint256()};
453 
454  JLOG(j_.debug()) << "Building canonical tx set: " << retriableTxs.key();
455 
456  for (auto const& item : *result.txns.map_)
457  {
458  try
459  {
460  retriableTxs.insert(
461  std::make_shared<STTx const>(SerialIter{item.slice()}));
462  JLOG(j_.debug()) << " Tx: " << item.key();
463  }
464  catch (std::exception const&)
465  {
466  failed.insert(item.key());
467  JLOG(j_.warn()) << " Tx: " << item.key() << " throws!";
468  }
469  }
470 
471  auto built = buildLCL(
472  prevLedger,
473  retriableTxs,
474  consensusCloseTime,
475  closeTimeCorrect,
476  closeResolution,
477  result.roundTime.read(),
478  failed);
479 
480  auto const newLCLHash = built.id();
481  JLOG(j_.debug()) << "Built ledger #" << built.seq() << ": " << newLCLHash;
482 
483  // Tell directly connected peers that we have a new LCL
484  notify(protocol::neACCEPTED_LEDGER, built, haveCorrectLCL);
485 
486  // As long as we're in sync with the network, attempt to detect attempts
487  // at censorship of transaction by tracking which ones don't make it in
488  // after a period of time.
489  if (haveCorrectLCL && result.state == ConsensusState::Yes)
490  {
492 
493  result.txns.map_->visitLeaves(
495  accepted.push_back(item->key());
496  });
497 
498  // Track all the transactions which failed or were marked as retriable
499  for (auto const& r : retriableTxs)
500  failed.insert(r.first.getTXID());
501 
502  censorshipDetector_.check(
503  std::move(accepted),
504  [curr = built.seq(),
505  j = app_.journal("CensorshipDetector"),
506  &failed](uint256 const& id, LedgerIndex seq) {
507  if (failed.count(id))
508  return true;
509 
510  auto const wait = curr - seq;
511 
512  if (wait && (wait % censorshipWarnInternal == 0))
513  {
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 << ".";
518 
519  JLOG(j.warn()) << ss.str();
520  }
521 
522  return false;
523  });
524  }
525 
526  if (validating_)
527  validating_ = ledgerMaster_.isCompatible(
528  *built.ledger_, j_.warn(), "Not validating");
529 
530  if (validating_ && !consensusFail &&
531  app_.getValidations().canValidateSeq(built.seq()))
532  {
533  validate(built, result.txns, proposing);
534  JLOG(j_.info()) << "CNF Val " << newLCLHash;
535  }
536  else
537  JLOG(j_.info()) << "CNF buildLCL " << newLCLHash;
538 
539  // See if we can accept a ledger as fully-validated
540  ledgerMaster_.consensusBuilt(
541  built.ledger_, result.txns.id(), std::move(consensusJson));
542 
543  //-------------------------------------------------------------------------
544  {
545  // Apply disputed transactions that didn't get in
546  //
547  // The first crack of transactions to get into the new
548  // open ledger goes to transactions proposed by a validator
549  // we trust but not included in the consensus set.
550  //
551  // These are done first because they are the most likely
552  // to receive agreement during consensus. They are also
553  // ordered logically "sooner" than transactions not mentioned
554  // in the previous consensus round.
555  //
556  bool anyDisputes = false;
557  for (auto const& [_, dispute] : result.disputes)
558  {
559  (void)_;
560  if (!dispute.getOurVote())
561  {
562  // we voted NO
563  try
564  {
565  JLOG(j_.debug())
566  << "Test applying disputed transaction that did"
567  << " not get in " << dispute.tx().id();
568 
569  SerialIter sit(dispute.tx().tx_.slice());
570  auto txn = std::make_shared<STTx const>(sit);
571 
572  // Disputed pseudo-transactions that were not accepted
573  // can't be successfully applied in the next ledger
574  if (isPseudoTx(*txn))
575  continue;
576 
577  retriableTxs.insert(txn);
578 
579  anyDisputes = true;
580  }
581  catch (std::exception const&)
582  {
583  JLOG(j_.debug())
584  << "Failed to apply transaction we voted NO on";
585  }
586  }
587  }
588 
589  // Build new open ledger
590  std::unique_lock lock{app_.getMasterMutex(), std::defer_lock};
591  std::unique_lock sl{ledgerMaster_.peekMutex(), std::defer_lock};
592  std::lock(lock, sl);
593 
594  auto const lastVal = ledgerMaster_.getValidatedLedger();
595  boost::optional<Rules> rules;
596  if (lastVal)
597  rules.emplace(*lastVal, app_.config().features);
598  else
599  rules.emplace(app_.config().features);
600  app_.openLedger().accept(
601  app_,
602  *rules,
603  built.ledger_,
604  localTxs_.getTxSet(),
605  anyDisputes,
606  retriableTxs,
607  tapNONE,
608  "consensus",
609  [&](OpenView& view, beast::Journal j) {
610  // Stuff the ledger with transactions from the queue.
611  return app_.getTxQ().accept(app_, view);
612  });
613 
614  // Signal a potential fee change to subscribers after the open ledger
615  // is created
616  app_.getOPs().reportFeeChange();
617  }
618 
619  //-------------------------------------------------------------------------
620  {
621  ledgerMaster_.switchLCL(built.ledger_);
622 
623  // Do these need to exist?
624  assert(ledgerMaster_.getClosedLedger()->info().hash == built.id());
625  assert(app_.openLedger().current()->info().parentHash == built.id());
626  }
627 
628  //-------------------------------------------------------------------------
629  // we entered the round with the network,
630  // see how close our close time is to other node's
631  // close time reports, and update our clock.
632  if ((mode == ConsensusMode::proposing ||
634  !consensusFail)
635  {
636  auto closeTime = rawCloseTimes.self;
637 
638  JLOG(j_.info()) << "We closed at "
639  << closeTime.time_since_epoch().count();
640  using usec64_t = std::chrono::duration<std::uint64_t>;
641  usec64_t closeTotal =
642  std::chrono::duration_cast<usec64_t>(closeTime.time_since_epoch());
643  int closeCount = 1;
644 
645  for (auto const& [t, v] : rawCloseTimes.peers)
646  {
647  JLOG(j_.info()) << std::to_string(v) << " time votes for "
648  << std::to_string(t.time_since_epoch().count());
649  closeCount += v;
650  closeTotal +=
651  std::chrono::duration_cast<usec64_t>(t.time_since_epoch()) * v;
652  }
653 
654  closeTotal += usec64_t(closeCount / 2); // for round to nearest
655  closeTotal /= closeCount;
656 
657  // Use signed times since we are subtracting
658  using duration = std::chrono::duration<std::int32_t>;
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 << ")";
664 
665  app_.timeKeeper().adjustCloseTime(offset);
666  }
667 }
668 
669 void
671  protocol::NodeEvent ne,
672  RCLCxLedger const& ledger,
673  bool haveCorrectLCL)
674 {
675  protocol::TMStatusChange s;
676 
677  if (!haveCorrectLCL)
678  s.set_newevent(protocol::neLOST_SYNC);
679  else
680  s.set_newevent(ne);
681 
682  s.set_ledgerseq(ledger.seq());
683  s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
684  s.set_ledgerhashprevious(
685  ledger.parentID().begin(),
686  std::decay_t<decltype(ledger.parentID())>::bytes);
687  s.set_ledgerhash(
688  ledger.id().begin(), std::decay_t<decltype(ledger.id())>::bytes);
689 
690  std::uint32_t uMin, uMax;
691  if (!ledgerMaster_.getFullValidatedRange(uMin, uMax))
692  {
693  uMin = 0;
694  uMax = 0;
695  }
696  else
697  {
698  // Don't advertise ledgers we're not willing to serve
699  uMin = std::max(uMin, ledgerMaster_.getEarliestFetch());
700  }
701  s.set_firstseq(uMin);
702  s.set_lastseq(uMax);
703  app_.overlay().foreach (
704  send_always(std::make_shared<Message>(s, protocol::mtSTATUS_CHANGE)));
705  JLOG(j_.trace()) << "send status change to peer";
706 }
707 
710  RCLCxLedger const& previousLedger,
711  CanonicalTXSet& retriableTxs,
712  NetClock::time_point closeTime,
713  bool closeTimeCorrect,
714  NetClock::duration closeResolution,
715  std::chrono::milliseconds roundTime,
716  std::set<TxID>& failedTxs)
717 {
718  std::shared_ptr<Ledger> built = [&]() {
719  if (auto const replayData = ledgerMaster_.releaseReplay())
720  {
721  assert(replayData->parent()->info().hash == previousLedger.id());
722  return buildLedger(*replayData, tapNONE, app_, j_);
723  }
724  return buildLedger(
725  previousLedger.ledger_,
726  closeTime,
727  closeTimeCorrect,
728  closeResolution,
729  app_,
730  retriableTxs,
731  failedTxs,
732  j_);
733  }();
734 
735  // Update fee computations based on accepted txs
736  using namespace std::chrono_literals;
737  app_.getTxQ().processClosedLedger(app_, *built, roundTime > 5s);
738 
739  // And stash the ledger in the ledger master
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";
744  else
745  JLOG(j_.debug()) << "Consensus built new ledger";
746  return RCLCxLedger{std::move(built)};
747 }
748 
749 void
751  RCLCxLedger const& ledger,
752  RCLTxSet const& txns,
753  bool proposing)
754 {
755  using namespace std::chrono_literals;
756  auto validationTime = app_.timeKeeper().closeTime();
757  if (validationTime <= lastValidationTime_)
758  validationTime = lastValidationTime_ + 1s;
759  lastValidationTime_ = validationTime;
760 
762  std::vector<uint256> amendments;
763 
764  auto const& feeTrack = app_.getFeeTrack();
765  std::uint32_t fee =
766  std::max(feeTrack.getLocalFee(), feeTrack.getClusterFee());
767 
768  if (fee > feeTrack.getLoadBase())
769  fees.loadFee = fee;
770 
771  // next ledger is flag ledger
772  if (((ledger.seq() + 1) % 256) == 0)
773  {
774  // Suggest fee changes and new features
775  feeVote_->doValidation(ledger.ledger_, fees);
776  amendments = app_.getAmendmentTable().doValidation(
777  getEnabledAmendments(*ledger.ledger_));
778  }
779 
780  auto v = std::make_shared<STValidation>(
781  ledger.id(),
782  ledger.seq(),
783  txns.id(),
784  validationTime,
785  valPublic_,
786  valSecret_,
787  nodeID_,
788  proposing /* full if proposed */,
789  fees,
790  amendments);
791 
792  // suppress it if we receive it
793  app_.getHashRouter().addSuppression(
794  sha512Half(makeSlice(v->getSerialized())));
795  handleNewValidation(app_, v, "local");
796  Blob validation = v->getSerialized();
797  protocol::TMValidation val;
798  val.set_validation(&validation[0], validation.size());
799  // Send signed validation to all of our directly connected peers
800  app_.overlay().send(val);
801 }
802 
803 void
805 {
806  JLOG(j_.info()) << "Consensus mode change before=" << to_string(before)
807  << ", after=" << to_string(after);
808 
809  // If we were proposing but aren't any longer, we need to reset the
810  // censorship tracking to avoid bogus warnings.
811  if ((before == ConsensusMode::proposing ||
812  before == ConsensusMode::observing) &&
813  before != after)
814  censorshipDetector_.reset();
815 
816  mode_ = after;
817 }
818 
820 RCLConsensus::getJson(bool full) const
821 {
822  Json::Value ret;
823  {
825  ret = consensus_.getJson(full);
826  }
827  ret["validating"] = adaptor_.validating();
828  return ret;
829 }
830 
831 void
833 {
834  try
835  {
837  consensus_.timerEntry(now);
838  }
839  catch (SHAMapMissingNode const& mn)
840  {
841  // This should never happen
842  JLOG(j_.error()) << "During consensus timerEntry: " << mn.what();
843  Rethrow();
844  }
845 }
846 
847 void
849 {
850  try
851  {
853  consensus_.gotTxSet(now, txSet);
854  }
855  catch (SHAMapMissingNode const& mn)
856  {
857  // This should never happen
858  JLOG(j_.error()) << "During consensus gotTxSet: " << mn.what();
859  Rethrow();
860  }
861 }
862 
864 
865 void
867  NetClock::time_point const& now,
868  boost::optional<std::chrono::milliseconds> consensusDelay)
869 {
871  consensus_.simulate(now, consensusDelay);
872 }
873 
874 bool
876  NetClock::time_point const& now,
877  RCLCxPeerPos const& newProposal)
878 {
880  return consensus_.peerProposal(now, newProposal);
881 }
882 
883 bool
885 {
886  // We have a key, we do not want out of sync validations after a restart
887  // and are not amendment blocked.
888  validating_ = valPublic_.size() != 0 &&
889  prevLgr.seq() >= app_.getMaxDisallowedLedger() &&
890  !app_.getOPs().isAmendmentBlocked();
891 
892  // If we are not running in standalone mode and there's a configured UNL,
893  // check to make sure that it's not expired.
894  if (validating_ && !app_.config().standalone() && app_.validators().count())
895  {
896  auto const when = app_.validators().expires();
897 
898  if (!when || *when < app_.timeKeeper().now())
899  {
900  JLOG(j_.error()) << "Voluntarily bowing out of consensus process "
901  "because of an expired validator list.";
902  validating_ = false;
903  }
904  }
905 
906  const bool synced = app_.getOPs().getOperatingMode() == OperatingMode::FULL;
907 
908  if (validating_)
909  {
910  JLOG(j_.info()) << "Entering consensus process, validating, synced="
911  << (synced ? "yes" : "no");
912  }
913  else
914  {
915  // Otherwise we just want to monitor the validation process.
916  JLOG(j_.info()) << "Entering consensus process, watching, synced="
917  << (synced ? "yes" : "no");
918  }
919 
920  // Notify inbound ledgers that we are starting a new round
921  inboundTransactions_.newRound(prevLgr.seq());
922 
923  // propose only if we're in sync with the network (and validating)
924  return validating_ && synced;
925 }
926 
927 bool
929 {
930  return ledgerMaster_.haveValidated();
931 }
932 
935 {
936  return ledgerMaster_.getValidLedgerIndex();
937 }
938 
941 {
942  return app_.validators().getQuorumKeys();
943 }
944 
947  Ledger_t::Seq const seq,
949 {
950  return app_.getValidations().laggards(seq, trustedKeys);
951 }
952 
953 bool
955 {
956  return !valPublic_.empty();
957 }
958 
959 void
961 {
962  if (!positions && app_.getOPs().isFull())
963  app_.getOPs().setMode(OperatingMode::CONNECTED);
964 }
965 
966 void
968  NetClock::time_point const& now,
969  RCLCxLedger::ID const& prevLgrId,
970  RCLCxLedger const& prevLgr,
971  hash_set<NodeID> const& nowUntrusted)
972 {
974  consensus_.startRound(
975  now, prevLgrId, prevLgr, nowUntrusted, adaptor_.preStartRound(prevLgr));
976 }
977 } // namespace ripple
ripple::Application
Definition: Application.h:94
ripple::RCLCxPeerPos
A peer's signed, proposed position for use in RCLConsensus.
Definition: RCLCxPeerPos.h:42
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
std::lock
T lock(T... args)
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:194
ripple::getEnabledAmendments
std::set< uint256 > getEnabledAmendments(ReadView const &view)
Definition: View.cpp:533
std::string
STL class.
ripple::InboundLedger::Reason::CONSENSUS
@ CONSENSUS
ripple::RCLCxPeerPos::signature
Slice signature() const
Signature of the proposal (not necessarily verified)
Definition: RCLCxPeerPos.h:74
std::shared_ptr
STL class.
ripple::ConsensusMode::proposing
@ proposing
We are normal participant in consensus and propose our position.
ripple::RCLConsensus::getJson
Json::Value getJson(bool full) const
Definition: RCLConsensus.cpp:820
std::exception
STL class.
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::RCLConsensus::consensus_
Consensus< Adaptor > consensus_
Definition: RCLConsensus.h:520
ripple::jtACCEPT
@ jtACCEPT
Definition: Job.h:59
std::unordered_set
STL class.
std::pair
ripple::SHAMapType::TRANSACTION
@ TRANSACTION
ripple::RCLConsensus::mutex_
std::recursive_mutex mutex_
Definition: RCLConsensus.h:517
ripple::LedgerMaster
Definition: LedgerMaster.h:58
ripple::ConsensusMode::wrongLedger
@ wrongLedger
We have the wrong ledger and are attempting to acquire it.
Json::Compact
Decorator for streaming out compact json.
Definition: json_writer.h:316
ripple::RCLConsensus::Adaptor::hasOpenTransactions
bool hasOpenTransactions() const
Whether the open ledger has any transactions.
Definition: RCLConsensus.cpp:231
std::vector< TxIDSeq >
ripple::STValidation::FeeSettings::loadFee
boost::optional< std::uint32_t > loadFee
Definition: STValidation.h:101
ripple::ConsensusState::Yes
@ Yes
We have consensus along with the network.
ripple::RCLConsensus::gotTxSet
void gotTxSet(NetClock::time_point const &now, RCLTxSet const &txSet)
Definition: RCLConsensus.cpp:848
std::chrono::duration
ripple::RCLConsensus::Adaptor::getPrevLedger
uint256 getPrevLedger(uint256 ledgerID, RCLCxLedger const &ledger, ConsensusMode mode)
Get the ID of the previous ledger/last closed ledger(LCL) on the network.
Definition: RCLConsensus.cpp:253
ripple::RCLTxSet::map_
std::shared_ptr< SHAMap > map_
The SHAMap representing the transactions.
Definition: RCLCxTx.h:189
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
std::lock_guard
STL class.
ripple::RCLConsensus::j_
const beast::Journal j_
Definition: RCLConsensus.h:521
ripple::PublicKey::slice
Slice slice() const noexcept
Definition: PublicKey.h:123
ripple::ConsensusResult::roundTime
ConsensusTimer roundTime
Definition: ConsensusTypes.h:233
ripple::RCLConsensus::timerEntry
void timerEntry(NetClock::time_point const &now)
Definition: RCLConsensus.cpp:832
ripple::RCLValidationsAdaptor::journal
beast::Journal journal() const
Definition: RCLValidations.h:219
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::RCLConsensus::Adaptor::onClose
Result onClose(RCLCxLedger const &ledger, NetClock::time_point const &closeTime, ConsensusMode mode)
Close the open ledger and return initial consensus position.
Definition: RCLConsensus.cpp:275
ripple::RCLCxLedger::closeTime
NetClock::time_point closeTime() const
The close time of this ledger.
Definition: RCLCxLedger.h:96
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:31
ripple::RCLValidatedLedger
Wraps a ledger instance for use in generic Validations LedgerTrie.
Definition: RCLValidations.h:147
ripple::ConsensusResult
Encapsulates the result of consensus.
Definition: ConsensusTypes.h:201
algorithm
ripple::handleNewValidation
bool handleNewValidation(Application &app, STValidation::ref val, std::string const &source)
Handle a new validation.
Definition: RCLValidations.cpp:152
ripple::ValidatorKeys
Validator keys and manifest as set in configuration file.
Definition: ValidatorKeys.h:36
ripple::RCLCxLedger::seq
Seq const & seq() const
Sequence number of the ledger.
Definition: RCLCxLedger.h:61
ripple::RCLCxLedger::parentID
ID const & parentID() const
Unique identifier (hash) of this ledger's parent.
Definition: RCLCxLedger.h:75
ripple::CanonicalTXSet
Holds transactions which were deferred to the next pass of consensus.
Definition: CanonicalTXSet.h:36
ripple::send_always
Sends a message to all peers.
Definition: predicates.h:31
ripple::RCLCxPeerPos::proposal
Proposal const & proposal() const
Definition: RCLCxPeerPos.h:94
ripple::RCLConsensus::Adaptor::doAccept
void doAccept(Result const &result, RCLCxLedger const &prevLedger, NetClock::duration closeResolution, ConsensusCloseTimes const &rawCloseTimes, ConsensusMode const &mode, Json::Value &&consensusJson)
Accept a new ledger based on the given transactions.
Definition: RCLConsensus.cpp:404
ripple::RCLConsensus::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)
Constructor.
Definition: RCLConsensus.cpp:48
ripple::SHAMapMissingNode
Definition: SHAMapMissingNode.h:55
ripple::RCLConsensus::Adaptor::onAccept
void onAccept(Result const &result, RCLCxLedger const &prevLedger, NetClock::duration const &closeResolution, ConsensusCloseTimes const &rawCloseTimes, ConsensusMode const &mode, Json::Value &&consensusJson)
Process the accepted ledger.
Definition: RCLConsensus.cpp:375
ripple::ConsensusMode::observing
@ observing
We are observing peer positions, but not proposing our position.
ripple::base_uint< 256 >
ripple::RCLConsensus::Adaptor::updateOperatingMode
void updateOperatingMode(std::size_t const positions) const
Update operating mode based on current peer positions.
Definition: RCLConsensus.cpp:960
ripple::isPseudoTx
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition: STTx.cpp:524
ripple::RCLConsensus::Adaptor::haveValidated
bool haveValidated() const
Definition: RCLConsensus.cpp:928
ripple::Validations::getPreferred
boost::optional< std::pair< Seq, ID > > getPreferred(Ledger const &curr)
Return the sequence number and ID of the preferred working ledger.
Definition: Validations.h:709
ripple::RCLConsensus::Adaptor::laggards
std::size_t laggards(Ledger_t::Seq const seq, hash_set< NodeKey_t > &trustedKeys) const
Definition: RCLConsensus.cpp:946
ripple::RCLConsensus::Adaptor::share
void share(RCLCxPeerPos const &peerPos)
Share the given proposal with all peers.
Definition: RCLConsensus.cpp:127
ripple::OperatingMode::CONNECTED
@ CONNECTED
convinced we are talking to the network
ripple::ConsensusResult::state
ConsensusState state
Definition: ConsensusTypes.h:237
ripple::ConsensusTimer::read
std::chrono::milliseconds read() const
Definition: ConsensusTypes.h:142
ripple::SHAMapItem
Definition: SHAMapItem.h:34
ripple::signDigest
Buffer signDigest(PublicKey const &pk, SecretKey const &sk, uint256 const &digest)
Generate a signature for a message digest.
Definition: SecretKey.cpp:98
ripple::RCLConsensus::peerProposal
bool peerProposal(NetClock::time_point const &now, RCLCxPeerPos const &newProposal)
Definition: RCLConsensus.cpp:875
ripple::Rethrow
void Rethrow()
Rethrow the exception currently being handled.
Definition: contract.h:48
ripple::RCLTxSet
Represents a set of transactions in RCLConsensus.
Definition: RCLCxTx.h:65
ripple::RCLConsensus::Adaptor::validate
void validate(RCLCxLedger const &ledger, RCLTxSet const &txns, bool proposing)
Validate the given ledger and share with peers as necessary.
Definition: RCLConsensus.cpp:750
ripple::Validations::getNodesAfter
std::size_t getNodesAfter(Ledger const &ledger, ID const &ledgerID)
Count the number of current trusted validators working on a ledger after the specified one.
Definition: Validations.h:833
std::unique_lock
STL class.
ripple::RCLTxSet::id
ID id() const
The unique ID/hash of the transaction set.
Definition: RCLCxTx.h:156
std::to_string
T to_string(T... args)
ripple::RCLCxTx::tx_
const SHAMapItem tx_
The SHAMapItem that represents the transaction.
Definition: RCLCxTx.h:57
ripple::RCLConsensus::Adaptor::Adaptor
Adaptor(Application &app, std::unique_ptr< FeeVote > &&feeVote, LedgerMaster &ledgerMaster, LocalTxs &localTxs, InboundTransactions &inboundTransactions, ValidatorKeys const &validatorKeys, beast::Journal journal)
Definition: RCLConsensus.cpp:71
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
std::chrono::time_point
ripple::HashPrefix::proposal
@ proposal
proposal for signing
ripple::RCLCxLedger::id
ID const & id() const
Unique identifier (hash) of this ledger.
Definition: RCLCxLedger.h:68
ripple::RCLConsensus::mode
ConsensusMode mode() const
Definition: RCLConsensus.h:456
ripple::LocalTxs
Definition: LocalTxs.h:33
ripple::Job
Definition: Job.h:82
ripple::SerialIter
Definition: Serializer.h:368
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::HashPrefix::validation
@ validation
validation for signing
ripple::RCLConsensus::Adaptor::acquireLedger
boost::optional< RCLCxLedger > acquireLedger(LedgerHash const &hash)
Attempt to acquire a specific ledger.
Definition: RCLConsensus.cpp:92
std::uint32_t
ripple::RCLConsensus::Adaptor::notify
void notify(protocol::NodeEvent ne, RCLCxLedger const &ledger, bool haveCorrectLCL)
Notify peers of a consensus state change.
Definition: RCLConsensus.cpp:670
ripple::ConsensusState::MovedOn
@ MovedOn
The network has consensus without us.
ripple::RCLConsensus::adaptor_
Adaptor adaptor_
Definition: RCLConsensus.h:519
ripple::SHAMapItem::slice
Slice slice() const
Definition: SHAMapItem.h:63
ripple::RCLConsensus::Adaptor::validator
bool validator() const
Whether I am a validator.
Definition: RCLConsensus.cpp:954
beast::abstract_clock< std::chrono::steady_clock >
ripple::proposalUniqueId
uint256 proposalUniqueId(uint256 const &proposeHash, uint256 const &previousLedger, std::uint32_t proposeSeq, NetClock::time_point closeTime, Slice const &publicKey, Slice const &signature)
Calculate a unique identifier for a signed proposal.
Definition: RCLCxPeerPos.cpp:72
ripple::RCLConsensus::Adaptor::buildLCL
RCLCxLedger buildLCL(RCLCxLedger const &previousLedger, CanonicalTXSet &retriableTxs, NetClock::time_point closeTime, bool closeTimeCorrect, NetClock::duration closeResolution, std::chrono::milliseconds roundTime, std::set< TxID > &failedTxs)
Build the new last closed ledger.
Definition: RCLConsensus.cpp:709
ripple::RCLCxPeerPos::publicKey
PublicKey const & publicKey() const
Public key of peer that sent the proposal.
Definition: RCLCxPeerPos.h:81
std::decay_t
ripple::RCLConsensus::Adaptor::onModeChange
void onModeChange(ConsensusMode before, ConsensusMode after)
Notified of change in consensus mode.
Definition: RCLConsensus.cpp:804
ripple::ManifestDisposition::accepted
@ accepted
Manifest is valid.
ripple::Serializer
Definition: Serializer.h:43
ripple::RCLCxLedger
Represents a ledger in RCLConsensus.
Definition: RCLCxLedger.h:35
ripple::ConsensusProposal::closeTime
NetClock::time_point const & closeTime() const
The current position on the consensus close time.
Definition: ConsensusProposal.h:124
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ConsensusMode
ConsensusMode
Represents how a node currently participates in Consensus.
Definition: ConsensusTypes.h:55
ripple::RCLConsensus::Adaptor::getValidLedgerIndex
LedgerIndex getValidLedgerIndex() const
Definition: RCLConsensus.cpp:934
ripple::base_uint::begin
iterator begin()
Definition: base_uint.h:114
ripple::RCLConsensus::Adaptor::acquireTxSet
boost::optional< RCLTxSet > acquireTxSet(RCLTxSet::ID const &setId)
Acquire the transaction set associated with a proposal.
Definition: RCLConsensus.cpp:221
std
STL namespace.
std::set::insert
T insert(T... args)
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:237
ripple::ConsensusResult::position
Proposal_t position
Our proposed position on transactions/close time.
Definition: ConsensusTypes.h:224
ripple::ConsensusProposal< NodeID, uint256, uint256 >::seqJoin
static const std::uint32_t seqJoin
Definition: ConsensusProposal.h:58
ripple::buildLedger
std::shared_ptr< Ledger > buildLedger(std::shared_ptr< Ledger const > const &parent, NetClock::time_point closeTime, const bool closeTimeCorrect, NetClock::duration closeResolution, Application &app, CanonicalTXSet &txns, std::set< TxID > &failedTxs, beast::Journal j)
Build a new ledger by applying consensus transactions.
Definition: BuildLedger.cpp:172
ripple::RCLConsensus::Adaptor::preStartRound
bool preStartRound(RCLCxLedger const &prevLedger)
Called before kicking off a new consensus round.
Definition: RCLConsensus.cpp:884
ripple::RCLConsensus::Adaptor::proposersValidated
std::size_t proposersValidated(LedgerHash const &h) const
Number of proposers that have validated the given ledger.
Definition: RCLConsensus.cpp:237
ripple::Validations< RCLValidationsAdaptor >
ripple::RCLCxPeerPos::suppressionID
uint256 const & suppressionID() const
Unique id used by hash router to suppress duplicates.
Definition: RCLCxPeerPos.h:88
mutex
ripple::ConsensusResult::txns
TxSet_t txns
The set of transactions consensus agrees go in the ledger.
Definition: ConsensusTypes.h:221
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::after
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition: Escrow.cpp:88
std::size_t
ripple::RCLCxLedger::ledger_
std::shared_ptr< Ledger const > ledger_
The ledger instance.
Definition: RCLCxLedger.h:120
ripple::jtADVANCE
@ jtADVANCE
Definition: Job.h:53
std::max
T max(T... args)
ripple::RCLCxTx
Represents a transaction in RCLConsensus.
Definition: RCLCxTx.h:35
ripple::Validations::adaptor
Adaptor const & adaptor() const
Return the adaptor instance.
Definition: Validations.h:556
ripple::RCLCxTx::id
ID const & id() const
The unique identifier/hash of the transaction.
Definition: RCLCxTx.h:51
std::unique_ptr
STL class.
ripple::RCLConsensus::Adaptor::propose
void propose(RCLCxPeerPos::Proposal const &proposal)
Propose the given position to my peers.
Definition: RCLConsensus.cpp:172
ripple::STValidation::FeeSettings
Fees to set when issuing a new validation.
Definition: STValidation.h:99
ripple::RCLConsensus::Adaptor::proposersFinished
std::size_t proposersFinished(RCLCxLedger const &ledger, LedgerHash const &h) const
Number of proposers that have validated a ledger descended from requested ledger.
Definition: RCLConsensus.cpp:243
ripple::RCLConsensus::Adaptor::onForceAccept
void onForceAccept(Result const &result, RCLCxLedger const &prevLedger, NetClock::duration const &closeResolution, ConsensusCloseTimes const &rawCloseTimes, ConsensusMode const &mode, Json::Value &&consensusJson)
Process the accepted ledger that was a result of simulation/force accept.
Definition: RCLConsensus.cpp:357
std::set
STL class.
ripple::RCLConsensus::Adaptor::getQuorumKeys
std::pair< std::size_t, hash_set< NodeKey_t > > getQuorumKeys() const
Definition: RCLConsensus.cpp:940
ripple::RCLConsensus::Adaptor::validating
bool validating() const
Definition: RCLConsensus.h:105
std::runtime_error::what
T what(T... args)
ripple::effCloseTime
std::chrono::time_point< Clock, Duration > effCloseTime(std::chrono::time_point< Clock, Duration > closeTime, std::chrono::duration< Rep, Period > resolution, std::chrono::time_point< Clock, Duration > priorCloseTime)
Calculate the effective ledger close time.
Definition: LedgerTiming.h:149
ripple::ConsensusCloseTimes
Stores the set of initial close times.
Definition: ConsensusTypes.h:174
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::ConsensusResult::proposers
std::size_t proposers
Definition: ConsensusTypes.h:240
ripple::InboundTransactions
Manages the acquisition and lifetime of transaction sets.
Definition: InboundTransactions.h:36
ripple::RCLConsensus::simulate
void simulate(NetClock::time_point const &now, boost::optional< std::chrono::milliseconds > consensusDelay)
Definition: RCLConsensus.cpp:866
ripple::RCLConsensus::startRound
void startRound(NetClock::time_point const &now, RCLCxLedger::ID const &prevLgrId, RCLCxLedger const &prevLgr, hash_set< NodeID > const &nowUntrusted)
Definition: RCLConsensus.cpp:967
ripple::ConsensusProposal< NodeID, uint256, uint256 >
ripple::OperatingMode::FULL
@ FULL
we have the ledger and can even validate