rippled
Loading...
Searching...
No Matches
LedgerDeltaAcquire.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2020 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/InboundLedger.h>
22#include <xrpld/app/ledger/LedgerReplay.h>
23#include <xrpld/app/ledger/LedgerReplayer.h>
24#include <xrpld/app/ledger/detail/LedgerDeltaAcquire.h>
25#include <xrpld/app/main/Application.h>
26#include <xrpld/core/JobQueue.h>
27#include <xrpld/overlay/PeerSet.h>
28
29namespace ripple {
30
32 Application& app,
33 InboundLedgers& inboundLedgers,
34 uint256 const& ledgerHash,
35 std::uint32_t ledgerSeq,
38 app,
39 ledgerHash,
40 LedgerReplayParameters::SUB_TASK_TIMEOUT,
42 "LedgerReplayDelta",
44 app.journal("LedgerReplayDelta"))
45 , inboundLedgers_(inboundLedgers)
46 , ledgerSeq_(ledgerSeq)
47 , peerSet_(std::move(peerSet))
48{
49 JLOG(journal_.trace()) << "Create " << hash_ << " Seq " << ledgerSeq;
50}
51
53{
54 JLOG(journal_.trace()) << "Destroy " << hash_;
55}
56
57void
59{
61 if (!isDone())
62 {
63 trigger(numPeers, sl);
64 setTimer(sl);
65 }
66}
67
68void
70{
72 if (fullLedger_)
73 {
74 complete_ = true;
75 JLOG(journal_.trace()) << "existing ledger " << hash_;
76 notify(sl);
77 return;
78 }
79
80 if (!fallBack_)
81 {
82 peerSet_->addPeers(
83 limit,
84 [this](auto peer) {
85 return peer->supportsFeature(ProtocolFeature::LedgerReplay) &&
86 peer->hasLedger(hash_, ledgerSeq_);
87 },
88 [this](auto peer) {
89 if (peer->supportsFeature(ProtocolFeature::LedgerReplay))
90 {
91 JLOG(journal_.trace())
92 << "Add a peer " << peer->id() << " for " << hash_;
93 protocol::TMReplayDeltaRequest request;
94 request.set_ledgerhash(hash_.data(), hash_.size());
95 peerSet_->sendRequest(request, peer);
96 }
97 else
98 {
99 if (++noFeaturePeerCount >=
101 {
102 JLOG(journal_.debug()) << "Fall back for " << hash_;
105 fallBack_ = true;
106 }
107 }
108 });
109 }
110
111 if (fallBack_)
114}
115
116void
118{
119 JLOG(journal_.trace()) << "mTimeouts=" << timeouts_ << " for " << hash_;
121 {
122 failed_ = true;
123 JLOG(journal_.debug()) << "too many timeouts " << hash_;
124 notify(sl);
125 }
126 else
127 {
128 trigger(1, sl);
129 }
130}
131
137
138void
140 LedgerInfo const& info,
142{
144 JLOG(journal_.trace()) << "got data for " << hash_;
145 if (isDone())
146 return;
147
148 if (info.seq == ledgerSeq_)
149 {
150 // create a temporary ledger for building a LedgerReplay object later
153 if (replayTemp_)
154 {
155 complete_ = true;
156 orderedTxns_ = std::move(orderedTxns);
157 JLOG(journal_.debug()) << "ready to replay " << hash_;
158 notify(sl);
159 return;
160 }
161 }
162
163 failed_ = true;
164 JLOG(journal_.error())
165 << "failed to create a (info only) ledger from verified data " << hash_;
166 notify(sl);
167}
168
169void
172 OnDeltaDataCB&& cb)
173{
175 dataReadyCallbacks_.emplace_back(std::move(cb));
176 if (reasons_.count(reason) == 0)
177 {
178 reasons_.emplace(reason);
179 if (fullLedger_)
180 onLedgerBuilt(sl, reason);
181 }
182
183 if (isDone())
184 {
185 JLOG(journal_.debug())
186 << "task added to a finished LedgerDeltaAcquire " << hash_;
187 notify(sl);
188 }
189}
190
193{
195
196 if (fullLedger_)
197 return fullLedger_;
198
199 if (failed_ || !complete_ || !replayTemp_)
200 return {};
201
202 XRPL_ASSERT(
203 parent->seq() + 1 == replayTemp_->seq(),
204 "ripple::LedgerDeltaAcquire::tryBuild : parent sequence match");
205 XRPL_ASSERT(
206 parent->info().hash == replayTemp_->info().parentHash,
207 "ripple::LedgerDeltaAcquire::tryBuild : parent hash match");
208 // build ledger
209 LedgerReplay replayData(parent, replayTemp_, std::move(orderedTxns_));
211 if (fullLedger_ && fullLedger_->info().hash == hash_)
212 {
213 JLOG(journal_.info()) << "Built " << hash_;
214 onLedgerBuilt(sl);
215 return fullLedger_;
216 }
217 else
218 {
219 failed_ = true;
220 complete_ = false;
221 JLOG(journal_.error()) << "tryBuild failed " << hash_ << " with parent "
222 << parent->info().hash;
223 Throw<std::runtime_error>("Cannot replay ledger");
224 }
225}
226
227void
229 ScopedLockType& sl,
231{
232 JLOG(journal_.debug()) << "onLedgerBuilt " << hash_
233 << (reason ? " for a new reason" : "");
234
237 bool firstTime = true;
238 if (reason) // small chance
239 {
240 reasons.clear();
241 reasons.push_back(*reason);
242 firstTime = false;
243 }
246 "onLedgerBuilt",
247 [=, ledger = this->fullLedger_, &app = this->app_]() {
248 for (auto reason : reasons)
249 {
250 switch (reason)
251 {
253 app.getLedgerMaster().storeLedger(ledger);
254 break;
255 default:
256 // TODO for other use cases
257 break;
258 }
259 }
260
261 if (firstTime)
262 app.getLedgerMaster().tryAdvance();
263 });
264}
265
266void
268{
269 XRPL_ASSERT(isDone(), "ripple::LedgerDeltaAcquire::notify : is done");
272 auto const good = !failed_;
273 sl.unlock();
274
275 for (auto& cb : toCall)
276 {
277 cb(good, hash_);
278 }
279
280 sl.lock();
281}
282
283} // namespace ripple
T begin(T... args)
Stream error() const
Definition Journal.h:346
Stream debug() const
Definition Journal.h:328
Stream info() const
Definition Journal.h:334
Stream trace() const
Severity stream access functions.
Definition Journal.h:322
virtual Config & config()=0
virtual JobQueue & getJobQueue()=0
virtual Family & getNodeFamily()=0
virtual LedgerMaster & getLedgerMaster()=0
Manages the lifetime of inbound ledgers.
virtual std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason)=0
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition JobQueue.h:168
std::shared_ptr< Ledger const > fullLedger_
void trigger(std::size_t limit, ScopedLockType &sl)
Trigger another round.
std::set< InboundLedger::Reason > reasons_
LedgerDeltaAcquire(Application &app, InboundLedgers &inboundLedgers, uint256 const &ledgerHash, std::uint32_t ledgerSeq, std::unique_ptr< PeerSet > peerSet)
Constructor.
void processData(LedgerInfo const &info, std::map< std::uint32_t, std::shared_ptr< STTx const > > &&orderedTxns)
Process the data extracted from a peer's reply.
std::map< std::uint32_t, std::shared_ptr< STTx const > > orderedTxns_
std::shared_ptr< Ledger const > tryBuild(std::shared_ptr< Ledger const > const &parent)
Try to build the ledger if not already.
std::shared_ptr< Ledger const > replayTemp_
void init(int numPeers)
Start the LedgerDeltaAcquire task.
std::vector< OnDeltaDataCB > dataReadyCallbacks_
void onTimer(bool progress, ScopedLockType &peerSetLock) override
Hook called from invokeOnTimer().
std::unique_ptr< PeerSet > peerSet_
void notify(ScopedLockType &sl)
Call the OnDeltaDataCB callbacks.
std::weak_ptr< TimeoutCounter > pmDowncast() override
Return a weak pointer to this.
void addDataCallback(InboundLedger::Reason reason, OnDeltaDataCB &&cb)
Add a reason and a callback to the LedgerDeltaAcquire subtask.
void onLedgerBuilt(ScopedLockType &sl, std::optional< InboundLedger::Reason > reason={})
Process a newly built ledger, such as store it.
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
This class is an "active" object.
void setTimer(ScopedLockType &)
Schedule a call to queueJob() after mTimerInterval.
std::chrono::milliseconds timerInterval_
The minimum time to wait between calls to execute().
uint256 const hash_
The hash of the object (in practice, always a ledger) we are trying to fetch.
std::recursive_mutex mtx_
static constexpr std::size_t size()
Definition base_uint.h:526
T count(T... args)
T emplace(T... args)
T end(T... args)
T is_same_v
T lock(T... args)
auto constexpr SUB_TASK_FALLBACK_TIMEOUT
std::uint32_t constexpr MAX_QUEUED_TASKS
std::uint32_t constexpr SUB_TASK_MAX_TIMEOUTS
auto constexpr MAX_NO_FEATURE_PEER_COUNT
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
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
@ jtREPLAY_TASK
Definition Job.h:61
Information about the notional ledger backing the view.
T swap(T... args)
T unlock(T... args)