1#include <xrpld/app/ledger/detail/LedgerReplayMsgHandler.h>
3#include <xrpld/app/ledger/LedgerMaster.h>
4#include <xrpld/app/ledger/LedgerReplayer.h>
5#include <xrpld/app/main/Application.h>
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>
22#include <boost/smart_ptr/intrusive_ptr.hpp>
40protocol::TMProofPathResponse
44 protocol::TMProofPathRequest& packet = *msg;
45 protocol::TMProofPathResponse reply;
47 if (!packet.has_key() || !packet.has_ledgerhash() || !packet.has_type() ||
49 !protocol::TMLedgerMapType_IsValid(packet.type()))
51 JLOG(
journal_.debug()) <<
"getProofPath: Invalid request";
52 reply.set_error(protocol::TMReplyError::reBAD_REQUEST);
55 reply.set_key(packet.key());
56 reply.set_ledgerhash(packet.ledgerhash());
57 reply.set_type(packet.type());
61 auto ledger =
app_.getLedgerMaster().getLedgerByHash(ledgerHash);
64 JLOG(
journal_.debug()) <<
"getProofPath: Don't have ledger " << ledgerHash;
65 reply.set_error(protocol::TMReplyError::reNO_LEDGER);
70 switch (packet.type())
72 case protocol::lmACCOUNT_STATE:
73 return ledger->stateMap().getProofPath(key);
74 case protocol::lmTRANSACTION:
75 return ledger->txMap().getProofPath(key);
85 JLOG(
journal_.debug()) <<
"getProofPath: Don't have the node " << key <<
" of ledger "
87 reply.set_error(protocol::TMReplyError::reNO_NODE);
93 addRaw(ledger->header(), nData);
96 for (
auto const& b : *
path)
97 reply.add_path(b.data(), b.size());
99 JLOG(
journal_.debug()) <<
"getProofPath for the node " << key <<
" of ledger " << ledgerHash
100 <<
" path length " <<
path->size();
108 protocol::TMProofPathResponse
const& reply = *msg;
109 if (reply.has_error() || !reply.has_key() || !reply.has_ledgerhash() || !reply.has_type() ||
110 !reply.has_ledgerheader() || reply.path_size() == 0 ||
113 JLOG(
journal_.debug()) <<
"Bad message: Error reply";
117 if (reply.type() != protocol::lmACCOUNT_STATE)
119 JLOG(
journal_.debug()) <<
"Bad message: we only support the state ShaMap for now";
124 auto info =
deserializeHeader({reply.ledgerheader().data(), reply.ledgerheader().size()});
128 JLOG(
journal_.debug()) <<
"Bad message: Hash mismatch";
131 info.hash = replyHash;
136 JLOG(
journal_.debug()) <<
"Bad message: we only support the short skip list for now. "
144 path.reserve(reply.path_size());
145 for (
int i = 0; i < reply.path_size(); ++i)
147 path.emplace_back(reply.path(i).begin(), reply.path(i).end());
152 JLOG(
journal_.debug()) <<
"Bad message: Proof path verify failed";
158 if (!node || !node->isLeaf())
160 JLOG(
journal_.debug()) <<
"Bad message: Cannot deserialize";
170 JLOG(
journal_.debug()) <<
"Bad message: Cannot get ShaMapItem";
174protocol::TMReplayDeltaResponse
178 protocol::TMReplayDeltaRequest
const& packet = *msg;
179 protocol::TMReplayDeltaResponse reply;
181 if (!packet.has_ledgerhash() || packet.ledgerhash().size() !=
uint256::size())
183 JLOG(
journal_.debug()) <<
"getReplayDelta: Invalid request";
184 reply.set_error(protocol::TMReplyError::reBAD_REQUEST);
187 reply.set_ledgerhash(packet.ledgerhash());
190 auto ledger =
app_.getLedgerMaster().getLedgerByHash(ledgerHash);
191 if (!ledger || !ledger->isImmutable())
193 JLOG(
journal_.debug()) <<
"getReplayDelta: Don't have ledger " << ledgerHash;
194 reply.set_error(protocol::TMReplyError::reNO_LEDGER);
200 addRaw(ledger->header(), nData);
203 auto const& txMap = ledger->txMap();
204 txMap.visitLeaves([&](boost::intrusive_ptr<SHAMapItem const>
const& txNode) {
205 reply.add_transaction(txNode->data(), txNode->size());
208 JLOG(
journal_.debug()) <<
"getReplayDelta for ledger " << ledgerHash <<
" txMap hash "
209 << txMap.getHash().asUInt256();
217 protocol::TMReplayDeltaResponse
const& reply = *msg;
218 if (reply.has_error() || !reply.has_ledgerheader() || !reply.has_ledgerhash() ||
221 JLOG(
journal_.debug()) <<
"Bad message: Error reply";
225 auto info =
deserializeHeader({reply.ledgerheader().data(), reply.ledgerheader().size()});
229 JLOG(
journal_.debug()) <<
"Bad message: Hash mismatch";
232 info.hash = replyHash;
234 auto numTxns = reply.transaction_size();
239 for (
int i = 0; i < numTxns; ++i)
246 reply.transaction(i).data(), reply.transaction(i).size());
255 JLOG(
journal_.debug()) <<
"Bad message: Cannot deserialize";
258 auto tid = tx->getTransactionID();
260 orderedTxns.
emplace(meta[sfTransactionIndex], std::move(tx));
265 JLOG(
journal_.debug()) <<
"Bad message: Cannot deserialize";
272 JLOG(
journal_.debug()) <<
"Bad message: Cannot deserialize";
278 JLOG(
journal_.debug()) <<
"Bad message: Transactions verify failed";
282 replayer_.gotReplayDelta(info, std::move(orderedTxns));
static BaseUInt fromRaw(Container const &c)
static constexpr std::size_t size()
bool processProofPathResponse(std::shared_ptr< protocol::TMProofPathResponse > const &msg)
Process TMProofPathResponse.
protocol::TMProofPathResponse processProofPathRequest(std::shared_ptr< protocol::TMProofPathRequest > const &msg)
Process TMProofPathRequest and return TMProofPathResponse.
LedgerReplayMsgHandler(Application &app, LedgerReplayer &replayer)
LedgerReplayer & replayer_
bool processReplayDeltaResponse(std::shared_ptr< protocol::TMReplayDeltaResponse > const &msg)
Process TMReplayDeltaResponse.
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
static SHAMapTreeNodePtr makeFromWire(Slice rawNode)
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
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
Slice slice() const noexcept
Keylet const & skip() noexcept
The index of the "short" skip list.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Dest safeDowncast(Src *s) noexcept
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.
boost::intrusive_ptr< SHAMapItem > makeShamapitem(uint256 const &tag, Slice data)
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
std::enable_if_t< std::is_same_v< T, char >||std::is_same_v< T, unsigned char >, Slice > makeSlice(std::array< T, N > const &a)