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(jtADVANCE, "getConsensusLedger",
107  [id = hash, &app = app_](Job&)
108  {
109  app.getInboundLedgers().acquire(id, 0,
111  });
112  }
113  return boost::none;
114  }
115 
116  assert(!built->open() && built->isImmutable());
117  assert(built->info().hash == hash);
118 
119  // Notify inbound transactions of the new ledger sequence number
120  inboundTransactions_.newRound(built->info().seq);
121 
122  return RCLCxLedger(built);
123 }
124 
125 void
127 {
128  protocol::TMProposeSet prop;
129 
130  auto const& proposal = peerPos.proposal();
131 
132  prop.set_proposeseq(proposal.proposeSeq());
133  prop.set_closetime(proposal.closeTime().time_since_epoch().count());
134 
135  prop.set_currenttxhash(
136  proposal.position().begin(), proposal.position().size());
137  prop.set_previousledger(
138  proposal.prevLedger().begin(), proposal.position().size());
139 
140  auto const pk = peerPos.publicKey().slice();
141  prop.set_nodepubkey(pk.data(), pk.size());
142 
143  auto const sig = peerPos.signature();
144  prop.set_signature(sig.data(), sig.size());
145 
146  app_.overlay().relay(prop, peerPos.suppressionID());
147 }
148 
149 void
151 {
152  // If we didn't relay this transaction recently, relay it to all peers
153  if (app_.getHashRouter().shouldRelay(tx.id()))
154  {
155  JLOG(j_.debug()) << "Relaying disputed tx " << tx.id();
156  auto const slice = tx.tx_.slice();
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());
162  app_.overlay().foreach (send_always(
163  std::make_shared<Message>(msg, protocol::mtTRANSACTION)));
164  }
165  else
166  {
167  JLOG(j_.debug()) << "Not relaying disputed tx " << tx.id();
168  }
169 }
170 void
172 {
173  JLOG(j_.trace()) << "We propose: "
174  << (proposal.isBowOut()
175  ? std::string("bowOut")
176  : ripple::to_string(proposal.position()));
177 
178  protocol::TMProposeSet prop;
179 
180  prop.set_currenttxhash(
181  proposal.position().begin(), proposal.position().size());
182  prop.set_previousledger(
183  proposal.prevLedger().begin(), proposal.position().size());
184  prop.set_proposeseq(proposal.proposeSeq());
185  prop.set_closetime(proposal.closeTime().time_since_epoch().count());
186 
187  prop.set_nodepubkey(valPublic_.data(), valPublic_.size());
188 
189  auto signingHash = sha512Half(
191  std::uint32_t(proposal.proposeSeq()),
192  proposal.closeTime().time_since_epoch().count(),
193  proposal.prevLedger(),
194  proposal.position());
195 
196  auto sig = signDigest(valPublic_, valSecret_, signingHash);
197 
198  prop.set_signature(sig.data(), sig.size());
199 
200  auto const suppression = proposalUniqueId(
201  proposal.position(),
202  proposal.prevLedger(),
203  proposal.proposeSeq(),
204  proposal.closeTime(),
205  valPublic_,
206  sig);
207 
208  app_.getHashRouter ().addSuppression (suppression);
209 
210  app_.overlay().send(prop);
211 }
212 
213 void
215 {
216  inboundTransactions_.giveSet(txns.id(), txns.map_, false);
217 }
218 
219 boost::optional<RCLTxSet>
221 {
222  if (auto txns = inboundTransactions_.getSet(setId, true))
223  {
224  return RCLTxSet{std::move(txns)};
225  }
226  return boost::none;
227 }
228 
229 bool
231 {
232  return !app_.openLedger().empty();
233 }
234 
237 {
238  return app_.getValidations().numTrustedForLedger(h);
239 }
240 
243  RCLCxLedger const& ledger,
244  LedgerHash const& h) const
245 {
246  RCLValidations& vals = app_.getValidations();
247  return vals.getNodesAfter(
248  RCLValidatedLedger(ledger.ledger_, vals.adaptor().journal()), h);
249 }
250 
251 uint256
253  uint256 ledgerID,
254  RCLCxLedger const& ledger,
256 {
257  RCLValidations& vals = app_.getValidations();
258  uint256 netLgr = vals.getPreferred(
259  RCLValidatedLedger{ledger.ledger_, vals.adaptor().journal()},
260  ledgerMaster_.getValidLedgerIndex());
261 
262  if (netLgr != ledgerID)
263  {
265  app_.getOPs().consensusViewChange();
266 
267  JLOG(j_.debug())<< Json::Compact(app_.getValidations().getJsonTrie());
268  }
269 
270  return netLgr;
271 }
272 
273 auto
275  RCLCxLedger const& ledger,
276  NetClock::time_point const& closeTime,
278 {
279  const bool wrongLCL = mode == ConsensusMode::wrongLedger;
280  const bool proposing = mode == ConsensusMode::proposing;
281 
282  notify(protocol::neCLOSING_LEDGER, ledger, !wrongLCL);
283 
284  auto const& prevLedger = ledger.ledger_;
285 
286  ledgerMaster_.applyHeldTransactions();
287  // Tell the ledger master not to acquire the ledger we're probably building
288  ledgerMaster_.setBuildingLedger(prevLedger->info().seq + 1);
289 
290  auto initialLedger = app_.openLedger().current();
291 
292  auto initialSet = std::make_shared<SHAMap>(
293  SHAMapType::TRANSACTION, app_.family());
294  initialSet->setUnbacked();
295 
296  // Build SHAMap containing all transactions in our open ledger
297  for (auto const& tx : initialLedger->txs)
298  {
299  JLOG(j_.trace()) << "Adding open ledger TX " <<
300  tx.first->getTransactionID();
301  Serializer s(2048);
302  tx.first->add(s);
303  initialSet->addItem(
304  SHAMapItem(tx.first->getTransactionID(), std::move(s)),
305  true,
306  false);
307  }
308 
309  // Add pseudo-transactions to the set
310  if ((app_.config().standalone() || (proposing && !wrongLCL)) &&
311  ((prevLedger->info().seq % 256) == 0))
312  {
313  // previous ledger was flag ledger, add pseudo-transactions
314  auto const validations =
315  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  {
337  proposed.emplace_back(item->key(), seq);
338  });
339 
340  censorshipDetector_.propose(std::move(proposed));
341  }
342 
343  // Needed because of the move below.
344  auto const setHash = initialSet->getHash().as_uint256();
345 
346  return Result{
347  std::move(initialSet),
349  initialLedger->info().parentHash,
351  setHash,
352  closeTime,
353  app_.timeKeeper().closeTime(),
354  nodeID_}};
355 }
356 
357 void
359  Result const& result,
360  RCLCxLedger const& prevLedger,
361  NetClock::duration const& closeResolution,
362  ConsensusCloseTimes const& rawCloseTimes,
363  ConsensusMode const& mode,
364  Json::Value && consensusJson)
365 {
366  doAccept(
367  result,
368  prevLedger,
369  closeResolution,
370  rawCloseTimes,
371  mode,
372  std::move(consensusJson));
373 }
374 
375 void
377  Result const& result,
378  RCLCxLedger const& prevLedger,
379  NetClock::duration const& closeResolution,
380  ConsensusCloseTimes const& rawCloseTimes,
381  ConsensusMode const& mode,
382  Json::Value && consensusJson)
383 {
384  app_.getJobQueue().addJob(
385  jtACCEPT,
386  "acceptLedger",
387  [=, cj = std::move(consensusJson) ](auto&) mutable {
388  // Note that no lock is held or acquired during this job.
389  // This is because generic Consensus guarantees that once a ledger
390  // is accepted, the consensus results and capture by reference state
391  // will not change until startRound is called (which happens via
392  // endConsensus).
393  this->doAccept(
394  result,
395  prevLedger,
396  closeResolution,
397  rawCloseTimes,
398  mode,
399  std::move(cj));
400  this->app_.getOPs().endConsensus();
401  });
402 }
403 
404 void
406  Result const& result,
407  RCLCxLedger const& prevLedger,
408  NetClock::duration closeResolution,
409  ConsensusCloseTimes const& rawCloseTimes,
410  ConsensusMode const& mode,
411  Json::Value && consensusJson)
412 {
413  prevProposers_ = result.proposers;
414  prevRoundTime_ = result.roundTime.read();
415 
416  bool closeTimeCorrect;
417 
418  const bool proposing = mode == ConsensusMode::proposing;
419  const bool haveCorrectLCL = mode != ConsensusMode::wrongLedger;
420  const bool consensusFail = result.state == ConsensusState::MovedOn;
421 
422  auto consensusCloseTime = result.position.closeTime();
423 
424  if (consensusCloseTime == NetClock::time_point{})
425  {
426  // We agreed to disagree on the close time
427  using namespace std::chrono_literals;
428  consensusCloseTime = prevLedger.closeTime() + 1s;
429  closeTimeCorrect = false;
430  }
431  else
432  {
433  // We agreed on a close time
434  consensusCloseTime = effCloseTime(
435  consensusCloseTime, closeResolution, prevLedger.closeTime());
436  closeTimeCorrect = true;
437  }
438 
439  JLOG(j_.debug()) << "Report: Prop=" << (proposing ? "yes" : "no")
440  << " val=" << (validating_ ? "yes" : "no")
441  << " corLCL=" << (haveCorrectLCL ? "yes" : "no")
442  << " fail=" << (consensusFail ? "yes" : "no");
443  JLOG(j_.debug()) << "Report: Prev = " << prevLedger.id() << ":"
444  << prevLedger.seq();
445 
446  //--------------------------------------------------------------------------
447  std::set<TxID> failed;
448 
449  // We want to put transactions in an unpredictable but deterministic order:
450  // we use the hash of the set.
451  //
452  // FIXME: Use a std::vector and a custom sorter instead of CanonicalTXSet?
453  CanonicalTXSet retriableTxs{ result.txns.map_->getHash().as_uint256() };
454 
455  JLOG(j_.debug()) << "Building canonical tx set: " << retriableTxs.key();
456 
457  for (auto const& item : *result.txns.map_)
458  {
459  try
460  {
461  retriableTxs.insert(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(prevLedger, retriableTxs, consensusCloseTime,
472  closeTimeCorrect, closeResolution, result.roundTime.read(), failed);
473 
474  auto const newLCLHash = built.id();
475  JLOG(j_.debug()) << "Built ledger #" << built.seq() << ": " << newLCLHash;
476 
477  // Tell directly connected peers that we have a new LCL
478  notify(protocol::neACCEPTED_LEDGER, built, haveCorrectLCL);
479 
480  // As long as we're in sync with the network, attempt to detect attempts
481  // at censorship of transaction by tracking which ones don't make it in
482  // after a period of time.
483  if (haveCorrectLCL && result.state == ConsensusState::Yes)
484  {
486 
487  result.txns.map_->visitLeaves (
489  {
490  accepted.push_back(item->key());
491  });
492 
493  // Track all the transactions which failed or were marked as retriable
494  for (auto const& r : retriableTxs)
495  failed.insert (r.first.getTXID());
496 
497  censorshipDetector_.check(std::move(accepted),
498  [curr = built.seq(), j = app_.journal("CensorshipDetector"), &failed]
499  (uint256 const& id, LedgerIndex seq)
500  {
501  if (failed.count(id))
502  return true;
503 
504  auto const wait = curr - seq;
505 
506  if (wait && (wait % censorshipWarnInternal == 0))
507  {
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
512  << ".";
513 
514  JLOG(j.warn()) << ss.str();
515  }
516 
517  return false;
518  });
519  }
520 
521  if (validating_)
522  validating_ = ledgerMaster_.isCompatible(
523  *built.ledger_, j_.warn(), "Not validating");
524 
525  if (validating_ && !consensusFail &&
526  app_.getValidations().canValidateSeq(built.seq()))
527  {
528  validate(built, result.txns, proposing);
529  JLOG(j_.info()) << "CNF Val " << newLCLHash;
530  }
531  else
532  JLOG(j_.info()) << "CNF buildLCL " << newLCLHash;
533 
534  // See if we can accept a ledger as fully-validated
535  ledgerMaster_.consensusBuilt(
536  built.ledger_, result.txns.id(), std::move(consensusJson));
537 
538  //-------------------------------------------------------------------------
539  {
540  // Apply disputed transactions that didn't get in
541  //
542  // The first crack of transactions to get into the new
543  // open ledger goes to transactions proposed by a validator
544  // we trust but not included in the consensus set.
545  //
546  // These are done first because they are the most likely
547  // to receive agreement during consensus. They are also
548  // ordered logically "sooner" than transactions not mentioned
549  // in the previous consensus round.
550  //
551  bool anyDisputes = false;
552  for (auto const& [_, dispute] : result.disputes)
553  {
554  (void)_;
555  if (!dispute.getOurVote())
556  {
557  // we voted NO
558  try
559  {
560  JLOG(j_.debug())
561  << "Test applying disputed transaction that did"
562  << " not get in " << dispute.tx().id();
563 
564  SerialIter sit(dispute.tx().tx_.slice());
565  auto txn = std::make_shared<STTx const>(sit);
566 
567  // Disputed pseudo-transactions that were not accepted
568  // can't be successfully applied in the next ledger
569  if (isPseudoTx(*txn))
570  continue;
571 
572  retriableTxs.insert(txn);
573 
574  anyDisputes = true;
575  }
576  catch (std::exception const&)
577  {
578  JLOG(j_.debug())
579  << "Failed to apply transaction we voted NO on";
580  }
581  }
582  }
583 
584  // Build new open ledger
585  std::unique_lock lock{app_.getMasterMutex(), std::defer_lock};
586  std::unique_lock sl{ledgerMaster_.peekMutex(), std::defer_lock};
587  std::lock(lock, sl);
588 
589  auto const lastVal = ledgerMaster_.getValidatedLedger();
590  boost::optional<Rules> rules;
591  if (lastVal)
592  rules.emplace(*lastVal, app_.config().features);
593  else
594  rules.emplace(app_.config().features);
595  app_.openLedger().accept(
596  app_,
597  *rules,
598  built.ledger_,
599  localTxs_.getTxSet(),
600  anyDisputes,
601  retriableTxs,
602  tapNONE,
603  "consensus",
604  [&](OpenView& view, beast::Journal j) {
605  // Stuff the ledger with transactions from the queue.
606  return app_.getTxQ().accept(app_, view);
607  });
608 
609  // Signal a potential fee change to subscribers after the open ledger
610  // is created
611  app_.getOPs().reportFeeChange();
612  }
613 
614  //-------------------------------------------------------------------------
615  {
616  ledgerMaster_.switchLCL(built.ledger_);
617 
618  // Do these need to exist?
619  assert(ledgerMaster_.getClosedLedger()->info().hash == built.id());
620  assert(
621  app_.openLedger().current()->info().parentHash == built.id());
622  }
623 
624  //-------------------------------------------------------------------------
625  // we entered the round with the network,
626  // see how close our close time is to other node's
627  // close time reports, and update our clock.
628  if ((mode == ConsensusMode::proposing || mode == ConsensusMode::observing) && !consensusFail)
629  {
630  auto closeTime = rawCloseTimes.self;
631 
632  JLOG(j_.info()) << "We closed at "
633  << closeTime.time_since_epoch().count();
634  using usec64_t = std::chrono::duration<std::uint64_t>;
635  usec64_t closeTotal =
636  std::chrono::duration_cast<usec64_t>(closeTime.time_since_epoch());
637  int closeCount = 1;
638 
639  for (auto const& [t, v] : rawCloseTimes.peers)
640  {
641  JLOG(j_.info())
642  << std::to_string(v) << " time votes for "
643  << std::to_string(t.time_since_epoch().count());
644  closeCount += v;
645  closeTotal +=
646  std::chrono::duration_cast<usec64_t>(t.time_since_epoch()) * v;
647  }
648 
649  closeTotal += usec64_t(closeCount / 2); // for round to nearest
650  closeTotal /= closeCount;
651 
652  // Use signed times since we are subtracting
653  using duration = std::chrono::duration<std::int32_t>;
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 << ")";
659 
660  app_.timeKeeper().adjustCloseTime(offset);
661  }
662 }
663 
664 void
666  protocol::NodeEvent ne,
667  RCLCxLedger const& ledger,
668  bool haveCorrectLCL)
669 {
670  protocol::TMStatusChange s;
671 
672  if (!haveCorrectLCL)
673  s.set_newevent(protocol::neLOST_SYNC);
674  else
675  s.set_newevent(ne);
676 
677  s.set_ledgerseq(ledger.seq());
678  s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
679  s.set_ledgerhashprevious(
680  ledger.parentID().begin(),
681  std::decay_t<decltype(ledger.parentID())>::bytes);
682  s.set_ledgerhash(
683  ledger.id().begin(), std::decay_t<decltype(ledger.id())>::bytes);
684 
685  std::uint32_t uMin, uMax;
686  if (!ledgerMaster_.getFullValidatedRange(uMin, uMax))
687  {
688  uMin = 0;
689  uMax = 0;
690  }
691  else
692  {
693  // Don't advertise ledgers we're not willing to serve
694  uMin = std::max(uMin, ledgerMaster_.getEarliestFetch());
695  }
696  s.set_firstseq(uMin);
697  s.set_lastseq(uMax);
698  app_.overlay ().foreach (send_always (
699  std::make_shared <Message> (
700  s, protocol::mtSTATUS_CHANGE)));
701  JLOG (j_.trace()) << "send status change to peer";
702 }
703 
706  RCLCxLedger const& previousLedger,
707  CanonicalTXSet& retriableTxs,
708  NetClock::time_point closeTime,
709  bool closeTimeCorrect,
710  NetClock::duration closeResolution,
711  std::chrono::milliseconds roundTime,
712  std::set<TxID>& failedTxs)
713 {
714  std::shared_ptr<Ledger> built = [&]()
715  {
716  if (auto const replayData = ledgerMaster_.releaseReplay())
717  {
718  assert(replayData->parent()->info().hash == previousLedger.id());
719  return buildLedger(*replayData, tapNONE, app_, j_);
720  }
721  return buildLedger(previousLedger.ledger_, closeTime, closeTimeCorrect,
722  closeResolution, app_, retriableTxs, failedTxs, j_);
723  }();
724 
725  // Update fee computations based on accepted txs
726  using namespace std::chrono_literals;
727  app_.getTxQ().processClosedLedger(app_, *built, roundTime > 5s);
728 
729  // And stash the ledger in the ledger master
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";
734  else
735  JLOG(j_.debug()) << "Consensus built new ledger";
736  return RCLCxLedger{std::move(built)};
737 }
738 
739 void
741  RCLTxSet const& txns,
742  bool proposing)
743 {
744  using namespace std::chrono_literals;
745  auto validationTime = app_.timeKeeper().closeTime();
746  if (validationTime <= lastValidationTime_)
747  validationTime = lastValidationTime_ + 1s;
748  lastValidationTime_ = validationTime;
749 
751  std::vector<uint256> amendments;
752 
753  auto const& feeTrack = app_.getFeeTrack();
754  std::uint32_t fee =
755  std::max(feeTrack.getLocalFee(), feeTrack.getClusterFee());
756 
757  if (fee > feeTrack.getLoadBase())
758  fees.loadFee = fee;
759 
760  // next ledger is flag ledger
761  if (((ledger.seq() + 1) % 256) == 0)
762  {
763  // Suggest fee changes and new features
764  feeVote_->doValidation(ledger.ledger_, fees);
765  amendments = app_.getAmendmentTable().doValidation (getEnabledAmendments(*ledger.ledger_));
766  }
767 
768  auto v = std::make_shared<STValidation>(
769  ledger.id(),
770  ledger.seq(),
771  txns.id(),
772  validationTime,
773  valPublic_,
774  valSecret_,
775  nodeID_,
776  proposing /* full if proposed */,
777  fees,
778  amendments);
779 
780  // suppress it if we receive it
781  app_.getHashRouter().addSuppression(
782  sha512Half(makeSlice(v->getSerialized())));
783  handleNewValidation(app_, v, "local");
784  Blob validation = v->getSerialized();
785  protocol::TMValidation val;
786  val.set_validation(&validation[0], validation.size());
787  // Send signed validation to all of our directly connected peers
788  app_.overlay().send(val);
789 }
790 
791 void
793  ConsensusMode before,
795 {
796  JLOG(j_.info()) << "Consensus mode change before=" << to_string(before)
797  << ", after=" << to_string(after);
798 
799  // If we were proposing but aren't any longer, we need to reset the
800  // censorship tracking to avoid bogus warnings.
801  if ((before == ConsensusMode::proposing || before == ConsensusMode::observing) && before != after)
802  censorshipDetector_.reset();
803 
804  mode_ = after;
805 }
806 
808 RCLConsensus::getJson(bool full) const
809 {
810  Json::Value ret;
811  {
813  ret = consensus_.getJson(full);
814  }
815  ret["validating"] = adaptor_.validating();
816  return ret;
817 }
818 
819 void
821 {
822  try
823  {
825  consensus_.timerEntry(now);
826  }
827  catch (SHAMapMissingNode const& mn)
828  {
829  // This should never happen
830  JLOG(j_.error()) << "During consensus timerEntry: " << mn.what();
831  Rethrow();
832  }
833 }
834 
835 void
837 {
838  try
839  {
841  consensus_.gotTxSet(now, txSet);
842  }
843  catch (SHAMapMissingNode const& mn)
844  {
845  // This should never happen
846  JLOG(j_.error()) << "During consensus gotTxSet: " << mn.what();
847  Rethrow();
848  }
849 }
850 
851 
853 
854 void
856  NetClock::time_point const& now,
857  boost::optional<std::chrono::milliseconds> consensusDelay)
858 {
860  consensus_.simulate(now, consensusDelay);
861 }
862 
863 bool
865  NetClock::time_point const& now,
866  RCLCxPeerPos const& newProposal)
867 {
869  return consensus_.peerProposal(now, newProposal);
870 }
871 
872 bool
874 {
875  // We have a key, we do not want out of sync validations after a restart
876  // and are not amendment blocked.
877  validating_ = valPublic_.size() != 0 &&
878  prevLgr.seq() >= app_.getMaxDisallowedLedger() &&
879  !app_.getOPs().isAmendmentBlocked();
880 
881  // If we are not running in standalone mode and there's a configured UNL,
882  // check to make sure that it's not expired.
883  if (validating_ && !app_.config().standalone() && app_.validators().count())
884  {
885  auto const when = app_.validators().expires();
886 
887  if (!when || *when < app_.timeKeeper().now())
888  {
889  JLOG(j_.error()) << "Voluntarily bowing out of consensus process "
890  "because of an expired validator list.";
891  validating_ = false;
892  }
893  }
894 
895  const bool synced = app_.getOPs().getOperatingMode() ==
897 
898  if (validating_)
899  {
900  JLOG(j_.info()) << "Entering consensus process, validating, synced="
901  << (synced ? "yes" : "no");
902  }
903  else
904  {
905  // Otherwise we just want to monitor the validation process.
906  JLOG(j_.info()) << "Entering consensus process, watching, synced="
907  << (synced ? "yes" : "no");
908  }
909 
910  // Notify inbound ledgers that we are starting a new round
911  inboundTransactions_.newRound(prevLgr.seq());
912 
913  // propose only if we're in sync with the network (and validating)
914  return validating_ && synced;
915 }
916 
917 bool
919 {
920  return ledgerMaster_.haveValidated();
921 }
922 
925 {
926  return ledgerMaster_.getValidLedgerIndex();
927 }
928 
931 {
932  return app_.validators().getQuorumKeys();
933 }
934 
938 {
939  return app_.getValidations().laggards(seq, trustedKeys);
940 }
941 
942 bool
944 {
945  return !valPublic_.empty();
946 }
947 
948 void
950 {
951  if (! positions && app_.getOPs().isFull())
952  app_.getOPs().setMode(OperatingMode::CONNECTED);
953 }
954 
955 void
957  NetClock::time_point const& now,
958  RCLCxLedger::ID const& prevLgrId,
959  RCLCxLedger const& prevLgr,
960  hash_set<NodeID> const& nowUntrusted)
961 {
963  consensus_.startRound(
964  now, prevLgrId, prevLgr, nowUntrusted, adaptor_.preStartRound(prevLgr));
965 }
966 }
ripple::Application
Definition: Application.h:85
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
ripple::RCLCxPeerPos::proposal
const Proposal & proposal() const
Definition: RCLCxPeerPos.h:94
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:199
ripple::getEnabledAmendments
std::set< uint256 > getEnabledAmendments(ReadView const &view)
Definition: View.cpp:513
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:808
std::exception
STL class.
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:287
ripple::RCLConsensus::consensus_
Consensus< Adaptor > consensus_
Definition: RCLConsensus.h:517
ripple::jtACCEPT
@ jtACCEPT
Definition: Job.h:60
std::unordered_set
STL class.
std::pair
ripple::SHAMapType::TRANSACTION
@ TRANSACTION
ripple::RCLConsensus::mutex_
std::recursive_mutex mutex_
Definition: RCLConsensus.h:514
ripple::LedgerMaster
Definition: LedgerMaster.h:60
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:277
ripple::RCLConsensus::Adaptor::hasOpenTransactions
bool hasOpenTransactions() const
Whether the open ledger has any transactions.
Definition: RCLConsensus.cpp:230
std::vector< TxIDSeq >
ripple::STValidation::FeeSettings::loadFee
boost::optional< std::uint32_t > loadFee
Definition: STValidation.h:103
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:836
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:252
ripple::RCLTxSet::map_
std::shared_ptr< SHAMap > map_
The SHAMap representing the transactions.
Definition: RCLCxTx.h:191
beast::Journal::warn
Stream warn() const
Definition: Journal.h:302
std::lock_guard
STL class.
ripple::RCLConsensus::j_
const beast::Journal j_
Definition: RCLConsensus.h:518
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:820
ripple::RCLValidationsAdaptor::journal
beast::Journal journal() const
Definition: RCLValidations.h:218
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:274
ripple::RCLCxLedger::closeTime
NetClock::time_point closeTime() const
The close time of this ledger.
Definition: RCLCxLedger.h:96
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:33
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:151
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::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:405
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:56
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:376
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:949
ripple::isPseudoTx
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition: STTx.cpp:525
ripple::RCLConsensus::Adaptor::haveValidated
bool haveValidated() const
Definition: RCLConsensus.cpp:918
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:698
ripple::RCLConsensus::Adaptor::laggards
std::size_t laggards(Ledger_t::Seq const seq, hash_set< NodeKey_t > &trustedKeys) const
Definition: RCLConsensus.cpp:936
ripple::RCLConsensus::Adaptor::share
void share(RCLCxPeerPos const &peerPos)
Share the given proposal with all peers.
Definition: RCLConsensus.cpp:126
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:100
ripple::RCLConsensus::peerProposal
bool peerProposal(NetClock::time_point const &now, RCLCxPeerPos const &newProposal)
Definition: RCLConsensus.cpp:864
ripple::Rethrow
void Rethrow()
Rethrow the exception currently being handled.
Definition: contract.h:50
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:740
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:822
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:307
beast::Journal::info
Stream info() const
Definition: Journal.h:297
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:453
ripple::LocalTxs
Definition: LocalTxs.h:33
ripple::Job
Definition: Job.h:83
ripple::SerialIter
Definition: Serializer.h:311
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
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:665
ripple::ConsensusState::MovedOn
@ MovedOn
The network has consensus without us.
ripple::RCLConsensus::adaptor_
Adaptor adaptor_
Definition: RCLConsensus.h:516
ripple::SHAMapItem::slice
Slice slice() const
Definition: SHAMapItem.h:59
ripple::RCLConsensus::Adaptor::validator
bool validator() const
Whether I am a validator.
Definition: RCLConsensus.cpp:943
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:74
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:705
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:792
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:924
ripple::base_uint::begin
iterator begin()
Definition: base_uint.h:106
ripple::RCLConsensus::Adaptor::acquireTxSet
boost::optional< RCLTxSet > acquireTxSet(RCLTxSet::ID const &setId)
Acquire the transaction set associated with a proposal.
Definition: RCLConsensus.cpp:220
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:268
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:174
ripple::RCLConsensus::Adaptor::preStartRound
bool preStartRound(RCLCxLedger const &prevLedger)
Called before kicking off a new consensus round.
Definition: RCLConsensus.cpp:873
ripple::RCLConsensus::Adaptor::proposersValidated
std::size_t proposersValidated(LedgerHash const &h) const
Number of proposers that have validated the given ledger.
Definition: RCLConsensus.cpp:236
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:292
ripple::after
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition: Escrow.cpp:87
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:54
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:545
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:171
ripple::STValidation::FeeSettings
Fees to set when issuing a new validation.
Definition: STValidation.h:101
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:242
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:358
std::set
STL class.
ripple::RCLConsensus::Adaptor::getQuorumKeys
std::pair< std::size_t, hash_set< NodeKey_t > > getQuorumKeys() const
Definition: RCLConsensus.cpp:930
ripple::RCLConsensus::Adaptor::validating
bool validating() const
Definition: RCLConsensus.h:104
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:151
ripple::ConsensusCloseTimes
Stores the set of initial close times.
Definition: ConsensusTypes.h:174
Json::Value
Represents a JSON value.
Definition: json_value.h:141
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:855
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:956
ripple::ConsensusProposal< NodeID, uint256, uint256 >
ripple::OperatingMode::FULL
@ FULL
we have the ledger and can even validate