xrpld
Loading...
Searching...
No Matches
LedgerReplayMsgHandler.cpp
1#include <xrpld/app/ledger/detail/LedgerReplayMsgHandler.h>
2
3#include <xrpld/app/ledger/LedgerMaster.h>
4#include <xrpld/app/ledger/LedgerReplayer.h>
5#include <xrpld/app/main/Application.h>
6
7#include <xrpl/basics/Blob.h>
8#include <xrpl/basics/Log.h>
9#include <xrpl/basics/Slice.h>
10#include <xrpl/basics/base_uint.h>
11#include <xrpl/basics/safe_cast.h>
12#include <xrpl/protocol/Indexes.h>
13#include <xrpl/protocol/LedgerHeader.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/STObject.h>
16#include <xrpl/protocol/STTx.h>
17#include <xrpl/protocol/Serializer.h>
18#include <xrpl/shamap/SHAMapItem.h>
19#include <xrpl/shamap/SHAMapMissingNode.h>
20#include <xrpl/shamap/SHAMapTreeNode.h>
21
22#include <boost/smart_ptr/intrusive_ptr.hpp>
23
24#include <xrpl.pb.h>
25
26#include <cstdint>
27#include <exception>
28#include <map>
29#include <memory>
30#include <optional>
31#include <utility>
32#include <vector>
33
34namespace xrpl {
36 : app_(app), replayer_(replayer), journal_(app.getJournal("LedgerReplayMsgHandler"))
37{
38}
39
40protocol::TMProofPathResponse
43{
44 protocol::TMProofPathRequest& packet = *msg;
45 protocol::TMProofPathResponse reply;
46
47 if (!packet.has_key() || !packet.has_ledgerhash() || !packet.has_type() ||
48 packet.ledgerhash().size() != uint256::size() || packet.key().size() != uint256::size() ||
49 !protocol::TMLedgerMapType_IsValid(packet.type()))
50 {
51 JLOG(journal_.debug()) << "getProofPath: Invalid request";
52 reply.set_error(protocol::TMReplyError::reBAD_REQUEST);
53 return reply;
54 }
55 reply.set_key(packet.key());
56 reply.set_ledgerhash(packet.ledgerhash());
57 reply.set_type(packet.type());
58
59 uint256 const key = uint256::fromRaw(packet.key());
60 uint256 const ledgerHash = uint256::fromRaw(packet.ledgerhash());
61 auto ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash);
62 if (!ledger)
63 {
64 JLOG(journal_.debug()) << "getProofPath: Don't have ledger " << ledgerHash;
65 reply.set_error(protocol::TMReplyError::reNO_LEDGER);
66 return reply;
67 }
68
69 auto const path = [&]() -> std::optional<std::vector<Blob>> {
70 switch (packet.type())
71 {
72 case protocol::lmACCOUNT_STATE:
73 return ledger->stateMap().getProofPath(key);
74 case protocol::lmTRANSACTION:
75 return ledger->txMap().getProofPath(key);
76 default:
77 // should not be here
78 // because already tested with TMLedgerMapType_IsValid()
79 return {};
80 }
81 }();
82
83 if (!path)
84 {
85 JLOG(journal_.debug()) << "getProofPath: Don't have the node " << key << " of ledger "
86 << ledgerHash;
87 reply.set_error(protocol::TMReplyError::reNO_NODE);
88 return reply;
89 }
90
91 // pack header
92 Serializer nData(128);
93 addRaw(ledger->header(), nData);
94 reply.set_ledgerheader(nData.getDataPtr(), nData.getLength());
95 // pack path
96 for (auto const& b : *path)
97 reply.add_path(b.data(), b.size());
98
99 JLOG(journal_.debug()) << "getProofPath for the node " << key << " of ledger " << ledgerHash
100 << " path length " << path->size();
101 return reply;
102}
103
107{
108 protocol::TMProofPathResponse const& reply = *msg;
109 if (reply.has_error())
110 {
111 JLOG(journal_.debug()) << "ProofPathResponse: peer reported error";
113 }
114 if (!reply.has_key() || !reply.has_ledgerhash() || !reply.has_type() ||
115 !reply.has_ledgerheader() || reply.path_size() == 0 ||
116 reply.ledgerhash().size() != uint256::size() || reply.key().size() != uint256::size())
117 {
118 JLOG(journal_.debug()) << "ProofPathResponse: malformed (missing or wrong-size fields)";
120 }
121
122 if (reply.type() != protocol::lmACCOUNT_STATE)
123 {
124 JLOG(journal_.debug()) << "ProofPathResponse: malformed (unsupported map type)";
126 }
127
128 // deserialize the header
129 LedgerHeader info;
130 try
131 {
132 info = deserializeHeader(makeSlice(reply.ledgerheader()));
133 }
134 catch (std::exception const& e)
135 {
136 JLOG(journal_.debug()) << "ProofPathResponse: malformed header (" << e.what() << ")";
138 }
139 uint256 const replyHash = uint256::fromRaw(reply.ledgerhash());
140 if (calculateLedgerHash(info) != replyHash)
141 {
142 JLOG(journal_.debug()) << "ProofPathResponse: malformed (hash mismatch)";
144 }
145 info.hash = replyHash;
146
147 uint256 const key = uint256::fromRaw(reply.key());
148 if (key != keylet::skip().key)
149 {
150 JLOG(journal_.debug()) << "ProofPathResponse: malformed (unexpected key " << key << ")";
152 }
153
154 // verify the skip list
156 path.reserve(reply.path_size());
157 for (int i = 0; i < reply.path_size(); ++i)
158 {
159 path.emplace_back(reply.path(i).begin(), reply.path(i).end());
160 }
161
163 {
164 JLOG(journal_.debug()) << "ProofPathResponse: malformed (proof path verify failed)";
166 }
167
168 // deserialize the SHAMapItem
170 try
171 {
173 }
174 catch (std::exception const& e)
175 {
176 JLOG(journal_.debug()) << "ProofPathResponse: malformed SHAMap node (" << e.what() << ")";
178 }
179 if (!node || !node->isLeaf())
180 {
181 JLOG(journal_.debug()) << "ProofPathResponse: malformed (not a leaf node)";
183 }
184
185 if (auto item = safeDowncast<SHAMapLeafNode*>(node.get())->peekItem())
186 {
187 replayer_.gotSkipList(info, item);
188 return ReplayMsgStatus::Ok;
189 }
190
191 JLOG(journal_.debug()) << "ProofPathResponse: malformed (no SHAMapItem)";
193}
194
195protocol::TMReplayDeltaResponse
198{
199 protocol::TMReplayDeltaRequest const& packet = *msg;
200 protocol::TMReplayDeltaResponse reply;
201
202 if (!packet.has_ledgerhash() || packet.ledgerhash().size() != uint256::size())
203 {
204 JLOG(journal_.debug()) << "getReplayDelta: Invalid request";
205 reply.set_error(protocol::TMReplyError::reBAD_REQUEST);
206 return reply;
207 }
208 reply.set_ledgerhash(packet.ledgerhash());
209
210 uint256 const ledgerHash = uint256::fromRaw(packet.ledgerhash());
211 auto ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash);
212 if (!ledger || !ledger->isImmutable())
213 {
214 JLOG(journal_.debug()) << "getReplayDelta: Don't have ledger " << ledgerHash;
215 reply.set_error(protocol::TMReplyError::reNO_LEDGER);
216 return reply;
217 }
218
219 // pack header
220 Serializer nData(128);
221 addRaw(ledger->header(), nData);
222 reply.set_ledgerheader(nData.getDataPtr(), nData.getLength());
223 // pack transactions
224 auto const& txMap = ledger->txMap();
225 txMap.visitLeaves([&](boost::intrusive_ptr<SHAMapItem const> const& txNode) {
226 reply.add_transaction(txNode->data(), txNode->size());
227 });
228
229 JLOG(journal_.debug()) << "getReplayDelta for ledger " << ledgerHash << " txMap hash "
230 << txMap.getHash().asUInt256();
231 return reply;
232}
233
237{
238 protocol::TMReplayDeltaResponse const& reply = *msg;
239 if (reply.has_error())
240 {
241 JLOG(journal_.debug()) << "ReplayDeltaResponse: peer reported error";
243 }
244 if (!reply.has_ledgerheader() || !reply.has_ledgerhash() ||
245 reply.ledgerhash().size() != uint256::size())
246 {
247 JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (missing or wrong-size fields)";
249 }
250
251 LedgerHeader info;
252 try
253 {
254 info = deserializeHeader(makeSlice(reply.ledgerheader()));
255 }
256 catch (std::exception const& e)
257 {
258 JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed header (" << e.what() << ")";
260 }
261 uint256 const replyHash = uint256::fromRaw(reply.ledgerhash());
262 if (calculateLedgerHash(info) != replyHash)
263 {
264 JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (hash mismatch)";
266 }
267 info.hash = replyHash;
268
269 auto numTxns = reply.transaction_size();
271 SHAMap txMap(SHAMapType::TRANSACTION, app_.getNodeFamily());
272 try
273 {
274 for (int i = 0; i < numTxns; ++i)
275 {
276 // deserialize:
277 // -- TxShaMapItem for building a ShaMap for verification
278 // -- Tx
279 // -- TxMetaData for Tx ordering
280 Serializer const shaMapItemData(
281 reply.transaction(i).data(), reply.transaction(i).size());
282
283 SerialIter txMetaSit(makeSlice(reply.transaction(i)));
284 SerialIter txSit(txMetaSit.getSlice(txMetaSit.getVLDataLength()));
285 SerialIter metaSit(txMetaSit.getSlice(txMetaSit.getVLDataLength()));
286
287 auto tx = std::make_shared<STTx const>(txSit);
288 if (!tx)
289 {
290 JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (tx deserialize)";
292 }
293 auto tid = tx->getTransactionID();
294 STObject meta(metaSit, sfMetadata);
295 orderedTxns.emplace(meta[sfTransactionIndex], std::move(tx));
296
297 if (!txMap.addGiveItem(
299 {
300 JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (tx map add)";
302 }
303 }
304 }
305 catch (std::exception const& e)
306 {
307 JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed transactions (" << e.what()
308 << ")";
310 }
311
312 if (txMap.getHash().asUInt256() != info.txHash)
313 {
314 JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (transactions verify failed)";
316 }
317
318 replayer_.gotReplayDelta(info, std::move(orderedTxns));
319 return ReplayMsgStatus::Ok;
320}
321
322} // namespace xrpl
static BaseUInt fromRaw(Container const &c)
Definition base_uint.h:302
static constexpr std::size_t size()
Definition base_uint.h:548
protocol::TMProofPathResponse processProofPathRequest(std::shared_ptr< protocol::TMProofPathRequest > const &msg)
Process TMProofPathRequest and return TMProofPathResponse.
LedgerReplayMsgHandler(Application &app, LedgerReplayer &replayer)
ReplayMsgStatus processReplayDeltaResponse(std::shared_ptr< protocol::TMReplayDeltaResponse > const &msg)
Process TMReplayDeltaResponse.
ReplayMsgStatus processProofPathResponse(std::shared_ptr< protocol::TMProofPathResponse > const &msg)
Process TMProofPathResponse.
protocol::TMReplayDeltaResponse processReplayDeltaRequest(std::shared_ptr< protocol::TMReplayDeltaRequest > const &msg)
Process TMReplayDeltaRequest and return TMReplayDeltaResponse.
Manages the lifetime of ledger replay tasks.
uint256 const & asUInt256() const
Definition SHAMapHash.h:26
static SHAMapTreeNodePtr makeFromWire(Slice rawNode)
static bool verifyProofPath(uint256 const &rootHash, uint256 const &key, std::vector< Blob > const &path)
Verify the proof path.
bool addGiveItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
SHAMapHash getHash() const
Slice getSlice(std::size_t bytes)
void const * getDataPtr() const
Definition Serializer.h:198
int getLength() const
Definition Serializer.h:208
Slice slice() const noexcept
Definition Serializer.h:45
T * get() const
Get the raw pointer.
T emplace(T... args)
T make_shared(T... args)
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:210
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
intr_ptr::SharedPtr< SHAMapTreeNode > SHAMapTreeNodePtr
Dest safeDowncast(Src *s) noexcept
Definition safe_cast.h:84
LedgerHeader deserializeHeader(Slice data, bool hasHash=false)
Deserialize a ledger header from a byte array.
uint256 calculateLedgerHash(LedgerHeader const &info)
Calculate the hash of a ledger header.
Slice makeSlice(std::array< T, N > const &a)
Definition Slice.h:228
boost::intrusive_ptr< SHAMapItem > makeShamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:148
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
ReplayMsgStatus
Outcome of processing an incoming ledger-replay response.
@ Malformed
Protocol-level violation; no honest peer would produce this.
@ BadData
Peer reported has_error() (legitimate "cannot fulfill" signal).
BaseUInt< 256 > uint256
Definition base_uint.h:580
Information about the notional ledger backing the view.
T what(T... args)