rippled
Loading...
Searching...
No Matches
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 <xrpld/app/ledger/BuildLedger.h>
21#include <xrpld/app/ledger/Ledger.h>
22#include <xrpld/app/ledger/LedgerReplay.h>
23#include <xrpld/app/ledger/OpenLedger.h>
24#include <xrpld/app/misc/CanonicalTXSet.h>
25#include <xrpld/app/tx/apply.h>
26
27#include <xrpl/protocol/Feature.h>
28
29namespace 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*/
37template <class ApplyTxs>
41 NetClock::time_point closeTime,
42 bool const 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 XRPL_ASSERT(
61 !accum.open(), "ripple::buildLedgerImpl : valid ledger state");
62 applyTxs(accum, built);
63 accum.apply(*built);
64 }
65
66 built->updateSkipList();
67 {
68 // Write the final version of all modified SHAMap
69 // nodes to the node store to preserve the new LCL
70
71 int const asf = built->stateMap().flushDirty(hotACCOUNT_NODE);
72 int const tmf = built->txMap().flushDirty(hotTRANSACTION_NODE);
73 JLOG(j.debug()) << "Flushed " << asf << " accounts and " << tmf
74 << " transaction nodes";
75 }
76 built->unshare();
77
78 // Accept ledger
79 XRPL_ASSERT(
80 built->info().seq < XRP_LEDGER_EARLIEST_FEES ||
81 built->read(keylet::fees()),
82 "ripple::buildLedgerImpl : valid ledger fees");
83 built->setAccepted(closeTime, closeResolution, closeTimeCorrect);
84
85 return built;
86}
87
100 Application& app,
102 CanonicalTXSet& txns,
103 std::set<TxID>& failed,
104 OpenView& view,
106{
107 bool certainRetry = true;
108 std::size_t count = 0;
109
110 // Attempt to apply all of the retriable transactions
111 for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass)
112 {
113 JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
114 << " begins (" << txns.size() << " transactions)";
115 int changes = 0;
116
117 auto it = txns.begin();
118
119 while (it != txns.end())
120 {
121 auto const txid = it->first.getTXID();
122
123 try
124 {
125 if (pass == 0 && built->txExists(txid))
126 {
127 it = txns.erase(it);
128 continue;
129 }
130
131 switch (applyTransaction(
132 app, view, *it->second, certainRetry, tapNONE, j))
133 {
135 it = txns.erase(it);
136 ++changes;
137 break;
138
140 failed.insert(txid);
141 it = txns.erase(it);
142 break;
143
145 ++it;
146 }
147 }
148 catch (std::exception const& ex)
149 {
150 JLOG(j.warn())
151 << "Transaction " << txid << " throws: " << ex.what();
152 failed.insert(txid);
153 it = txns.erase(it);
154 }
155 }
156
157 JLOG(j.debug()) << (certainRetry ? "Pass: " : "Final pass: ") << pass
158 << " completed (" << changes << " changes)";
159
160 // Accumulate changes.
161 count += changes;
162
163 // A non-retry pass made no changes
164 if (!changes && !certainRetry)
165 break;
166
167 // Stop retriable passes
168 if (!changes || (pass >= LEDGER_RETRY_PASSES))
169 certainRetry = false;
170 }
171
172 // If there are any transactions left, we must have
173 // tried them in at least one final pass
174 XRPL_ASSERT(
175 txns.empty() || !certainRetry,
176 "ripple::applyTransactions : retry transactions");
177 return count;
178}
179
180// Build a ledger from consensus transactions
183 std::shared_ptr<Ledger const> const& parent,
184 NetClock::time_point closeTime,
185 bool const closeTimeCorrect,
186 NetClock::duration closeResolution,
187 Application& app,
188 CanonicalTXSet& txns,
189 std::set<TxID>& failedTxns,
191{
192 JLOG(j.debug()) << "Report: Transaction Set = " << txns.key() << ", close "
193 << closeTime.time_since_epoch().count()
194 << (closeTimeCorrect ? "" : " (incorrect)");
195
196 return buildLedgerImpl(
197 parent,
198 closeTime,
199 closeTimeCorrect,
200 closeResolution,
201 app,
202 j,
203 [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
204 JLOG(j.debug())
205 << "Attempting to apply " << txns.size() << " transactions";
206
207 auto const applied =
208 applyTransactions(app, built, txns, failedTxns, accum, j);
209
210 if (!txns.empty() || !failedTxns.empty())
211 JLOG(j.debug())
212 << "Applied " << applied << " transactions; "
213 << failedTxns.size() << " failed and " << txns.size()
214 << " will be retried. "
215 << "Total transactions in ledger (including Inner Batch): "
216 << accum.txCount();
217 else
218 JLOG(j.debug())
219 << "Applied " << applied << " transactions. "
220 << "Total transactions in ledger (including Inner Batch): "
221 << accum.txCount();
222 });
223}
224
225// Build a ledger by replaying
228 LedgerReplay const& replayData,
229 ApplyFlags applyFlags,
230 Application& app,
232{
233 auto const& replayLedger = replayData.replay();
234
235 JLOG(j.debug()) << "Report: Replay Ledger " << replayLedger->info().hash;
236
237 return buildLedgerImpl(
238 replayData.parent(),
239 replayLedger->info().closeTime,
240 ((replayLedger->info().closeFlags & sLCF_NoConsensusTime) == 0),
241 replayLedger->info().closeTimeResolution,
242 app,
243 j,
244 [&](OpenView& accum, std::shared_ptr<Ledger> const& built) {
245 for (auto& tx : replayData.orderedTxns())
246 applyTransaction(app, accum, *tx.second, false, applyFlags, j);
247 });
248}
249
250} // namespace ripple
A generic endpoint for log messages.
Definition Journal.h:60
Stream debug() const
Definition Journal.h:328
Stream warn() const
Definition Journal.h:340
Holds transactions which were deferred to the next pass of consensus.
const_iterator end() const
const_iterator begin() const
const_iterator erase(const_iterator const &it)
uint256 const & key() const
std::shared_ptr< Ledger const > const & parent() const
std::shared_ptr< Ledger const > const & replay() const
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:65
std::size_t txCount() const
Return the number of tx inserted since creation.
Definition OpenView.cpp:122
bool open() const override
Returns true if this reflects an open ledger.
Definition OpenView.h:191
void apply(TxsRawView &to) const
Apply changes.
Definition OpenView.cpp:128
T empty(T... args)
T insert(T... args)
T is_same_v
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition Indexes.cpp:222
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
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.
std::shared_ptr< Ledger > buildLedgerImpl(std::shared_ptr< Ledger const > const &parent, NetClock::time_point closeTime, bool const closeTimeCorrect, NetClock::duration closeResolution, Application &app, beast::Journal j, ApplyTxs &&applyTxs)
@ Success
Applied to this ledger.
@ Retry
Should be retried in this ledger.
@ Fail
Should not be retried in this ledger.
@ hotACCOUNT_NODE
Definition NodeObject.h:35
@ hotTRANSACTION_NODE
Definition NodeObject.h:36
static constexpr std::uint32_t XRP_LEDGER_EARLIEST_FEES
The XRP Ledger mainnet's earliest ledger with a FeeSettings object.
static std::uint32_t const sLCF_NoConsensusTime
std::shared_ptr< Ledger > buildLedger(std::shared_ptr< Ledger const > const &parent, NetClock::time_point closeTime, bool const closeTimeCorrect, NetClock::duration closeResolution, Application &app, CanonicalTXSet &txns, std::set< TxID > &failedTxs, beast::Journal j)
Build a new ledger by applying consensus transactions.
@ tapNONE
Definition ApplyView.h:31
ApplyTransactionResult applyTransaction(Application &app, OpenView &view, STTx const &tx, bool retryAssured, ApplyFlags flags, beast::Journal journal)
Transaction application helper.
Definition apply.cpp:239
T size(T... args)
T time_since_epoch(T... args)
T what(T... args)