rippled
BuildLedger.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2018 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/BuildLedger.h>
21 #include <ripple/app/ledger/Ledger.h>
22 #include <ripple/app/ledger/LedgerReplay.h>
23 #include <ripple/app/ledger/OpenLedger.h>
24 #include <ripple/app/main/Application.h>
25 #include <ripple/app/misc/CanonicalTXSet.h>
26 #include <ripple/app/tx/apply.h>
27 #include <ripple/protocol/Feature.h>
28 
29 namespace ripple {
30 
31 /* Generic buildLedgerImpl that dispatches to ApplyTxs invocable with signature
32  void(OpenView&, std::shared_ptr<Ledger> const&)
33  It is responsible for adding transactions to the open view to generate the
34  new ledger. It is generic since the mechanics differ for consensus
35  generated ledgers versus replayed ledgers.
36 */
37 template <class ApplyTxs>
40  std::shared_ptr<Ledger const> const& parent,
41  NetClock::time_point closeTime,
42  const bool closeTimeCorrect,
43  NetClock::duration closeResolution,
44  Application& app,
46  ApplyTxs&& applyTxs)
47 {
48  auto built = std::make_shared<Ledger>(*parent, closeTime);
49 
50  // Set up to write SHAMap changes to our database,
51  // perform updates, extract changes
52 
53  {
54  OpenView accum(&*built);
55  assert(!accum.open());
56  applyTxs(accum, built);
57  accum.apply(*built);
58  }
59 
60  built->updateSkipList();
61  {
62  // Write the final version of all modified SHAMap
63  // nodes to the node store to preserve the new LCL
64 
65  int const asf =
66  built->stateMap().flushDirty(hotACCOUNT_NODE, built->info().seq);
67  int const tmf =
68  built->txMap().flushDirty(hotTRANSACTION_NODE, built->info().seq);
69  JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf
70  << " transaction nodes";
71  }
72  built->unshare();
73 
74  // Accept ledger
75  built->setAccepted(
76  closeTime, closeResolution, closeTimeCorrect, app.config());
77 
78  return built;
79 }
80 
93  Application& app,
94  std::shared_ptr<Ledger const> const& built,
95  CanonicalTXSet& txns,
96  std::set<TxID>& failed,
97  OpenView& view,
99 {
100  bool certainRetry = true;
101  std::size_t count = 0;
102 
103  // Attempt to apply all of the retriable transactions
104  for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass)
105  {
106  JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
107  << " begins (" << txns.size() << " transactions)";
108  int changes = 0;
109 
110  auto it = txns.begin();
111 
112  while (it != txns.end())
113  {
114  auto const txid = it->first.getTXID();
115 
116  try
117  {
118  if (pass == 0 && built->txExists(txid))
119  {
120  it = txns.erase(it);
121  continue;
122  }
123 
124  switch (applyTransaction(
125  app, view, *it->second, certainRetry, tapNONE, j))
126  {
128  it = txns.erase(it);
129  ++changes;
130  break;
131 
132  case ApplyResult::Fail:
133  failed.insert(txid);
134  it = txns.erase(it);
135  break;
136 
137  case ApplyResult::Retry:
138  ++it;
139  }
140  }
141  catch (std::exception const&)
142  {
143  JLOG(j.warn()) << "Transaction " << txid << " throws";
144  failed.insert(txid);
145  it = txns.erase(it);
146  }
147  }
148 
149  JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
150  << " completed (" << changes << " changes)";
151 
152  // Accumulate changes.
153  count += changes;
154 
155  // A non-retry pass made no changes
156  if (!changes && !certainRetry)
157  break;
158 
159  // Stop retriable passes
160  if (!changes || (pass >= LEDGER_RETRY_PASSES))
161  certainRetry = false;
162  }
163 
164  // If there are any transactions left, we must have
165  // tried them in at least one final pass
166  assert(txns.empty() || !certainRetry);
167  return count;
168 }
169 
170 // Build a ledger from consensus transactions
173  std::shared_ptr<Ledger const> const& parent,
174  NetClock::time_point closeTime,
175  const bool closeTimeCorrect,
176  NetClock::duration closeResolution,
177  Application& app,
178  CanonicalTXSet& txns,
179  std::set<TxID>& failedTxns,
180  beast::Journal j)
181 {
182  JLOG(j.debug()) << "Report: Transaction Set = " << txns.key() << ", close "
183  << closeTime.time_since_epoch().count()
184  << (closeTimeCorrect ? "" : " (incorrect)");
185 
186  return buildLedgerImpl(
187  parent,
188  closeTime,
189  closeTimeCorrect,
190  closeResolution,
191  app,
192  j,
193  [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
194  JLOG(j.debug())
195  << "Attempting to apply " << txns.size() << " transactions";
196 
197  auto const applied =
198  applyTransactions(app, built, txns, failedTxns, accum, j);
199 
200  if (!txns.empty() || !failedTxns.empty())
201  JLOG(j.debug()) << "Applied " << applied << " transactions; "
202  << failedTxns.size() << " failed and "
203  << txns.size() << " will be retried.";
204  else
205  JLOG(j.debug()) << "Applied " << applied << " transactions.";
206  });
207 }
208 
209 // Build a ledger by replaying
212  LedgerReplay const& replayData,
213  ApplyFlags applyFlags,
214  Application& app,
215  beast::Journal j)
216 {
217  auto const& replayLedger = replayData.replay();
218 
219  JLOG(j.debug()) << "Report: Replay Ledger " << replayLedger->info().hash;
220 
221  return buildLedgerImpl(
222  replayData.parent(),
223  replayLedger->info().closeTime,
224  ((replayLedger->info().closeFlags & sLCF_NoConsensusTime) == 0),
225  replayLedger->info().closeTimeResolution,
226  app,
227  j,
228  [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
229  for (auto& tx : replayData.orderedTxns())
230  applyTransaction(app, accum, *tx.second, false, applyFlags, j);
231  });
232 }
233 
234 } // namespace ripple
ripple::Application
Definition: Application.h:94
std::shared_ptr
STL class.
std::exception
STL class.
ripple::CanonicalTXSet::key
uint256 const & key() const
Definition: CanonicalTXSet.h:136
ripple::OpenView::apply
void apply(TxsRawView &to) const
Apply changes.
Definition: OpenView.cpp:107
ripple::CanonicalTXSet::erase
const_iterator erase(const_iterator const &it)
Definition: CanonicalTXSet.h:107
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:52
ripple::hotACCOUNT_NODE
@ hotACCOUNT_NODE
Definition: NodeObject.h:35
ripple::applyTransaction
ApplyResult applyTransaction(Application &app, OpenView &view, STTx const &tx, bool retryAssured, ApplyFlags flags, beast::Journal journal)
Transaction application helper.
Definition: apply.cpp:122
std::set::size
T size(T... args)
std::chrono::duration
ripple::ApplyFlags
ApplyFlags
Definition: ApplyView.h:30
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::hotTRANSACTION_NODE
@ hotTRANSACTION_NODE
Definition: NodeObject.h:36
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:31
ripple::CanonicalTXSet
Holds transactions which were deferred to the next pass of consensus.
Definition: CanonicalTXSet.h:36
ripple::CanonicalTXSet::begin
const_iterator begin() const
Definition: CanonicalTXSet.h:113
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::LedgerReplay::parent
std::shared_ptr< Ledger const > const & parent() const
Definition: LedgerReplay.h:46
ripple::Ledger::txExists
bool txExists(uint256 const &key) const override
Returns true if a tx exists in the tx map.
Definition: Ledger.cpp:457
ripple::buildLedgerImpl
std::shared_ptr< Ledger > buildLedgerImpl(std::shared_ptr< Ledger const > const &parent, NetClock::time_point closeTime, const bool closeTimeCorrect, NetClock::duration closeResolution, Application &app, beast::Journal j, ApplyTxs &&applyTxs)
Definition: BuildLedger.cpp:39
ripple::Application::config
virtual Config & config()=0
ripple::ApplyResult::Retry
@ Retry
Should be retried in this ledger.
ripple::OpenView::open
bool open() const override
Returns true if this reflects an open ledger.
Definition: OpenView.h:154
std::chrono::time_point
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::LedgerReplay::replay
std::shared_ptr< Ledger const > const & replay() const
Definition: LedgerReplay.h:54
ripple::applyTransactions
std::size_t applyTransactions(Application &app, std::shared_ptr< Ledger const > const &built, CanonicalTXSet &txns, std::set< TxID > &failed, OpenView &view, beast::Journal j)
Apply a set of consensus transactions to a ledger.
Definition: BuildLedger.cpp:92
ripple::ApplyResult::Success
@ Success
Applied to this ledger.
ripple::CanonicalTXSet::end
const_iterator end() const
Definition: CanonicalTXSet.h:119
ripple::ApplyResult::Fail
@ Fail
Should not be retried in this ledger.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::CanonicalTXSet::size
size_t size() const
Definition: CanonicalTXSet.h:125
std::set::insert
T insert(T... args)
ripple::CanonicalTXSet::empty
bool empty() const
Definition: CanonicalTXSet.h:130
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
std::set::empty
T empty(T... args)
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
std::set
STL class.
ripple::sLCF_NoConsensusTime
static const std::uint32_t sLCF_NoConsensusTime
Definition: ReadView.h:411
ripple::LedgerReplay
Definition: LedgerReplay.h:32