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  if (built->isFlagLedger() && built->rules().enabled(featureNegativeUNL))
51  {
52  built->updateNegativeUNL();
53  }
54 
55  // Set up to write SHAMap changes to our database,
56  // perform updates, extract changes
57 
58  {
59  OpenView accum(&*built);
60  assert(!accum.open());
61  applyTxs(accum, built);
62  accum.apply(*built);
63  }
64 
65  built->updateSkipList();
66  {
67  // Write the final version of all modified SHAMap
68  // nodes to the node store to preserve the new LCL
69 
70  int const asf = built->stateMap().flushDirty(hotACCOUNT_NODE);
71  int const tmf = built->txMap().flushDirty(hotTRANSACTION_NODE);
72  JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf
73  << " transaction nodes";
74  }
75  built->unshare();
76 
77  // Accept ledger
78  assert(
79  built->info().seq < XRP_LEDGER_EARLIEST_FEES ||
80  built->read(keylet::fees()));
81  built->setAccepted(closeTime, closeResolution, closeTimeCorrect);
82 
83  return built;
84 }
85 
98  Application& app,
99  std::shared_ptr<Ledger const> const& built,
100  CanonicalTXSet& txns,
101  std::set<TxID>& failed,
102  OpenView& view,
103  beast::Journal j)
104 {
105  bool certainRetry = true;
106  std::size_t count = 0;
107 
108  // Attempt to apply all of the retriable transactions
109  for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass)
110  {
111  JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
112  << " begins (" << txns.size() << " transactions)";
113  int changes = 0;
114 
115  auto it = txns.begin();
116 
117  while (it != txns.end())
118  {
119  auto const txid = it->first.getTXID();
120 
121  try
122  {
123  if (pass == 0 && built->txExists(txid))
124  {
125  it = txns.erase(it);
126  continue;
127  }
128 
129  switch (applyTransaction(
130  app, view, *it->second, certainRetry, tapNONE, j))
131  {
133  it = txns.erase(it);
134  ++changes;
135  break;
136 
137  case ApplyResult::Fail:
138  failed.insert(txid);
139  it = txns.erase(it);
140  break;
141 
142  case ApplyResult::Retry:
143  ++it;
144  }
145  }
146  catch (std::exception const& ex)
147  {
148  JLOG(j.warn())
149  << "Transaction " << txid << " throws: " << ex.what();
150  failed.insert(txid);
151  it = txns.erase(it);
152  }
153  }
154 
155  JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
156  << " completed (" << changes << " changes)";
157 
158  // Accumulate changes.
159  count += changes;
160 
161  // A non-retry pass made no changes
162  if (!changes && !certainRetry)
163  break;
164 
165  // Stop retriable passes
166  if (!changes || (pass >= LEDGER_RETRY_PASSES))
167  certainRetry = false;
168  }
169 
170  // If there are any transactions left, we must have
171  // tried them in at least one final pass
172  assert(txns.empty() || !certainRetry);
173  return count;
174 }
175 
176 // Build a ledger from consensus transactions
179  std::shared_ptr<Ledger const> const& parent,
180  NetClock::time_point closeTime,
181  const bool closeTimeCorrect,
182  NetClock::duration closeResolution,
183  Application& app,
184  CanonicalTXSet& txns,
185  std::set<TxID>& failedTxns,
186  beast::Journal j)
187 {
188  JLOG(j.debug()) << "Report: Transaction Set = " << txns.key() << ", close "
189  << closeTime.time_since_epoch().count()
190  << (closeTimeCorrect ? "" : " (incorrect)");
191 
192  return buildLedgerImpl(
193  parent,
194  closeTime,
195  closeTimeCorrect,
196  closeResolution,
197  app,
198  j,
199  [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
200  JLOG(j.debug())
201  << "Attempting to apply " << txns.size() << " transactions";
202 
203  auto const applied =
204  applyTransactions(app, built, txns, failedTxns, accum, j);
205 
206  if (!txns.empty() || !failedTxns.empty())
207  JLOG(j.debug()) << "Applied " << applied << " transactions; "
208  << failedTxns.size() << " failed and "
209  << txns.size() << " will be retried.";
210  else
211  JLOG(j.debug()) << "Applied " << applied << " transactions.";
212  });
213 }
214 
215 // Build a ledger by replaying
218  LedgerReplay const& replayData,
219  ApplyFlags applyFlags,
220  Application& app,
221  beast::Journal j)
222 {
223  auto const& replayLedger = replayData.replay();
224 
225  JLOG(j.debug()) << "Report: Replay Ledger " << replayLedger->info().hash;
226 
227  return buildLedgerImpl(
228  replayData.parent(),
229  replayLedger->info().closeTime,
230  ((replayLedger->info().closeFlags & sLCF_NoConsensusTime) == 0),
231  replayLedger->info().closeTimeResolution,
232  app,
233  j,
234  [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
235  for (auto& tx : replayData.orderedTxns())
236  applyTransaction(app, accum, *tx.second, false, applyFlags, j);
237  });
238 }
239 
240 } // namespace ripple
ripple::Application
Definition: Application.h:115
std::shared_ptr< Ledger >
std::exception
STL class.
ripple::CanonicalTXSet::key
uint256 const & key() const
Definition: CanonicalTXSet.h:166
ripple::OpenView::apply
void apply(TxsRawView &to) const
Apply changes.
Definition: OpenView.cpp:130
ripple::CanonicalTXSet::erase
const_iterator erase(const_iterator const &it)
Definition: CanonicalTXSet.h:137
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:55
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:125
std::set::size
T size(T... args)
std::chrono::duration
ripple::ApplyFlags
ApplyFlags
Definition: ApplyView.h:29
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:30
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
ripple::CanonicalTXSet
Holds transactions which were deferred to the next pass of consensus.
Definition: CanonicalTXSet.h:38
ripple::CanonicalTXSet::begin
const_iterator begin() const
Definition: CanonicalTXSet.h:143
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:52
ripple::Ledger::txExists
bool txExists(uint256 const &key) const override
Returns true if a tx exists in the tx map.
Definition: Ledger.cpp:503
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::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:175
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:60
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:97
ripple::ApplyResult::Success
@ Success
Applied to this ledger.
ripple::CanonicalTXSet::end
const_iterator end() const
Definition: CanonicalTXSet.h:149
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:155
ripple::featureNegativeUNL
const uint256 featureNegativeUNL
std::set::insert
T insert(T... args)
ripple::CanonicalTXSet::empty
bool empty() const
Definition: CanonicalTXSet.h:160
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:178
std::set::empty
T empty(T... args)
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
ripple::keylet::fees
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition: Indexes.cpp:171
std::set
STL class.
std::exception::what
T what(T... args)
ripple::sLCF_NoConsensusTime
static const std::uint32_t sLCF_NoConsensusTime
Definition: ReadView.h:348
ripple::LedgerReplay
Definition: LedgerReplay.h:33