rippled
Loading...
Searching...
No Matches
LedgerReplayMsgHandler.cpp
1#include <xrpld/app/ledger/LedgerMaster.h>
2#include <xrpld/app/ledger/LedgerReplayer.h>
3#include <xrpld/app/ledger/detail/LedgerReplayMsgHandler.h>
4#include <xrpld/app/main/Application.h>
5
6#include <xrpl/protocol/LedgerHeader.h>
7
8#include <memory>
9
10namespace ripple {
12 Application& app,
13 LedgerReplayer& replayer)
14 : app_(app)
15 , replayer_(replayer)
16 , journal_(app.journal("LedgerReplayMsgHandler"))
17{
18}
19
20protocol::TMProofPathResponse
23{
24 protocol::TMProofPathRequest& packet = *msg;
25 protocol::TMProofPathResponse reply;
26
27 if (!packet.has_key() || !packet.has_ledgerhash() || !packet.has_type() ||
28 packet.ledgerhash().size() != uint256::size() ||
29 packet.key().size() != uint256::size() ||
30 !protocol::TMLedgerMapType_IsValid(packet.type()))
31 {
32 JLOG(journal_.debug()) << "getProofPath: Invalid request";
33 reply.set_error(protocol::TMReplyError::reBAD_REQUEST);
34 return reply;
35 }
36 reply.set_key(packet.key());
37 reply.set_ledgerhash(packet.ledgerhash());
38 reply.set_type(packet.type());
39
40 uint256 const key(packet.key());
41 uint256 const ledgerHash(packet.ledgerhash());
42 auto ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash);
43 if (!ledger)
44 {
45 JLOG(journal_.debug())
46 << "getProofPath: Don't have ledger " << ledgerHash;
47 reply.set_error(protocol::TMReplyError::reNO_LEDGER);
48 return reply;
49 }
50
51 auto const path = [&]() -> std::optional<std::vector<Blob>> {
52 switch (packet.type())
53 {
54 case protocol::lmACCOUNT_STATE:
55 return ledger->stateMap().getProofPath(key);
56 case protocol::lmTRANASCTION:
57 return ledger->txMap().getProofPath(key);
58 default:
59 // should not be here
60 // because already tested with TMLedgerMapType_IsValid()
61 return {};
62 }
63 }();
64
65 if (!path)
66 {
67 JLOG(journal_.debug()) << "getProofPath: Don't have the node " << key
68 << " of ledger " << ledgerHash;
69 reply.set_error(protocol::TMReplyError::reNO_NODE);
70 return reply;
71 }
72
73 // pack header
74 Serializer nData(128);
75 addRaw(ledger->info(), nData);
76 reply.set_ledgerheader(nData.getDataPtr(), nData.getLength());
77 // pack path
78 for (auto const& b : *path)
79 reply.add_path(b.data(), b.size());
80
81 JLOG(journal_.debug()) << "getProofPath for the node " << key
82 << " of ledger " << ledgerHash << " path length "
83 << path->size();
84 return reply;
85}
86
87bool
90{
91 protocol::TMProofPathResponse& reply = *msg;
92 if (reply.has_error() || !reply.has_key() || !reply.has_ledgerhash() ||
93 !reply.has_type() || !reply.has_ledgerheader() ||
94 reply.path_size() == 0)
95 {
96 JLOG(journal_.debug()) << "Bad message: Error reply";
97 return false;
98 }
99
100 if (reply.type() != protocol::lmACCOUNT_STATE)
101 {
102 JLOG(journal_.debug())
103 << "Bad message: we only support the state ShaMap for now";
104 return false;
105 }
106
107 // deserialize the header
108 auto info = deserializeHeader(
109 {reply.ledgerheader().data(), reply.ledgerheader().size()});
110 uint256 replyHash(reply.ledgerhash());
111 if (calculateLedgerHash(info) != replyHash)
112 {
113 JLOG(journal_.debug()) << "Bad message: Hash mismatch";
114 return false;
115 }
116 info.hash = replyHash;
117
118 uint256 key(reply.key());
119 if (key != keylet::skip().key)
120 {
121 JLOG(journal_.debug())
122 << "Bad message: we only support the short skip list for now. "
123 "Key in reply "
124 << key;
125 return false;
126 }
127
128 // verify the skip list
130 path.reserve(reply.path_size());
131 for (int i = 0; i < reply.path_size(); ++i)
132 {
133 path.emplace_back(reply.path(i).begin(), reply.path(i).end());
134 }
135
136 if (!SHAMap::verifyProofPath(info.accountHash, key, path))
137 {
138 JLOG(journal_.debug()) << "Bad message: Proof path verify failed";
139 return false;
140 }
141
142 // deserialize the SHAMapItem
143 auto node = SHAMapTreeNode::makeFromWire(makeSlice(path.front()));
144 if (!node || !node->isLeaf())
145 {
146 JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
147 return false;
148 }
149
150 if (auto item = static_cast<SHAMapLeafNode*>(node.get())->peekItem())
151 {
152 replayer_.gotSkipList(info, item);
153 return true;
154 }
155
156 JLOG(journal_.debug()) << "Bad message: Cannot get ShaMapItem";
157 return false;
158}
159
160protocol::TMReplayDeltaResponse
163{
164 protocol::TMReplayDeltaRequest& packet = *msg;
165 protocol::TMReplayDeltaResponse reply;
166
167 if (!packet.has_ledgerhash() ||
168 packet.ledgerhash().size() != uint256::size())
169 {
170 JLOG(journal_.debug()) << "getReplayDelta: Invalid request";
171 reply.set_error(protocol::TMReplyError::reBAD_REQUEST);
172 return reply;
173 }
174 reply.set_ledgerhash(packet.ledgerhash());
175
176 uint256 const ledgerHash{packet.ledgerhash()};
177 auto ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash);
178 if (!ledger || !ledger->isImmutable())
179 {
180 JLOG(journal_.debug())
181 << "getReplayDelta: Don't have ledger " << ledgerHash;
182 reply.set_error(protocol::TMReplyError::reNO_LEDGER);
183 return reply;
184 }
185
186 // pack header
187 Serializer nData(128);
188 addRaw(ledger->info(), nData);
189 reply.set_ledgerheader(nData.getDataPtr(), nData.getLength());
190 // pack transactions
191 auto const& txMap = ledger->txMap();
192 txMap.visitLeaves(
193 [&](boost::intrusive_ptr<SHAMapItem const> const& txNode) {
194 reply.add_transaction(txNode->data(), txNode->size());
195 });
196
197 JLOG(journal_.debug()) << "getReplayDelta for ledger " << ledgerHash
198 << " txMap hash " << txMap.getHash().as_uint256();
199 return reply;
200}
201
202bool
205{
206 protocol::TMReplayDeltaResponse& reply = *msg;
207 if (reply.has_error() || !reply.has_ledgerheader())
208 {
209 JLOG(journal_.debug()) << "Bad message: Error reply";
210 return false;
211 }
212
213 auto info = deserializeHeader(
214 {reply.ledgerheader().data(), reply.ledgerheader().size()});
215 uint256 replyHash(reply.ledgerhash());
216 if (calculateLedgerHash(info) != replyHash)
217 {
218 JLOG(journal_.debug()) << "Bad message: Hash mismatch";
219 return false;
220 }
221 info.hash = replyHash;
222
223 auto numTxns = reply.transaction_size();
226 try
227 {
228 for (int i = 0; i < numTxns; ++i)
229 {
230 // deserialize:
231 // -- TxShaMapItem for building a ShaMap for verification
232 // -- Tx
233 // -- TxMetaData for Tx ordering
234 Serializer shaMapItemData(
235 reply.transaction(i).data(), reply.transaction(i).size());
236
237 SerialIter txMetaSit(makeSlice(reply.transaction(i)));
238 SerialIter txSit(txMetaSit.getSlice(txMetaSit.getVLDataLength()));
239 SerialIter metaSit(txMetaSit.getSlice(txMetaSit.getVLDataLength()));
240
241 auto tx = std::make_shared<STTx const>(txSit);
242 if (!tx)
243 {
244 JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
245 return false;
246 }
247 auto tid = tx->getTransactionID();
248 STObject meta(metaSit, sfMetadata);
249 orderedTxns.emplace(meta[sfTransactionIndex], std::move(tx));
250
251 if (!txMap.addGiveItem(
253 make_shamapitem(tid, shaMapItemData.slice())))
254 {
255 JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
256 return false;
257 }
258 }
259 }
260 catch (std::exception const&)
261 {
262 JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
263 return false;
264 }
265
266 if (txMap.getHash().as_uint256() != info.txHash)
267 {
268 JLOG(journal_.debug()) << "Bad message: Transactions verify failed";
269 return false;
270 }
271
272 replayer_.gotReplayDelta(info, std::move(orderedTxns));
273 return true;
274}
275
276} // namespace ripple
Stream debug() const
Definition Journal.h:309
virtual Family & getNodeFamily()=0
virtual LedgerMaster & getLedgerMaster()=0
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
protocol::TMReplayDeltaResponse processReplayDeltaRequest(std::shared_ptr< protocol::TMReplayDeltaRequest > const &msg)
Process TMReplayDeltaRequest and return TMReplayDeltaResponse.
bool processProofPathResponse(std::shared_ptr< protocol::TMProofPathResponse > const &msg)
Process TMProofPathResponse.
bool processReplayDeltaResponse(std::shared_ptr< protocol::TMReplayDeltaResponse > const &msg)
Process TMReplayDeltaResponse.
protocol::TMProofPathResponse processProofPathRequest(std::shared_ptr< protocol::TMProofPathRequest > const &msg)
Process TMProofPathRequest and return TMProofPathResponse.
LedgerReplayMsgHandler(Application &app, LedgerReplayer &replayer)
Manages the lifetime of ledger replay tasks.
void gotReplayDelta(LedgerInfo const &info, std::map< std::uint32_t, std::shared_ptr< STTx const > > &&txns)
Process a ledger delta (extracted from a TMReplayDeltaResponse message)
void gotSkipList(LedgerInfo const &info, boost::intrusive_ptr< SHAMapItem const > const &data)
Process a skip list (extracted from a TMProofPathResponse message)
uint256 const & as_uint256() const
Definition SHAMapHash.h:25
boost::intrusive_ptr< SHAMapItem const > const & peekItem() const
static intr_ptr::SharedPtr< SHAMapTreeNode > makeFromWire(Slice rawNode)
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition SHAMap.h:78
bool addGiveItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition SHAMap.cpp:784
SHAMapHash getHash() const
Definition SHAMap.cpp:871
static bool verifyProofPath(uint256 const &rootHash, uint256 const &key, std::vector< Blob > const &path)
Verify the proof path.
Slice getSlice(std::size_t bytes)
Slice slice() const noexcept
Definition Serializer.h:47
int getLength() const
Definition Serializer.h:214
void const * getDataPtr() const
Definition Serializer.h:204
static constexpr std::size_t size()
Definition base_uint.h:507
T emplace(T... args)
T is_same_v
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition Indexes.cpp:177
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
uint256 calculateLedgerHash(LedgerInfo const &info)
Definition Ledger.cpp:35
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:225
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition SHAMapItem.h:142
@ txNode
transaction plus metadata
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
LedgerHeader deserializeHeader(Slice data, bool hasHash=false)
Deserialize a ledger header from a byte array.