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 =
71  built->stateMap().flushDirty(hotACCOUNT_NODE, built->info().seq);
72  int const tmf =
73  built->txMap().flushDirty(hotTRANSACTION_NODE, built->info().seq);
74  JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf
75  << " transaction nodes";
76  }
77  built->unshare();
78 
79  // Accept ledger
80  built->setAccepted(
81  closeTime, closeResolution, closeTimeCorrect, app.config());
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&)
147  {
148  JLOG(j.warn()) << "Transaction " << txid << " throws";
149  failed.insert(txid);
150  it = txns.erase(it);
151  }
152  }
153 
154  JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
155  << " completed (" << changes << " changes)";
156 
157  // Accumulate changes.
158  count += changes;
159 
160  // A non-retry pass made no changes
161  if (!changes && !certainRetry)
162  break;
163 
164  // Stop retriable passes
165  if (!changes || (pass >= LEDGER_RETRY_PASSES))
166  certainRetry = false;
167  }
168 
169  // If there are any transactions left, we must have
170  // tried them in at least one final pass
171  assert(txns.empty() || !certainRetry);
172  return count;
173 }
174 
175 // Build a ledger from consensus transactions
178  std::shared_ptr<Ledger const> const& parent,
179  NetClock::time_point closeTime,
180  const bool closeTimeCorrect,
181  NetClock::duration closeResolution,
182  Application& app,
183  CanonicalTXSet& txns,
184  std::set<TxID>& failedTxns,
185  beast::Journal j)
186 {
187  JLOG(j.debug()) << "Report: Transaction Set = " << txns.key() << ", close "
188  << closeTime.time_since_epoch().count()
189  << (closeTimeCorrect ? "" : " (incorrect)");
190 
191  return buildLedgerImpl(
192  parent,
193  closeTime,
194  closeTimeCorrect,
195  closeResolution,
196  app,
197  j,
198  [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
199  JLOG(j.debug())
200  << "Attempting to apply " << txns.size() << " transactions";
201 
202  auto const applied =
203  applyTransactions(app, built, txns, failedTxns, accum, j);
204 
205  if (!txns.empty() || !failedTxns.empty())
206  JLOG(j.debug()) << "Applied " << applied << " transactions; "
207  << failedTxns.size() << " failed and "
208  << txns.size() << " will be retried.";
209  else
210  JLOG(j.debug()) << "Applied " << applied << " transactions.";
211  });
212 }
213 
214 // Build a ledger by replaying
217  LedgerReplay const& replayData,
218  ApplyFlags applyFlags,
219  Application& app,
220  beast::Journal j)
221 {
222  auto const& replayLedger = replayData.replay();
223 
224  JLOG(j.debug()) << "Report: Replay Ledger " << replayLedger->info().hash;
225 
226  return buildLedgerImpl(
227  replayData.parent(),
228  replayLedger->info().closeTime,
229  ((replayLedger->info().closeFlags & sLCF_NoConsensusTime) == 0),
230  replayLedger->info().closeTimeResolution,
231  app,
232  j,
233  [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
234  for (auto& tx : replayData.orderedTxns())
235  applyTransaction(app, accum, *tx.second, false, applyFlags, j);
236  });
237 }
238 
239 } // namespace ripple
ripple::Application
Definition: Application.h:97
std::shared_ptr< Ledger >
std::exception
STL class.
ripple::CanonicalTXSet::key
uint256 const & key() const
Definition: CanonicalTXSet.h:165
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:136
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:37
ripple::CanonicalTXSet::begin
const_iterator begin() const
Definition: CanonicalTXSet.h:142
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:458
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:97
ripple::ApplyResult::Success
@ Success
Applied to this ledger.
ripple::CanonicalTXSet::end
const_iterator end() const
Definition: CanonicalTXSet.h:148
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:154
ripple::featureNegativeUNL
const uint256 featureNegativeUNL
Definition: Feature.cpp:188
std::set::insert
T insert(T... args)
ripple::CanonicalTXSet::empty
bool empty() const
Definition: CanonicalTXSet.h:159
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:177
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:415
ripple::LedgerReplay
Definition: LedgerReplay.h:32