rippled
Loading...
Searching...
No Matches
LedgerDeltaAcquire.cpp
1#include <xrpld/app/ledger/BuildLedger.h>
2#include <xrpld/app/ledger/InboundLedger.h>
3#include <xrpld/app/ledger/LedgerReplay.h>
4#include <xrpld/app/ledger/LedgerReplayer.h>
5#include <xrpld/app/ledger/detail/LedgerDeltaAcquire.h>
6#include <xrpld/app/main/Application.h>
7#include <xrpld/overlay/PeerSet.h>
8
9#include <xrpl/core/JobQueue.h>
10
11namespace xrpl {
12
14 Application& app,
15 InboundLedgers& inboundLedgers,
16 uint256 const& ledgerHash,
17 std::uint32_t ledgerSeq,
20 app,
21 ledgerHash,
22 LedgerReplayParameters::SUB_TASK_TIMEOUT,
24 app.journal("LedgerReplayDelta"))
25 , inboundLedgers_(inboundLedgers)
26 , ledgerSeq_(ledgerSeq)
27 , peerSet_(std::move(peerSet))
28{
29 JLOG(journal_.trace()) << "Create " << hash_ << " Seq " << ledgerSeq;
30}
31
33{
34 JLOG(journal_.trace()) << "Destroy " << hash_;
35}
36
37void
39{
41 if (!isDone())
42 {
43 trigger(numPeers, sl);
44 setTimer(sl);
45 }
46}
47
48void
50{
52 if (fullLedger_)
53 {
54 complete_ = true;
55 JLOG(journal_.trace()) << "existing ledger " << hash_;
56 notify(sl);
57 return;
58 }
59
60 if (!fallBack_)
61 {
62 peerSet_->addPeers(
63 limit,
64 [this](auto peer) {
65 return peer->supportsFeature(ProtocolFeature::LedgerReplay) && peer->hasLedger(hash_, ledgerSeq_);
66 },
67 [this](auto peer) {
68 if (peer->supportsFeature(ProtocolFeature::LedgerReplay))
69 {
70 JLOG(journal_.trace()) << "Add a peer " << peer->id() << " for " << hash_;
71 protocol::TMReplayDeltaRequest request;
72 request.set_ledgerhash(hash_.data(), hash_.size());
73 peerSet_->sendRequest(request, peer);
74 }
75 else
76 {
78 {
79 JLOG(journal_.debug()) << "Fall back for " << hash_;
81 fallBack_ = true;
82 }
83 }
84 });
85 }
86
87 if (fallBack_)
89}
90
91void
93{
94 JLOG(journal_.trace()) << "mTimeouts=" << timeouts_ << " for " << hash_;
96 {
97 failed_ = true;
98 JLOG(journal_.debug()) << "too many timeouts " << hash_;
99 notify(sl);
100 }
101 else
102 {
103 trigger(1, sl);
104 }
105}
106
112
113void
115 LedgerHeader const& info,
117{
119 JLOG(journal_.trace()) << "got data for " << hash_;
120 if (isDone())
121 return;
122
123 if (info.seq == ledgerSeq_)
124 {
125 // create a temporary ledger for building a LedgerReplay object later
127 if (replayTemp_)
128 {
129 complete_ = true;
130 orderedTxns_ = std::move(orderedTxns);
131 JLOG(journal_.debug()) << "ready to replay " << hash_;
132 notify(sl);
133 return;
134 }
135 }
136
137 failed_ = true;
138 JLOG(journal_.error()) << "failed to create a (info only) ledger from verified data " << hash_;
139 notify(sl);
140}
141
142void
144{
146 dataReadyCallbacks_.emplace_back(std::move(cb));
147 if (reasons_.count(reason) == 0)
148 {
149 reasons_.emplace(reason);
150 if (fullLedger_)
151 onLedgerBuilt(sl, reason);
152 }
153
154 if (isDone())
155 {
156 JLOG(journal_.debug()) << "task added to a finished LedgerDeltaAcquire " << hash_;
157 notify(sl);
158 }
159}
160
163{
165
166 if (fullLedger_)
167 return fullLedger_;
168
169 if (failed_ || !complete_ || !replayTemp_)
170 return {};
171
172 XRPL_ASSERT(parent->seq() + 1 == replayTemp_->seq(), "xrpl::LedgerDeltaAcquire::tryBuild : parent sequence match");
173 XRPL_ASSERT(
174 parent->header().hash == replayTemp_->header().parentHash,
175 "xrpl::LedgerDeltaAcquire::tryBuild : parent hash match");
176 // build ledger
177 LedgerReplay replayData(parent, replayTemp_, std::move(orderedTxns_));
179 if (fullLedger_ && fullLedger_->header().hash == hash_)
180 {
181 JLOG(journal_.info()) << "Built " << hash_;
182 onLedgerBuilt(sl);
183 return fullLedger_;
184 }
185 else
186 {
187 failed_ = true;
188 complete_ = false;
189 JLOG(journal_.error()) << "tryBuild failed " << hash_ << " with parent " << parent->header().hash;
190 Throw<std::runtime_error>("Cannot replay ledger");
191 }
192}
193
194void
196{
197 JLOG(journal_.debug()) << "onLedgerBuilt " << hash_ << (reason ? " for a new reason" : "");
198
200 bool firstTime = true;
201 if (reason) // small chance
202 {
203 reasons.clear();
204 reasons.push_back(*reason);
205 firstTime = false;
206 }
207 app_.getJobQueue().addJob(jtREPLAY_TASK, "OnLedBuilt", [=, ledger = this->fullLedger_, &app = this->app_]() {
208 for (auto reason : reasons)
209 {
210 switch (reason)
211 {
213 app.getLedgerMaster().storeLedger(ledger);
214 break;
215 default:
216 // TODO for other use cases
217 break;
218 }
219 }
220
221 if (firstTime)
222 app.getLedgerMaster().tryAdvance();
223 });
224}
225
226void
228{
229 XRPL_ASSERT(isDone(), "xrpl::LedgerDeltaAcquire::notify : is done");
232 auto const good = !failed_;
233 sl.unlock();
234
235 for (auto& cb : toCall)
236 {
237 cb(good, hash_);
238 }
239
240 sl.lock();
241}
242
243} // namespace xrpl
T begin(T... args)
Stream error() const
Definition Journal.h:319
Stream debug() const
Definition Journal.h:301
Stream info() const
Definition Journal.h:307
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
virtual Config & config()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual Family & getNodeFamily()=0
virtual JobQueue & getJobQueue()=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:146
std::uint32_t const ledgerSeq_
void trigger(std::size_t limit, ScopedLockType &sl)
Trigger another round.
void init(int numPeers)
Start the LedgerDeltaAcquire task.
std::shared_ptr< Ledger const > fullLedger_
void onLedgerBuilt(ScopedLockType &sl, std::optional< InboundLedger::Reason > reason={})
Process a newly built ledger, such as store it.
LedgerDeltaAcquire(Application &app, InboundLedgers &inboundLedgers, uint256 const &ledgerHash, std::uint32_t ledgerSeq, std::unique_ptr< PeerSet > peerSet)
Constructor.
std::vector< OnDeltaDataCB > dataReadyCallbacks_
void processData(LedgerHeader const &info, std::map< std::uint32_t, std::shared_ptr< STTx const > > &&orderedTxns)
Process the data extracted from a peer's reply.
std::unique_ptr< PeerSet > peerSet_
std::set< InboundLedger::Reason > reasons_
void notify(ScopedLockType &sl)
Call the OnDeltaDataCB callbacks.
std::shared_ptr< Ledger const > replayTemp_
void onTimer(bool progress, ScopedLockType &peerSetLock) override
Hook called from invokeOnTimer().
std::weak_ptr< TimeoutCounter > pmDowncast() override
Return a weak pointer to this.
std::shared_ptr< Ledger const > tryBuild(std::shared_ptr< Ledger const > const &parent)
Try to build the ledger if not already.
std::map< std::uint32_t, std::shared_ptr< STTx const > > orderedTxns_
void addDataCallback(InboundLedger::Reason reason, OnDeltaDataCB &&cb)
Add a reason and a callback to the LedgerDeltaAcquire subtask.
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
This class is an "active" object.
std::recursive_mutex mtx_
uint256 const hash_
The hash of the object (in practice, always a ledger) we are trying to fetch.
beast::Journal journal_
void setTimer(ScopedLockType &)
Schedule a call to queueJob() after mTimerInterval.
std::chrono::milliseconds timerInterval_
The minimum time to wait between calls to execute().
pointer data()
Definition base_uint.h:102
static constexpr std::size_t size()
Definition base_uint.h:495
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
auto constexpr MAX_NO_FEATURE_PEER_COUNT
std::uint32_t constexpr MAX_QUEUED_TASKS
std::uint32_t constexpr SUB_TASK_MAX_TIMEOUTS
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
@ jtREPLAY_TASK
Definition Job.h:41
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:12
Information about the notional ledger backing the view.
T swap(T... args)
T unlock(T... args)