rippled
InboundLedger.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/ledger/AccountStateSF.h>
21 #include <ripple/app/ledger/InboundLedger.h>
22 #include <ripple/app/ledger/InboundLedgers.h>
23 #include <ripple/app/ledger/LedgerMaster.h>
24 #include <ripple/app/ledger/TransactionStateSF.h>
25 #include <ripple/app/main/Application.h>
26 #include <ripple/app/misc/NetworkOPs.h>
27 #include <ripple/basics/Log.h>
28 #include <ripple/core/JobQueue.h>
29 #include <ripple/nodestore/DatabaseShard.h>
30 #include <ripple/overlay/Overlay.h>
31 #include <ripple/protocol/HashPrefix.h>
32 #include <ripple/protocol/jss.h>
33 #include <ripple/resource/Fees.h>
34 #include <ripple/shamap/SHAMapNodeID.h>
35 
36 #include <boost/iterator/function_output_iterator.hpp>
37 
38 #include <algorithm>
39 #include <random>
40 
41 namespace ripple {
42 
43 using namespace std::chrono_literals;
44 
45 enum {
46  // Number of peers to start with
48 
49  // Number of peers to add on a timeout
50  ,
52 
53  // how many timeouts before we give up
54  ,
56 
57  // how many timeouts before we get aggressive
58  ,
60 
61  // Number of nodes to find initially
62  ,
64 
65  // Number of nodes to request for a reply
66  ,
68 
69  // Number of nodes to request blindly
70  ,
71  reqNodes = 12
72 };
73 
74 // millisecond for each ledger timeout
75 auto constexpr ledgerAcquireTimeout = 3000ms;
76 
78  Application& app,
79  uint256 const& hash,
80  std::uint32_t seq,
81  Reason reason,
82  clock_type& clock,
85  app,
86  hash,
88  {jtLEDGER_DATA, "InboundLedger", 5},
89  app.journal("InboundLedger"))
90  , m_clock(clock)
91  , mHaveHeader(false)
92  , mHaveState(false)
93  , mHaveTransactions(false)
94  , mSignaled(false)
95  , mByHash(true)
96  , mSeq(seq)
97  , mReason(reason)
98  , mReceiveDispatched(false)
99  , mPeerSet(std::move(peerSet))
100 {
101  JLOG(journal_.trace()) << "Acquiring ledger " << hash_;
102  touch();
103 }
104 
105 void
107 {
108  ScopedLockType sl(mtx_);
109  collectionLock.unlock();
110 
111  tryDB(app_.getNodeFamily().db());
112  if (failed_)
113  return;
114 
115  if (!complete_)
116  {
117  auto shardStore = app_.getShardStore();
118  if (mReason == Reason::SHARD)
119  {
120  if (!shardStore)
121  {
122  JLOG(journal_.error())
123  << "Acquiring shard with no shard store available";
124  failed_ = true;
125  return;
126  }
127 
128  mHaveHeader = false;
129  mHaveTransactions = false;
130  mHaveState = false;
131  mLedger.reset();
132 
133  tryDB(app_.getShardFamily()->db());
134  if (failed_)
135  return;
136  }
137  else if (shardStore && mSeq >= shardStore->earliestLedgerSeq())
138  {
139  if (auto l = shardStore->fetchLedger(hash_, mSeq))
140  {
141  mHaveHeader = true;
142  mHaveTransactions = true;
143  mHaveState = true;
144  complete_ = true;
145  mLedger = std::move(l);
146  }
147  }
148  }
149  if (!complete_)
150  {
151  addPeers();
152  queueJob(sl);
153  return;
154  }
155 
156  JLOG(journal_.debug()) << "Acquiring ledger we already have in "
157  << " local store. " << hash_;
158  assert(
159  mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
160  mLedger->read(keylet::fees()));
161  mLedger->setImmutable();
162 
164  return;
165 
167 
168  // Check if this could be a newer fully-validated ledger
169  if (mReason == Reason::CONSENSUS)
171 }
172 
175 {
176  auto const& peerIds = mPeerSet->getPeerIds();
177  return std::count_if(peerIds.begin(), peerIds.end(), [this](auto id) {
178  return (app_.overlay().findPeerByShortID(id) != nullptr);
179  });
180 }
181 
182 void
184 {
185  ScopedLockType sl(mtx_);
186 
187  // If we didn't know the sequence number, but now do, save it
188  if ((seq != 0) && (mSeq == 0))
189  mSeq = seq;
190 
191  // Prevent this from being swept
192  touch();
193 }
194 
195 bool
197 {
198  ScopedLockType sl(mtx_);
199  if (!isDone())
200  {
201  if (mLedger)
202  tryDB(mLedger->stateMap().family().db());
203  else if (mReason == Reason::SHARD)
204  tryDB(app_.getShardFamily()->db());
205  else
206  tryDB(app_.getNodeFamily().db());
207  if (failed_ || complete_)
208  {
209  done();
210  return true;
211  }
212  }
213  return false;
214 }
215 
217 {
218  // Save any received AS data not processed. It could be useful
219  // for populating a different ledger
220  for (auto& entry : mReceivedData)
221  {
222  if (entry.second->type() == protocol::liAS_NODE)
223  app_.getInboundLedgers().gotStaleData(entry.second);
224  }
225  if (!isDone())
226  {
227  JLOG(journal_.debug())
228  << "Acquire " << hash_ << " abort "
229  << ((timeouts_ == 0) ? std::string()
230  : (std::string("timeouts:") +
231  std::to_string(timeouts_) + " "))
232  << mStats.get();
233  }
234 }
235 
238  uint256 const& root,
239  SHAMap& map,
240  int max,
241  SHAMapSyncFilter* filter)
242 {
244 
245  if (!root.isZero())
246  {
247  if (map.getHash().isZero())
248  ret.push_back(root);
249  else
250  {
251  auto mn = map.getMissingNodes(max, filter);
252  ret.reserve(mn.size());
253  for (auto const& n : mn)
254  ret.push_back(n.second);
255  }
256  }
257 
258  return ret;
259 }
260 
263 {
264  return neededHashes(mLedger->info().txHash, mLedger->txMap(), max, filter);
265 }
266 
269 {
270  return neededHashes(
271  mLedger->info().accountHash, mLedger->stateMap(), max, filter);
272 }
273 
275 deserializeHeader(Slice data, bool hasHash)
276 {
277  SerialIter sit(data.data(), data.size());
278 
279  LedgerInfo info;
280 
281  info.seq = sit.get32();
282  info.drops = sit.get64();
283  info.parentHash = sit.get256();
284  info.txHash = sit.get256();
285  info.accountHash = sit.get256();
286  info.parentCloseTime =
290  info.closeFlags = sit.get8();
291 
292  if (hasHash)
293  info.hash = sit.get256();
294 
295  return info;
296 }
297 
298 LedgerInfo
299 deserializePrefixedHeader(Slice data, bool hasHash)
300 {
301  return deserializeHeader(data + 4, hasHash);
302 }
303 
304 // See how much of the ledger data is stored locally
305 // Data found in a fetch pack will be stored
306 void
308 {
309  if (!mHaveHeader)
310  {
311  auto makeLedger = [&, this](Blob const& data) {
312  JLOG(journal_.trace()) << "Ledger header found in fetch pack";
313  mLedger = std::make_shared<Ledger>(
315  app_.config(),
317  : app_.getNodeFamily());
318  if (mLedger->info().hash != hash_ ||
319  (mSeq != 0 && mSeq != mLedger->info().seq))
320  {
321  // We know for a fact the ledger can never be acquired
322  JLOG(journal_.warn())
323  << "hash " << hash_ << " seq " << std::to_string(mSeq)
324  << " cannot be a ledger";
325  mLedger.reset();
326  failed_ = true;
327  }
328  };
329 
330  // Try to fetch the ledger header from the DB
331  if (auto nodeObject = srcDB.fetchNodeObject(hash_, mSeq))
332  {
333  JLOG(journal_.trace()) << "Ledger header found in local store";
334 
335  makeLedger(nodeObject->getData());
336  if (failed_)
337  return;
338 
339  // Store the ledger header if the source and destination differ
340  auto& dstDB{mLedger->stateMap().family().db()};
341  if (std::addressof(dstDB) != std::addressof(srcDB))
342  {
343  Blob blob{nodeObject->getData()};
344  dstDB.store(
345  hotLEDGER, std::move(blob), hash_, mLedger->info().seq);
346  }
347  }
348  else
349  {
350  // Try to fetch the ledger header from a fetch pack
351  auto data = app_.getLedgerMaster().getFetchPack(hash_);
352  if (!data)
353  return;
354 
355  JLOG(journal_.trace()) << "Ledger header found in fetch pack";
356 
357  makeLedger(*data);
358  if (failed_)
359  return;
360 
361  // Store the ledger header in the ledger's database
362  mLedger->stateMap().family().db().store(
363  hotLEDGER, std::move(*data), hash_, mLedger->info().seq);
364  }
365 
366  if (mSeq == 0)
367  mSeq = mLedger->info().seq;
368  mLedger->stateMap().setLedgerSeq(mSeq);
369  mLedger->txMap().setLedgerSeq(mSeq);
370  mHaveHeader = true;
371  }
372 
373  if (!mHaveTransactions)
374  {
375  if (mLedger->info().txHash.isZero())
376  {
377  JLOG(journal_.trace()) << "No TXNs to fetch";
378  mHaveTransactions = true;
379  }
380  else
381  {
382  TransactionStateSF filter(
383  mLedger->txMap().family().db(), app_.getLedgerMaster());
384  if (mLedger->txMap().fetchRoot(
385  SHAMapHash{mLedger->info().txHash}, &filter))
386  {
387  if (neededTxHashes(1, &filter).empty())
388  {
389  JLOG(journal_.trace()) << "Had full txn map locally";
390  mHaveTransactions = true;
391  }
392  }
393  }
394  }
395 
396  if (!mHaveState)
397  {
398  if (mLedger->info().accountHash.isZero())
399  {
400  JLOG(journal_.fatal())
401  << "We are acquiring a ledger with a zero account hash";
402  failed_ = true;
403  return;
404  }
405  AccountStateSF filter(
406  mLedger->stateMap().family().db(), app_.getLedgerMaster());
407  if (mLedger->stateMap().fetchRoot(
408  SHAMapHash{mLedger->info().accountHash}, &filter))
409  {
410  if (neededStateHashes(1, &filter).empty())
411  {
412  JLOG(journal_.trace()) << "Had full AS map locally";
413  mHaveState = true;
414  }
415  }
416  }
417 
419  {
420  JLOG(journal_.debug()) << "Had everything locally";
421  complete_ = true;
422  assert(
423  mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
424  mLedger->read(keylet::fees()));
425  mLedger->setImmutable();
426  }
427 }
428 
431 void
433 {
434  mRecentNodes.clear();
435 
436  if (isDone())
437  {
438  JLOG(journal_.info()) << "Already done " << hash_;
439  return;
440  }
441 
443  {
444  if (mSeq != 0)
445  {
446  JLOG(journal_.warn())
447  << timeouts_ << " timeouts for ledger " << mSeq;
448  }
449  else
450  {
451  JLOG(journal_.warn())
452  << timeouts_ << " timeouts for ledger " << hash_;
453  }
454  failed_ = true;
455  done();
456  return;
457  }
458 
459  if (!wasProgress)
460  {
461  checkLocal();
462 
463  mByHash = true;
464 
465  std::size_t pc = getPeerCount();
466  JLOG(journal_.debug())
467  << "No progress(" << pc << ") for ledger " << hash_;
468 
469  // addPeers triggers if the reason is not HISTORY
470  // So if the reason IS HISTORY, need to trigger after we add
471  // otherwise, we need to trigger before we add
472  // so each peer gets triggered once
473  if (mReason != Reason::HISTORY)
475  addPeers();
476  if (mReason == Reason::HISTORY)
478  }
479 }
480 
482 void
484 {
485  mPeerSet->addPeers(
487  [this](auto peer) { return peer->hasLedger(hash_, mSeq); },
488  [this](auto peer) {
489  // For historical nodes, do not trigger too soon
490  // since a fetch pack is probably coming
491  if (mReason != Reason::HISTORY)
493  });
494 }
495 
498 {
499  return shared_from_this();
500 }
501 
502 void
504 {
505  if (mSignaled)
506  return;
507 
508  mSignaled = true;
509  touch();
510 
511  JLOG(journal_.debug()) << "Acquire " << hash_ << (failed_ ? " fail " : " ")
512  << ((timeouts_ == 0)
513  ? std::string()
514  : (std::string("timeouts:") +
515  std::to_string(timeouts_) + " "))
516  << mStats.get();
517 
518  assert(complete_ || failed_);
519 
520  if (complete_ && !failed_ && mLedger)
521  {
522  assert(
523  mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES ||
524  mLedger->read(keylet::fees()));
525  mLedger->setImmutable();
526  switch (mReason)
527  {
528  case Reason::SHARD:
530  [[fallthrough]];
531  case Reason::HISTORY:
533  break;
534  default:
536  break;
537  }
538  }
539 
540  // We hold the PeerSet lock, so must dispatch
542  jtLEDGER_DATA, "AcquisitionDone", [self = shared_from_this()]() {
543  if (self->complete_ && !self->failed_)
544  {
545  self->app_.getLedgerMaster().checkAccept(self->getLedger());
546  self->app_.getLedgerMaster().tryAdvance();
547  }
548  else
549  self->app_.getInboundLedgers().logFailure(
550  self->hash_, self->mSeq);
551  });
552 }
553 
556 void
558 {
559  ScopedLockType sl(mtx_);
560 
561  if (isDone())
562  {
563  JLOG(journal_.debug())
564  << "Trigger on ledger: " << hash_ << (complete_ ? " completed" : "")
565  << (failed_ ? " failed" : "");
566  return;
567  }
568 
569  if (auto stream = journal_.trace())
570  {
571  if (peer)
572  stream << "Trigger acquiring ledger " << hash_ << " from " << peer;
573  else
574  stream << "Trigger acquiring ledger " << hash_;
575 
576  if (complete_ || failed_)
577  stream << "complete=" << complete_ << " failed=" << failed_;
578  else
579  stream << "header=" << mHaveHeader << " tx=" << mHaveTransactions
580  << " as=" << mHaveState;
581  }
582 
583  if (!mHaveHeader)
584  {
585  tryDB(
587  : app_.getNodeFamily().db());
588  if (failed_)
589  {
590  JLOG(journal_.warn()) << " failed local for " << hash_;
591  return;
592  }
593  }
594 
595  protocol::TMGetLedger tmGL;
596  tmGL.set_ledgerhash(hash_.begin(), hash_.size());
597 
598  if (timeouts_ != 0)
599  {
600  // Be more aggressive if we've timed out at least once
601  tmGL.set_querytype(protocol::qtINDIRECT);
602 
603  if (!progress_ && !failed_ && mByHash &&
605  {
606  auto need = getNeededHashes();
607 
608  if (!need.empty())
609  {
610  protocol::TMGetObjectByHash tmBH;
611  bool typeSet = false;
612  tmBH.set_query(true);
613  tmBH.set_ledgerhash(hash_.begin(), hash_.size());
614  for (auto const& p : need)
615  {
616  JLOG(journal_.debug()) << "Want: " << p.second;
617 
618  if (!typeSet)
619  {
620  tmBH.set_type(p.first);
621  typeSet = true;
622  }
623 
624  if (p.first == tmBH.type())
625  {
626  protocol::TMIndexedObject* io = tmBH.add_objects();
627  io->set_hash(p.second.begin(), p.second.size());
628  if (mSeq != 0)
629  io->set_ledgerseq(mSeq);
630  }
631  }
632 
633  auto packet =
634  std::make_shared<Message>(tmBH, protocol::mtGET_OBJECTS);
635  auto const& peerIds = mPeerSet->getPeerIds();
637  peerIds.begin(), peerIds.end(), [this, &packet](auto id) {
638  if (auto p = app_.overlay().findPeerByShortID(id))
639  {
640  mByHash = false;
641  p->send(packet);
642  }
643  });
644  }
645  else
646  {
647  JLOG(journal_.info())
648  << "getNeededHashes says acquire is complete";
649  mHaveHeader = true;
650  mHaveTransactions = true;
651  mHaveState = true;
652  complete_ = true;
653  }
654  }
655  }
656 
657  // We can't do much without the header data because we don't know the
658  // state or transaction root hashes.
659  if (!mHaveHeader && !failed_)
660  {
661  tmGL.set_itype(protocol::liBASE);
662  if (mSeq != 0)
663  tmGL.set_ledgerseq(mSeq);
664  JLOG(journal_.trace()) << "Sending header request to "
665  << (peer ? "selected peer" : "all peers");
666  mPeerSet->sendRequest(tmGL, peer);
667  return;
668  }
669 
670  if (mLedger)
671  tmGL.set_ledgerseq(mLedger->info().seq);
672 
673  if (reason != TriggerReason::reply)
674  {
675  // If we're querying blind, don't query deep
676  tmGL.set_querydepth(0);
677  }
678  else if (peer && peer->isHighLatency())
679  {
680  // If the peer has high latency, query extra deep
681  tmGL.set_querydepth(2);
682  }
683  else
684  tmGL.set_querydepth(1);
685 
686  // Get the state data first because it's the most likely to be useful
687  // if we wind up abandoning this fetch.
688  if (mHaveHeader && !mHaveState && !failed_)
689  {
690  assert(mLedger);
691 
692  if (!mLedger->stateMap().isValid())
693  {
694  failed_ = true;
695  }
696  else if (mLedger->stateMap().getHash().isZero())
697  {
698  // we need the root node
699  tmGL.set_itype(protocol::liAS_NODE);
700  *tmGL.add_nodeids() = SHAMapNodeID().getRawString();
701  JLOG(journal_.trace()) << "Sending AS root request to "
702  << (peer ? "selected peer" : "all peers");
703  mPeerSet->sendRequest(tmGL, peer);
704  return;
705  }
706  else
707  {
708  AccountStateSF filter(
709  mLedger->stateMap().family().db(), app_.getLedgerMaster());
710 
711  // Release the lock while we process the large state map
712  sl.unlock();
713  auto nodes =
714  mLedger->stateMap().getMissingNodes(missingNodesFind, &filter);
715  sl.lock();
716 
717  // Make sure nothing happened while we released the lock
718  if (!failed_ && !complete_ && !mHaveState)
719  {
720  if (nodes.empty())
721  {
722  if (!mLedger->stateMap().isValid())
723  failed_ = true;
724  else
725  {
726  mHaveState = true;
727 
728  if (mHaveTransactions)
729  complete_ = true;
730  }
731  }
732  else
733  {
734  filterNodes(nodes, reason);
735 
736  if (!nodes.empty())
737  {
738  tmGL.set_itype(protocol::liAS_NODE);
739  for (auto const& id : nodes)
740  {
741  *(tmGL.add_nodeids()) = id.first.getRawString();
742  }
743 
744  JLOG(journal_.trace())
745  << "Sending AS node request (" << nodes.size()
746  << ") to "
747  << (peer ? "selected peer" : "all peers");
748  mPeerSet->sendRequest(tmGL, peer);
749  return;
750  }
751  else
752  {
753  JLOG(journal_.trace()) << "All AS nodes filtered";
754  }
755  }
756  }
757  }
758  }
759 
760  if (mHaveHeader && !mHaveTransactions && !failed_)
761  {
762  assert(mLedger);
763 
764  if (!mLedger->txMap().isValid())
765  {
766  failed_ = true;
767  }
768  else if (mLedger->txMap().getHash().isZero())
769  {
770  // we need the root node
771  tmGL.set_itype(protocol::liTX_NODE);
772  *(tmGL.add_nodeids()) = SHAMapNodeID().getRawString();
773  JLOG(journal_.trace()) << "Sending TX root request to "
774  << (peer ? "selected peer" : "all peers");
775  mPeerSet->sendRequest(tmGL, peer);
776  return;
777  }
778  else
779  {
780  TransactionStateSF filter(
781  mLedger->txMap().family().db(), app_.getLedgerMaster());
782 
783  auto nodes =
784  mLedger->txMap().getMissingNodes(missingNodesFind, &filter);
785 
786  if (nodes.empty())
787  {
788  if (!mLedger->txMap().isValid())
789  failed_ = true;
790  else
791  {
792  mHaveTransactions = true;
793 
794  if (mHaveState)
795  complete_ = true;
796  }
797  }
798  else
799  {
800  filterNodes(nodes, reason);
801 
802  if (!nodes.empty())
803  {
804  tmGL.set_itype(protocol::liTX_NODE);
805  for (auto const& n : nodes)
806  {
807  *(tmGL.add_nodeids()) = n.first.getRawString();
808  }
809  JLOG(journal_.trace())
810  << "Sending TX node request (" << nodes.size()
811  << ") to " << (peer ? "selected peer" : "all peers");
812  mPeerSet->sendRequest(tmGL, peer);
813  return;
814  }
815  else
816  {
817  JLOG(journal_.trace()) << "All TX nodes filtered";
818  }
819  }
820  }
821  }
822 
823  if (complete_ || failed_)
824  {
825  JLOG(journal_.debug())
826  << "Done:" << (complete_ ? " complete" : "")
827  << (failed_ ? " failed " : " ") << mLedger->info().seq;
828  sl.unlock();
829  done();
830  }
831 }
832 
833 void
834 InboundLedger::filterNodes(
836  TriggerReason reason)
837 {
838  // Sort nodes so that the ones we haven't recently
839  // requested come before the ones we have.
840  auto dup = std::stable_partition(
841  nodes.begin(), nodes.end(), [this](auto const& item) {
842  return mRecentNodes.count(item.second) == 0;
843  });
844 
845  // If everything is a duplicate we don't want to send
846  // any query at all except on a timeout where we need
847  // to query everyone:
848  if (dup == nodes.begin())
849  {
850  JLOG(journal_.trace()) << "filterNodes: all duplicates";
851 
852  if (reason != TriggerReason::timeout)
853  {
854  nodes.clear();
855  return;
856  }
857  }
858  else
859  {
860  JLOG(journal_.trace()) << "filterNodes: pruning duplicates";
861 
862  nodes.erase(dup, nodes.end());
863  }
864 
865  std::size_t const limit =
866  (reason == TriggerReason::reply) ? reqNodesReply : reqNodes;
867 
868  if (nodes.size() > limit)
869  nodes.resize(limit);
870 
871  for (auto const& n : nodes)
872  mRecentNodes.insert(n.second);
873 }
874 
878 // data must not have hash prefix
879 bool
880 InboundLedger::takeHeader(std::string const& data)
881 {
882  // Return value: true=normal, false=bad data
883  JLOG(journal_.trace()) << "got header acquiring ledger " << hash_;
884 
885  if (complete_ || failed_ || mHaveHeader)
886  return true;
887 
888  auto* f = mReason == Reason::SHARD ? app_.getShardFamily()
889  : &app_.getNodeFamily();
890  mLedger = std::make_shared<Ledger>(
891  deserializeHeader(makeSlice(data)), app_.config(), *f);
892  if (mLedger->info().hash != hash_ ||
893  (mSeq != 0 && mSeq != mLedger->info().seq))
894  {
895  JLOG(journal_.warn())
896  << "Acquire hash mismatch: " << mLedger->info().hash
897  << "!=" << hash_;
898  mLedger.reset();
899  return false;
900  }
901  if (mSeq == 0)
902  mSeq = mLedger->info().seq;
903  mLedger->stateMap().setLedgerSeq(mSeq);
904  mLedger->txMap().setLedgerSeq(mSeq);
905  mHaveHeader = true;
906 
907  Serializer s(data.size() + 4);
908  s.add32(HashPrefix::ledgerMaster);
909  s.addRaw(data.data(), data.size());
910  f->db().store(hotLEDGER, std::move(s.modData()), hash_, mSeq);
911 
912  if (mLedger->info().txHash.isZero())
913  mHaveTransactions = true;
914 
915  if (mLedger->info().accountHash.isZero())
916  mHaveState = true;
917 
918  mLedger->txMap().setSynching();
919  mLedger->stateMap().setSynching();
920 
921  return true;
922 }
923 
927 void
928 InboundLedger::receiveNode(protocol::TMLedgerData& packet, SHAMapAddNode& san)
929 {
930  if (!mHaveHeader)
931  {
932  JLOG(journal_.warn()) << "Missing ledger header";
933  san.incInvalid();
934  return;
935  }
936  if (packet.type() == protocol::liTX_NODE)
937  {
938  if (mHaveTransactions || failed_)
939  {
940  san.incDuplicate();
941  return;
942  }
943  }
944  else if (mHaveState || failed_)
945  {
946  san.incDuplicate();
947  return;
948  }
949 
950  auto [map, rootHash, filter] = [&]()
952  if (packet.type() == protocol::liTX_NODE)
953  return {
954  mLedger->txMap(),
955  SHAMapHash{mLedger->info().txHash},
956  std::make_unique<TransactionStateSF>(
957  mLedger->txMap().family().db(), app_.getLedgerMaster())};
958  return {
959  mLedger->stateMap(),
960  SHAMapHash{mLedger->info().accountHash},
961  std::make_unique<AccountStateSF>(
962  mLedger->stateMap().family().db(), app_.getLedgerMaster())};
963  }();
964 
965  try
966  {
967  auto const f = filter.get();
968 
969  for (auto const& node : packet.nodes())
970  {
971  auto const nodeID = deserializeSHAMapNodeID(node.nodeid());
972 
973  if (!nodeID)
974  throw std::runtime_error("data does not properly deserialize");
975 
976  if (nodeID->isRoot())
977  {
978  san += map.addRootNode(rootHash, makeSlice(node.nodedata()), f);
979  }
980  else
981  {
982  san += map.addKnownNode(*nodeID, makeSlice(node.nodedata()), f);
983  }
984 
985  if (!san.isGood())
986  {
987  JLOG(journal_.warn()) << "Received bad node data";
988  return;
989  }
990  }
991  }
992  catch (std::exception const& e)
993  {
994  JLOG(journal_.error()) << "Received bad node data: " << e.what();
995  san.incInvalid();
996  return;
997  }
998 
999  if (!map.isSynching())
1000  {
1001  if (packet.type() == protocol::liTX_NODE)
1002  mHaveTransactions = true;
1003  else
1004  mHaveState = true;
1005 
1006  if (mHaveTransactions && mHaveState)
1007  {
1008  complete_ = true;
1009  done();
1010  }
1011  }
1012 }
1013 
1017 bool
1018 InboundLedger::takeAsRootNode(Slice const& data, SHAMapAddNode& san)
1019 {
1020  if (failed_ || mHaveState)
1021  {
1022  san.incDuplicate();
1023  return true;
1024  }
1025 
1026  if (!mHaveHeader)
1027  {
1028  assert(false);
1029  return false;
1030  }
1031 
1032  AccountStateSF filter(
1033  mLedger->stateMap().family().db(), app_.getLedgerMaster());
1034  san += mLedger->stateMap().addRootNode(
1035  SHAMapHash{mLedger->info().accountHash}, data, &filter);
1036  return san.isGood();
1037 }
1038 
1042 bool
1043 InboundLedger::takeTxRootNode(Slice const& data, SHAMapAddNode& san)
1044 {
1045  if (failed_ || mHaveTransactions)
1046  {
1047  san.incDuplicate();
1048  return true;
1049  }
1050 
1051  if (!mHaveHeader)
1052  {
1053  assert(false);
1054  return false;
1055  }
1056 
1057  TransactionStateSF filter(
1058  mLedger->txMap().family().db(), app_.getLedgerMaster());
1059  san += mLedger->txMap().addRootNode(
1060  SHAMapHash{mLedger->info().txHash}, data, &filter);
1061  return san.isGood();
1062 }
1063 
1065 InboundLedger::getNeededHashes()
1066 {
1068 
1069  if (!mHaveHeader)
1070  {
1071  ret.push_back(
1072  std::make_pair(protocol::TMGetObjectByHash::otLEDGER, hash_));
1073  return ret;
1074  }
1075 
1076  if (!mHaveState)
1077  {
1078  AccountStateSF filter(
1079  mLedger->stateMap().family().db(), app_.getLedgerMaster());
1080  for (auto const& h : neededStateHashes(4, &filter))
1081  {
1082  ret.push_back(
1083  std::make_pair(protocol::TMGetObjectByHash::otSTATE_NODE, h));
1084  }
1085  }
1086 
1087  if (!mHaveTransactions)
1088  {
1089  TransactionStateSF filter(
1090  mLedger->txMap().family().db(), app_.getLedgerMaster());
1091  for (auto const& h : neededTxHashes(4, &filter))
1092  {
1094  protocol::TMGetObjectByHash::otTRANSACTION_NODE, h));
1095  }
1096  }
1097 
1098  return ret;
1099 }
1100 
1104 bool
1105 InboundLedger::gotData(
1106  std::weak_ptr<Peer> peer,
1108 {
1109  std::lock_guard sl(mReceivedDataLock);
1110 
1111  if (isDone())
1112  return false;
1113 
1114  mReceivedData.emplace_back(peer, data);
1115 
1116  if (mReceiveDispatched)
1117  return false;
1118 
1119  mReceiveDispatched = true;
1120  return true;
1121 }
1122 
1126 // VFALCO NOTE, it is not necessary to pass the entire Peer,
1127 // we can get away with just a Resource::Consumer endpoint.
1128 //
1129 // TODO Change peer to Consumer
1130 //
1131 int
1132 InboundLedger::processData(
1133  std::shared_ptr<Peer> peer,
1134  protocol::TMLedgerData& packet)
1135 {
1136  if (packet.type() == protocol::liBASE)
1137  {
1138  if (packet.nodes().empty())
1139  {
1140  JLOG(journal_.warn()) << peer->id() << ": empty header data";
1141  peer->charge(Resource::feeInvalidRequest);
1142  return -1;
1143  }
1144 
1145  SHAMapAddNode san;
1146 
1147  ScopedLockType sl(mtx_);
1148 
1149  try
1150  {
1151  if (!mHaveHeader)
1152  {
1153  if (!takeHeader(packet.nodes(0).nodedata()))
1154  {
1155  JLOG(journal_.warn()) << "Got invalid header data";
1156  peer->charge(Resource::feeInvalidRequest);
1157  return -1;
1158  }
1159 
1160  san.incUseful();
1161  }
1162 
1163  if (!mHaveState && (packet.nodes().size() > 1) &&
1164  !takeAsRootNode(makeSlice(packet.nodes(1).nodedata()), san))
1165  {
1166  JLOG(journal_.warn()) << "Included AS root invalid";
1167  }
1168 
1169  if (!mHaveTransactions && (packet.nodes().size() > 2) &&
1170  !takeTxRootNode(makeSlice(packet.nodes(2).nodedata()), san))
1171  {
1172  JLOG(journal_.warn()) << "Included TX root invalid";
1173  }
1174  }
1175  catch (std::exception const& ex)
1176  {
1177  JLOG(journal_.warn())
1178  << "Included AS/TX root invalid: " << ex.what();
1179  peer->charge(Resource::feeBadData);
1180  return -1;
1181  }
1182 
1183  if (san.isUseful())
1184  progress_ = true;
1185 
1186  mStats += san;
1187  return san.getGood();
1188  }
1189 
1190  if ((packet.type() == protocol::liTX_NODE) ||
1191  (packet.type() == protocol::liAS_NODE))
1192  {
1193  std::string type = packet.type() == protocol::liTX_NODE ? "liTX_NODE: "
1194  : "liAS_NODE: ";
1195 
1196  if (packet.nodes().empty())
1197  {
1198  JLOG(journal_.info()) << peer->id() << ": response with no nodes";
1199  peer->charge(Resource::feeInvalidRequest);
1200  return -1;
1201  }
1202 
1203  ScopedLockType sl(mtx_);
1204 
1205  // Verify node IDs and data are complete
1206  for (auto const& node : packet.nodes())
1207  {
1208  if (!node.has_nodeid() || !node.has_nodedata())
1209  {
1210  JLOG(journal_.warn()) << "Got bad node";
1211  peer->charge(Resource::feeInvalidRequest);
1212  return -1;
1213  }
1214  }
1215 
1216  SHAMapAddNode san;
1217  receiveNode(packet, san);
1218 
1219  JLOG(journal_.debug())
1220  << "Ledger "
1221  << ((packet.type() == protocol::liTX_NODE) ? "TX" : "AS")
1222  << " node stats: " << san.get();
1223 
1224  if (san.isUseful())
1225  progress_ = true;
1226 
1227  mStats += san;
1228  return san.getGood();
1229  }
1230 
1231  return -1;
1232 }
1233 
1234 namespace detail {
1235 // Track the amount of useful data that each peer returns
1237 {
1238  // Map from peer to amount of useful the peer returned
1240  // The largest amount of useful data that any peer returned
1241  int maxCount = 0;
1242 
1243  // Update the data count for a peer
1244  void
1245  update(std::shared_ptr<Peer>&& peer, int dataCount)
1246  {
1247  if (dataCount <= 0)
1248  return;
1249  maxCount = std::max(maxCount, dataCount);
1250  auto i = counts.find(peer);
1251  if (i == counts.end())
1252  {
1253  counts.emplace(std::move(peer), dataCount);
1254  return;
1255  }
1256  i->second = std::max(i->second, dataCount);
1257  }
1258 
1259  // Prune all the peers that didn't return enough data.
1260  void
1262  {
1263  // Remove all the peers that didn't return at least half as much data as
1264  // the best peer
1265  auto const thresh = maxCount / 2;
1266  auto i = counts.begin();
1267  while (i != counts.end())
1268  {
1269  if (i->second < thresh)
1270  i = counts.erase(i);
1271  else
1272  ++i;
1273  }
1274  }
1275 
1276  // call F with the `peer` parameter with a random sample of at most n values
1277  // of the counts vector.
1278  template <class F>
1279  void
1281  {
1282  if (counts.empty())
1283  return;
1284 
1285  auto outFunc = [&f](auto&& v) { f(v.first); };
1287 #if _MSC_VER
1289  s.reserve(n);
1290  std::sample(
1291  counts.begin(), counts.end(), std::back_inserter(s), n, rng);
1292  for (auto& v : s)
1293  {
1294  outFunc(v);
1295  }
1296 #else
1297  std::sample(
1298  counts.begin(),
1299  counts.end(),
1300  boost::make_function_output_iterator(outFunc),
1301  n,
1302  rng);
1303 #endif
1304  }
1305 };
1306 } // namespace detail
1307 
1311 void
1312 InboundLedger::runData()
1313 {
1314  // Maximum number of peers to request data from
1315  constexpr std::size_t maxUsefulPeers = 6;
1316 
1317  decltype(mReceivedData) data;
1318 
1319  // Reserve some memory so the first couple iterations don't reallocate
1320  data.reserve(8);
1321 
1322  detail::PeerDataCounts dataCounts;
1323 
1324  for (;;)
1325  {
1326  data.clear();
1327 
1328  {
1329  std::lock_guard sl(mReceivedDataLock);
1330 
1331  if (mReceivedData.empty())
1332  {
1333  mReceiveDispatched = false;
1334  break;
1335  }
1336 
1337  data.swap(mReceivedData);
1338  }
1339 
1340  for (auto& entry : data)
1341  {
1342  if (auto peer = entry.first.lock())
1343  {
1344  int count = processData(peer, *(entry.second));
1345  dataCounts.update(std::move(peer), count);
1346  }
1347  }
1348  }
1349 
1350  // Select a random sample of the peers that gives us the most nodes that are
1351  // useful
1352  dataCounts.prune();
1353  dataCounts.sampleN(maxUsefulPeers, [&](std::shared_ptr<Peer> const& peer) {
1354  trigger(peer, TriggerReason::reply);
1355  });
1356 }
1357 
1359 InboundLedger::getJson(int)
1360 {
1362 
1363  ScopedLockType sl(mtx_);
1364 
1365  ret[jss::hash] = to_string(hash_);
1366 
1367  if (complete_)
1368  ret[jss::complete] = true;
1369 
1370  if (failed_)
1371  ret[jss::failed] = true;
1372 
1373  if (!complete_ && !failed_)
1374  ret[jss::peers] = static_cast<int>(mPeerSet->getPeerIds().size());
1375 
1376  ret[jss::have_header] = mHaveHeader;
1377 
1378  if (mHaveHeader)
1379  {
1380  ret[jss::have_state] = mHaveState;
1381  ret[jss::have_transactions] = mHaveTransactions;
1382  }
1383 
1384  ret[jss::timeouts] = timeouts_;
1385 
1386  if (mHaveHeader && !mHaveState)
1387  {
1389  for (auto const& h : neededStateHashes(16, nullptr))
1390  {
1391  hv.append(to_string(h));
1392  }
1393  ret[jss::needed_state_hashes] = hv;
1394  }
1395 
1396  if (mHaveHeader && !mHaveTransactions)
1397  {
1399  for (auto const& h : neededTxHashes(16, nullptr))
1400  {
1401  hv.append(to_string(h));
1402  }
1403  ret[jss::needed_transaction_hashes] = hv;
1404  }
1405 
1406  return ret;
1407 }
1408 
1409 } // namespace ripple
ripple::InboundLedger::mRecentNodes
std::set< uint256 > mRecentNodes
Definition: InboundLedger.h:187
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::Application
Definition: Application.h:115
ripple::SHAMapAddNode
Definition: SHAMapAddNode.h:28
ripple::Application::getNodeFamily
virtual Family & getNodeFamily()=0
ripple::SHAMapAddNode::get
std::string get() const
Definition: SHAMapAddNode.h:156
ripple::InboundLedger::Reason::HISTORY
@ HISTORY
ripple::InboundLedger::getNeededHashes
std::vector< neededHash_t > getNeededHashes()
Definition: InboundLedger.cpp:1065
ripple::InboundLedger::mReason
const Reason mReason
Definition: InboundLedger.h:185
std::for_each
T for_each(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:241
ripple::InboundLedger::TriggerReason
TriggerReason
Definition: InboundLedger.h:123
ripple::reqNodes
@ reqNodes
Definition: InboundLedger.cpp:71
ripple::NodeStore::Database
Persistency layer for NodeObject.
Definition: Database.h:51
std::string
STL class.
ripple::InboundLedger::Reason::CONSENSUS
@ CONSENSUS
std::shared_ptr
STL class.
ripple::InboundLedger::mHaveState
bool mHaveState
Definition: InboundLedger.h:180
ripple::LedgerInfo::parentHash
uint256 parentHash
Definition: ReadView.h:94
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:852
std::exception
STL class.
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::InboundLedger::TriggerReason::added
@ added
ripple::deserializeSHAMapNodeID
std::optional< SHAMapNodeID > deserializeSHAMapNodeID(void const *data, std::size_t size)
Return an object representing a serialized SHAMap Node ID.
Definition: SHAMapNodeID.cpp:101
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:178
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::InboundLedger::mSignaled
bool mSignaled
Definition: InboundLedger.h:182
std::pair
std::vector::reserve
T reserve(T... args)
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:91
ripple::ledgerAcquireTimeout
constexpr auto ledgerAcquireTimeout
Definition: InboundLedger.cpp:75
std::vector
STL class.
std::unordered_map::find
T find(T... args)
ripple::InboundLedger::update
void update(std::uint32_t seq)
Definition: InboundLedger.cpp:183
ripple::InboundLedger::touch
void touch()
Definition: InboundLedger.h:111
std::back_inserter
T back_inserter(T... args)
std::chrono::duration
ripple::peerCountStart
@ peerCountStart
Definition: InboundLedger.cpp:47
ripple::InboundLedger::~InboundLedger
~InboundLedger()
Definition: InboundLedger.cpp:216
ripple::TimeoutCounter::queueJob
void queueJob(ScopedLockType &)
Queue a job to call invokeOnTimer().
Definition: TimeoutCounter.cpp:69
ripple::TimeoutCounter::progress_
bool progress_
Whether forward progress has been made.
Definition: TimeoutCounter.h:134
random
ripple::InboundLedger::mByHash
bool mByHash
Definition: InboundLedger.h:183
std::unordered_map::emplace
T emplace(T... args)
ripple::neededHashes
static std::vector< uint256 > neededHashes(uint256 const &root, SHAMap &map, int max, SHAMapSyncFilter *filter)
Definition: InboundLedger.cpp:237
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
std::lock_guard
STL class.
ripple::SHAMapHash::isZero
bool isZero() const
Definition: SHAMapHash.h:53
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
ripple::InboundLedger::neededStateHashes
std::vector< uint256 > neededStateHashes(int max, SHAMapSyncFilter *filter) const
Definition: InboundLedger.cpp:268
ripple::detail::PeerDataCounts::prune
void prune()
Definition: InboundLedger.cpp:1261
std::tuple
ripple::AccountStateSF
Definition: AccountStateSF.h:31
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:166
ripple::InboundLedger::mPeerSet
std::unique_ptr< PeerSet > mPeerSet
Definition: InboundLedger.h:197
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:83
std::minstd_rand
ripple::TimeoutCounter
This class is an "active" object.
Definition: TimeoutCounter.h:66
ripple::deserializePrefixedHeader
LedgerInfo deserializePrefixedHeader(Slice data, bool hasHash)
Deserialize a ledger header (prefixed with 4 bytes) from a byte array.
Definition: InboundLedger.cpp:299
ripple::Family::db
virtual NodeStore::Database & db()=0
ripple::LedgerInfo::txHash
uint256 txHash
Definition: ReadView.h:92
ripple::XRP_LEDGER_EARLIEST_FEES
static constexpr std::uint32_t XRP_LEDGER_EARLIEST_FEES
The XRP Ledger mainnet's earliest ledger with a FeeSettings object.
Definition: SystemParameters.h:73
std::shared_ptr::reset
T reset(T... args)
ripple::SHAMapHash
Definition: SHAMapHash.h:32
algorithm
ripple::jtLEDGER_DATA
@ jtLEDGER_DATA
Definition: Job.h:67
ripple::TimeoutCounter::mtx_
std::recursive_mutex mtx_
Definition: TimeoutCounter.h:125
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:519
std::unique_lock::unlock
T unlock(T... args)
ripple::InboundLedger::neededTxHashes
std::vector< uint256 > neededTxHashes(int max, SHAMapSyncFilter *filter) const
Definition: InboundLedger.cpp:262
std::vector::push_back
T push_back(T... args)
ripple::LedgerInfo::closeTime
NetClock::time_point closeTime
Definition: ReadView.h:114
ripple::base_uint< 256 >
std::sample
T sample(T... args)
ripple::reqNodesReply
@ reqNodesReply
Definition: InboundLedger.cpp:67
std::addressof
T addressof(T... args)
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::InboundLedger::mLedger
std::shared_ptr< Ledger > mLedger
Definition: InboundLedger.h:178
std::enable_shared_from_this< InboundLedger >::shared_from_this
T shared_from_this(T... args)
ripple::TimeoutCounter::app_
Application & app_
Definition: TimeoutCounter.h:123
ripple::SerialIter::get8
unsigned char get8()
Definition: Serializer.cpp:362
ripple::SHAMapAddNode::isUseful
bool isUseful() const
Definition: SHAMapAddNode.h:116
ripple::InboundLedger::getPeerCount
std::size_t getPeerCount() const
Definition: InboundLedger.cpp:174
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::SerialIter::get256
uint256 get256()
Definition: Serializer.h:376
ripple::SerialIter::get64
std::uint64_t get64()
Definition: Serializer.cpp:399
std::random_device
ripple::InboundLedger::addPeers
void addPeers()
Add more peers to the set, if possible.
Definition: InboundLedger.cpp:483
ripple::LedgerMaster::getFetchPack
std::optional< Blob > getFetchPack(uint256 const &hash) override
Retrieves partial ledger data of the coresponding hash from peers.
Definition: LedgerMaster.cpp:2146
ripple::peerCountAdd
@ peerCountAdd
Definition: InboundLedger.cpp:51
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::TimeoutCounter::failed_
bool failed_
Definition: TimeoutCounter.h:132
ripple::InboundLedgers::gotStaleData
virtual void gotStaleData(std::shared_ptr< protocol::TMLedgerData > packet)=0
ripple::InboundLedger::InboundLedger
InboundLedger(Application &app, uint256 const &hash, std::uint32_t seq, Reason reason, clock_type &, std::unique_ptr< PeerSet > peerSet)
Definition: InboundLedger.cpp:77
ripple::Application::config
virtual Config & config()=0
ripple::InboundLedgers::onLedgerFetched
virtual void onLedgerFetched()=0
Called when a complete ledger is obtained.
ripple::SHAMapAddNode::isGood
bool isGood() const
Definition: SHAMapAddNode.h:132
std::unique_lock< std::recursive_mutex >
ripple::SHAMap
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:95
ripple::Serializer::addRaw
int addRaw(Blob const &vector)
Definition: Serializer.cpp:100
ripple::LedgerInfo::closeFlags
int closeFlags
Definition: ReadView.h:105
std::to_string
T to_string(T... args)
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::InboundLedger::tryDB
void tryDB(NodeStore::Database &srcDB)
Definition: InboundLedger.cpp:307
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
std::chrono::time_point
std::unordered_map::erase
T erase(T... args)
std::runtime_error
STL class.
ripple::SerialIter
Definition: Serializer.h:310
ripple::detail::PeerDataCounts
Definition: InboundLedger.cpp:1236
std::uint32_t
ripple::missingNodesFind
@ missingNodesFind
Definition: InboundLedger.cpp:63
ripple::TimeoutCounter::isDone
bool isDone() const
Definition: TimeoutCounter.h:116
ripple::InboundLedger::mHaveHeader
bool mHaveHeader
Definition: InboundLedger.h:179
beast::abstract_clock< std::chrono::steady_clock >
ripple::SHAMap::getMissingNodes
std::vector< std::pair< SHAMapNodeID, uint256 > > getMissingNodes(int maxNodes, SHAMapSyncFilter *filter)
Check for nodes in the SHAMap not available.
Definition: SHAMapSync.cpp:317
ripple::LedgerMaster::checkAccept
void checkAccept(std::shared_ptr< Ledger const > const &ledger)
Definition: LedgerMaster.cpp:1042
ripple::LedgerInfo::drops
XRPAmount drops
Definition: ReadView.h:96
std::weak_ptr
STL class.
ripple::Serializer
Definition: Serializer.h:39
ripple::InboundLedger::TriggerReason::timeout
@ timeout
ripple::InboundLedger::pmDowncast
std::weak_ptr< TimeoutCounter > pmDowncast() override
Return a weak pointer to this.
Definition: InboundLedger.cpp:497
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::deserializeHeader
LedgerInfo deserializeHeader(Slice data, bool hasHash)
Deserialize a ledger header from a byte array.
Definition: InboundLedger.cpp:275
ripple::InboundLedger::mStats
SHAMapAddNode mStats
Definition: InboundLedger.h:189
ripple::TimeoutCounter::hash_
const uint256 hash_
The hash of the object (in practice, always a ledger) we are trying to fetch.
Definition: TimeoutCounter.h:129
ripple::detail::PeerDataCounts::update
void update(std::shared_ptr< Peer > &&peer, int dataCount)
Definition: InboundLedger.cpp:1245
ripple::Application::getShardFamily
virtual Family * getShardFamily()=0
ripple::base_uint::begin
iterator begin()
Definition: base_uint.h:133
std::unordered_map::begin
T begin(T... args)
ripple::InboundLedger::mSeq
std::uint32_t mSeq
Definition: InboundLedger.h:184
ripple::LedgerInfo::closeTimeResolution
NetClock::duration closeTimeResolution
Definition: ReadView.h:108
ripple::detail::PeerDataCounts::sampleN
void sampleN(std::size_t n, F &&f)
Definition: InboundLedger.cpp:1280
ripple::NodeStore::DatabaseShard::setStored
virtual void setStored(std::shared_ptr< Ledger const > const &ledger)=0
Notifies the database that the given ledger has been fully acquired and stored.
std::count_if
T count_if(T... args)
ripple::InboundLedger::done
void done()
Definition: InboundLedger.cpp:503
std::unordered_map::empty
T empty(T... args)
ripple::detail::PeerDataCounts::counts
std::unordered_map< std::shared_ptr< Peer >, int > counts
Definition: InboundLedger.cpp:1239
ripple::InboundLedger::trigger
void trigger(std::shared_ptr< Peer > const &, TriggerReason)
Request more nodes, perhaps from a specific peer.
Definition: InboundLedger.cpp:557
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::SHAMapAddNode::incInvalid
void incInvalid()
Definition: SHAMapAddNode.h:80
std::size_t
ripple::keylet::fees
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition: Indexes.cpp:171
ripple::SHAMapAddNode::incUseful
void incUseful()
Definition: SHAMapAddNode.h:86
ripple::hotLEDGER
@ hotLEDGER
Definition: NodeObject.h:34
std::make_pair
T make_pair(T... args)
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::LedgerInfo
Information about the notional ledger backing the view.
Definition: ReadView.h:75
ripple::SHAMapAddNode::getGood
int getGood() const
Definition: SHAMapAddNode.h:104
ripple::LedgerMaster::storeLedger
bool storeLedger(std::shared_ptr< Ledger const > ledger)
Definition: LedgerMaster.cpp:536
std::unordered_map::end
T end(T... args)
ripple::InboundLedger::Reason
Reason
Definition: InboundLedger.h:43
ripple::NodeStore::Database::fetchNodeObject
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t ledgerSeq=0, FetchType fetchType=FetchType::synchronous, bool duplicate=false)
Fetch a node object.
Definition: Database.cpp:252
ripple::SHAMapAddNode::incDuplicate
void incDuplicate()
Definition: SHAMapAddNode.h:92
ripple::TimeoutCounter::complete_
bool complete_
Definition: TimeoutCounter.h:131
std::max
T max(T... args)
ripple::SerialIter::get32
std::uint32_t get32()
Definition: Serializer.cpp:386
ripple::ledgerBecomeAggressiveThreshold
@ ledgerBecomeAggressiveThreshold
Definition: InboundLedger.cpp:59
ripple::SHAMapSyncFilter
Definition: SHAMapSyncFilter.h:30
ripple::TimeoutCounter::timeouts_
int timeouts_
Definition: TimeoutCounter.h:130
std::unique_ptr
STL class.
std::stable_partition
T stable_partition(T... args)
ripple::InboundLedger::Reason::SHARD
@ SHARD
std::unordered_map
STL class.
ripple::InboundLedger::onTimer
void onTimer(bool progress, ScopedLockType &peerSetLock) override
Called with a lock by the PeerSet when the timer expires.
Definition: InboundLedger.cpp:432
ripple::InboundLedger::checkLocal
bool checkLocal()
Definition: InboundLedger.cpp:196
ripple::TransactionStateSF
Definition: TransactionStateSF.h:31
ripple::ledgerTimeoutRetriesMax
@ ledgerTimeoutRetriesMax
Definition: InboundLedger.cpp:55
ripple::InboundLedger::mHaveTransactions
bool mHaveTransactions
Definition: InboundLedger.h:181
ripple::InboundLedger::mReceivedData
std::vector< std::pair< std::weak_ptr< Peer >, std::shared_ptr< protocol::TMLedgerData > > > mReceivedData
Definition: InboundLedger.h:195
ripple::InboundLedger::init
void init(ScopedLockType &collectionLock)
Definition: InboundLedger.cpp:106
ripple::LedgerInfo::accountHash
uint256 accountHash
Definition: ReadView.h:93
ripple::TimeoutCounter::journal_
beast::Journal journal_
Definition: TimeoutCounter.h:124
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::LedgerInfo::parentCloseTime
NetClock::time_point parentCloseTime
Definition: ReadView.h:84
ripple::root
Number root(Number f, unsigned d)
Definition: Number.cpp:624