xrpld
Loading...
Searching...
No Matches
LedgerDeltaAcquire.cpp
1#include <xrpld/app/ledger/detail/LedgerDeltaAcquire.h>
2
3#include <xrpld/app/ledger/BuildLedger.h>
4#include <xrpld/app/ledger/InboundLedger.h>
5#include <xrpld/app/ledger/InboundLedgers.h>
6#include <xrpld/app/ledger/LedgerMaster.h>
7#include <xrpld/app/ledger/LedgerReplay.h>
8#include <xrpld/app/ledger/LedgerReplayer.h>
9#include <xrpld/app/ledger/detail/TimeoutCounter.h>
10#include <xrpld/app/main/Application.h>
11#include <xrpld/overlay/Peer.h>
12#include <xrpld/overlay/PeerSet.h>
13
14#include <xrpl/basics/Log.h>
15#include <xrpl/basics/base_uint.h>
16#include <xrpl/basics/contract.h>
17#include <xrpl/beast/utility/instrumentation.h>
18#include <xrpl/core/Job.h>
19#include <xrpl/core/JobQueue.h>
20#include <xrpl/ledger/ApplyView.h>
21#include <xrpl/protocol/LedgerHeader.h>
22#include <xrpl/protocol/Rules.h>
23
24#include <xrpl.pb.h>
25
26#include <cstddef>
27#include <cstdint>
28#include <map>
29#include <memory>
30#include <optional>
31#include <stdexcept>
32#include <utility>
33#include <vector>
34
35namespace xrpl {
36
38 Application& app,
39 InboundLedgers& inboundLedgers,
40 uint256 const& ledgerHash,
41 std::uint32_t ledgerSeq,
44 app,
45 ledgerHash,
46 ledger_replay_parameters::kSubTaskTimeout,
47 {.jobType = JtReplayTask,
48 .jobName = "LedReplDelta",
50 app.getJournal("LedgerReplayDelta"))
51 , inboundLedgers_(inboundLedgers)
52 , ledgerSeq_(ledgerSeq)
53 , peerSet_(std::move(peerSet))
54{
55 JLOG(journal_.trace()) << "Create " << hash_ << " Seq " << ledgerSeq;
56}
57
59{
60 JLOG(journal_.trace()) << "Destroy " << hash_;
61}
62
63void
65{
67 if (!isDone())
68 {
69 trigger(numPeers, sl);
70 setTimer(sl);
71 }
72}
73
74void
76{
77 fullLedger_ = app_.getLedgerMaster().getLedgerByHash(hash_);
78 if (fullLedger_)
79 {
80 complete_ = true;
81 JLOG(journal_.trace()) << "existing ledger " << hash_;
82 notify(sl);
83 return;
84 }
85
86 if (!fallBack_)
87 {
88 peerSet_->addPeers(
89 limit,
90 [this](auto peer) {
91 return peer->supportsFeature(ProtocolFeature::LedgerReplay) &&
92 peer->hasLedger(hash_, ledgerSeq_);
93 },
94 [this](auto peer) {
95 if (peer->supportsFeature(ProtocolFeature::LedgerReplay))
96 {
97 JLOG(journal_.trace()) << "Add a peer " << peer->id() << " for " << hash_;
98 protocol::TMReplayDeltaRequest request;
99 request.set_ledgerhash(hash_.data(), hash_.size());
100 peerSet_->sendRequest(request, peer);
101 }
102 else
103 {
105 {
106 JLOG(journal_.debug()) << "Fall back for " << hash_;
108 fallBack_ = true;
109 }
110 }
111 });
112 }
113
114 if (fallBack_)
116}
117
118void
120{
121 JLOG(journal_.trace()) << "timeouts_=" << timeouts_ << " for " << hash_;
123 {
124 failed_ = true;
125 JLOG(journal_.debug()) << "too many timeouts " << hash_;
126 notify(sl);
127 }
128 else
129 {
130 trigger(1, sl);
131 }
132}
133
139
140void
142 LedgerHeader const& info,
144{
146 JLOG(journal_.trace()) << "got data for " << hash_;
147 if (isDone())
148 return;
149
150 if (info.seq == ledgerSeq_)
151 {
152 // create a temporary ledger for building a LedgerReplay object later
153 Rules const rules{app_.config().features};
154 replayTemp_ = std::make_shared<Ledger>(info, rules, app_.getNodeFamily());
155 if (replayTemp_)
156 {
157 complete_ = true;
158 orderedTxns_ = std::move(orderedTxns);
159 JLOG(journal_.debug()) << "ready to replay " << hash_;
160 notify(sl);
161 return;
162 }
163 }
164
165 failed_ = true;
166 JLOG(journal_.error()) << "failed to create a (info only) ledger from verified data " << hash_;
167 notify(sl);
168}
169
170void
172{
174 dataReadyCallbacks_.emplace_back(std::move(cb));
175 if (!reasons_.contains(reason))
176 {
177 reasons_.emplace(reason);
178 if (fullLedger_)
179 onLedgerBuilt(sl, reason);
180 }
181
182 if (isDone())
183 {
184 JLOG(journal_.debug()) << "task added to a finished LedgerDeltaAcquire " << hash_;
185 notify(sl);
186 }
187}
188
191{
193
194 if (fullLedger_)
195 return fullLedger_;
196
197 if (failed_ || !complete_ || !replayTemp_)
198 return {};
199
200 XRPL_ASSERT(
201 parent->seq() + 1 == replayTemp_->seq(),
202 "xrpl::LedgerDeltaAcquire::tryBuild : parent sequence match");
203 XRPL_ASSERT(
204 parent->header().hash == replayTemp_->header().parentHash,
205 "xrpl::LedgerDeltaAcquire::tryBuild : parent hash match");
206 // build ledger
207 LedgerReplay const replayData(parent, replayTemp_, std::move(orderedTxns_));
209 if (fullLedger_ && fullLedger_->header().hash == hash_)
210 {
211 JLOG(journal_.info()) << "Built " << hash_;
212 onLedgerBuilt(sl);
213 return fullLedger_;
214 }
215
216 failed_ = true;
217 complete_ = false;
218 JLOG(journal_.error()) << "tryBuild failed " << hash_ << " with parent "
219 << parent->header().hash;
220 Throw<std::runtime_error>("Cannot replay ledger");
221}
222
223void
225{
226 JLOG(journal_.debug()) << "onLedgerBuilt " << hash_ << (reason ? " for a new reason" : "");
227
229 bool firstTime = true;
230 if (reason) // small chance
231 {
232 reasons.clear();
233 reasons.push_back(*reason);
234 firstTime = false;
235 }
236 app_.getJobQueue().addJob(
237 JtReplayTask, "OnLedBuilt", [=, ledger = this->fullLedger_, &app = this->app_]() {
238 for (auto reason : reasons)
239 {
240 switch (reason)
241 {
243 app.getLedgerMaster().storeLedger(ledger);
244 break;
245 default:
246 // TODO for other use cases
247 break;
248 }
249 }
250
251 if (firstTime)
252 app.getLedgerMaster().tryAdvance();
253 });
254}
255
256void
258{
259 XRPL_ASSERT(isDone(), "xrpl::LedgerDeltaAcquire::notify : is done");
262 auto const good = !failed_;
263 sl.unlock();
264
265 for (auto& cb : toCall)
266 {
267 cb(good, hash_);
268 }
269
270 sl.lock();
271}
272
273} // namespace xrpl
Manages the lifetime of inbound ledgers.
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::function< void(bool successful, uint256 const &hash)> OnDeltaDataCB
A callback used to notify that the delta's data is ready or failed.
Rules controlling protocol behavior.
Definition Rules.h:40
TimeoutCounter(Application &app, uint256 const &targetHash, std::chrono::milliseconds timeoutInterval, QueueJobParameter &&jobParameter, beast::Journal journal)
std::recursive_mutex mtx_
std::unique_lock< std::recursive_mutex > ScopedLockType
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 timerInterval_.
std::chrono::milliseconds timerInterval_
The minimum time to wait between calls to execute().
T lock(T... args)
T make_shared(T... args)
constexpr std::uint32_t kSubTaskMaxTimeouts
constexpr std::uint32_t kMaxQueuedTasks
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ JtReplayTask
Definition Job.h:47
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:28
BaseUInt< 256 > uint256
Definition base_uint.h:580
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:52
Information about the notional ledger backing the view.
T swap(T... args)
T unlock(T... args)