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  built->setAccepted(
79  closeTime, closeResolution, closeTimeCorrect, app.config());
80 
81  return built;
82 }
83 
96  Application& app,
97  std::shared_ptr<Ledger const> const& built,
98  CanonicalTXSet& txns,
99  std::set<TxID>& failed,
100  OpenView& view,
101  beast::Journal j)
102 {
103  bool certainRetry = true;
104  std::size_t count = 0;
105 
106  // Attempt to apply all of the retriable transactions
107  for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass)
108  {
109  JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
110  << " begins (" << txns.size() << " transactions)";
111  int changes = 0;
112 
113  auto it = txns.begin();
114 
115  while (it != txns.end())
116  {
117  auto const txid = it->first.getTXID();
118 
119  try
120  {
121  if (pass == 0 && built->txExists(txid))
122  {
123  it = txns.erase(it);
124  continue;
125  }
126 
127  switch (applyTransaction(
128  app, view, *it->second, certainRetry, tapNONE, j))
129  {
131  it = txns.erase(it);
132  ++changes;
133  break;
134 
135  case ApplyResult::Fail:
136  failed.insert(txid);
137  it = txns.erase(it);
138  break;
139 
140  case ApplyResult::Retry:
141  ++it;
142  }
143  }
144  catch (std::exception const&)
145  {
146  JLOG(j.warn()) << "Transaction " << txid << " throws";
147  failed.insert(txid);
148  it = txns.erase(it);
149  }
150  }
151 
152  JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
153  << " completed (" << changes << " changes)";
154 
155  // Accumulate changes.
156  count += changes;
157 
158  // A non-retry pass made no changes
159  if (!changes && !certainRetry)
160  break;
161 
162  // Stop retriable passes
163  if (!changes || (pass >= LEDGER_RETRY_PASSES))
164  certainRetry = false;
165  }
166 
167  // If there are any transactions left, we must have
168  // tried them in at least one final pass
169  assert(txns.empty() || !certainRetry);
170  return count;
171 }
172 
173 // Build a ledger from consensus transactions
176  std::shared_ptr<Ledger const> const& parent,
177  NetClock::time_point closeTime,
178  const bool closeTimeCorrect,
179  NetClock::duration closeResolution,
180  Application& app,
181  CanonicalTXSet& txns,
182  std::set<TxID>& failedTxns,
183  beast::Journal j)
184 {
185  JLOG(j.debug()) << "Report: Transaction Set = " << txns.key() << ", close "
186  << closeTime.time_since_epoch().count()
187  << (closeTimeCorrect ? "" : " (incorrect)");
188 
189  return buildLedgerImpl(
190  parent,
191  closeTime,
192  closeTimeCorrect,
193  closeResolution,
194  app,
195  j,
196  [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
197  JLOG(j.debug())
198  << "Attempting to apply " << txns.size() << " transactions";
199 
200  auto const applied =
201  applyTransactions(app, built, txns, failedTxns, accum, j);
202 
203  if (!txns.empty() || !failedTxns.empty())
204  JLOG(j.debug()) << "Applied " << applied << " transactions; "
205  << failedTxns.size() << " failed and "
206  << txns.size() << " will be retried.";
207  else
208  JLOG(j.debug()) << "Applied " << applied << " transactions.";
209  });
210 }
211 
212 // Build a ledger by replaying
215  LedgerReplay const& replayData,
216  ApplyFlags applyFlags,
217  Application& app,
218  beast::Journal j)
219 {
220  auto const& replayLedger = replayData.replay();
221 
222  JLOG(j.debug()) << "Report: Replay Ledger " << replayLedger->info().hash;
223 
224  return buildLedgerImpl(
225  replayData.parent(),
226  replayLedger->info().closeTime,
227  ((replayLedger->info().closeFlags & sLCF_NoConsensusTime) == 0),
228  replayLedger->info().closeTimeResolution,
229  app,
230  j,
231  [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
232  for (auto& tx : replayData.orderedTxns())
233  applyTransaction(app, accum, *tx.second, false, applyFlags, j);
234  });
235 }
236 
237 } // 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::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
Definition: Ledger.cpp:482
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: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:95
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:175
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:348
ripple::LedgerReplay
Definition: LedgerReplay.h:33