rippled
LedgerReplayMsgHandler.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2020 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/ledger/LedgerMaster.h>
21 #include <ripple/app/ledger/LedgerReplayer.h>
22 #include <ripple/app/ledger/impl/LedgerReplayMsgHandler.h>
23 #include <ripple/app/main/Application.h>
24 #include <ripple/protocol/LedgerHeader.h>
25 
26 #include <memory>
27 
28 namespace ripple {
30  Application& app,
31  LedgerReplayer& replayer)
32  : app_(app)
33  , replayer_(replayer)
34  , journal_(app.journal("LedgerReplayMsgHandler"))
35 {
36 }
37 
38 protocol::TMProofPathResponse
41 {
42  protocol::TMProofPathRequest& packet = *msg;
43  protocol::TMProofPathResponse reply;
44 
45  if (!packet.has_key() || !packet.has_ledgerhash() || !packet.has_type() ||
46  packet.ledgerhash().size() != uint256::size() ||
47  packet.key().size() != uint256::size() ||
48  !protocol::TMLedgerMapType_IsValid(packet.type()))
49  {
50  JLOG(journal_.debug()) << "getProofPath: Invalid request";
51  reply.set_error(protocol::TMReplyError::reBAD_REQUEST);
52  return reply;
53  }
54  reply.set_key(packet.key());
55  reply.set_ledgerhash(packet.ledgerhash());
56  reply.set_type(packet.type());
57 
58  uint256 const key(packet.key());
59  uint256 const ledgerHash(packet.ledgerhash());
60  auto ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash);
61  if (!ledger)
62  {
63  JLOG(journal_.debug())
64  << "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::lmTRANASCTION:
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
86  << " of ledger " << ledgerHash;
87  reply.set_error(protocol::TMReplyError::reNO_NODE);
88  return reply;
89  }
90 
91  // pack header
92  Serializer nData(128);
93  addRaw(ledger->info(), 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
100  << " of ledger " << ledgerHash << " path length "
101  << path->size();
102  return reply;
103 }
104 
105 bool
108 {
109  protocol::TMProofPathResponse& reply = *msg;
110  if (reply.has_error() || !reply.has_key() || !reply.has_ledgerhash() ||
111  !reply.has_type() || !reply.has_ledgerheader() ||
112  reply.path_size() == 0)
113  {
114  JLOG(journal_.debug()) << "Bad message: Error reply";
115  return false;
116  }
117 
118  if (reply.type() != protocol::lmACCOUNT_STATE)
119  {
120  JLOG(journal_.debug())
121  << "Bad message: we only support the state ShaMap for now";
122  return false;
123  }
124 
125  // deserialize the header
126  auto info = deserializeHeader(
127  {reply.ledgerheader().data(), reply.ledgerheader().size()});
128  uint256 replyHash(reply.ledgerhash());
129  if (calculateLedgerHash(info) != replyHash)
130  {
131  JLOG(journal_.debug()) << "Bad message: Hash mismatch";
132  return false;
133  }
134  info.hash = replyHash;
135 
136  uint256 key(reply.key());
137  if (key != keylet::skip().key)
138  {
139  JLOG(journal_.debug())
140  << "Bad message: we only support the short skip list for now. "
141  "Key in reply "
142  << key;
143  return false;
144  }
145 
146  // verify the skip list
147  std::vector<Blob> path;
148  path.reserve(reply.path_size());
149  for (int i = 0; i < reply.path_size(); ++i)
150  {
151  path.emplace_back(reply.path(i).begin(), reply.path(i).end());
152  }
153 
154  if (!SHAMap::verifyProofPath(info.accountHash, key, path))
155  {
156  JLOG(journal_.debug()) << "Bad message: Proof path verify failed";
157  return false;
158  }
159 
160  // deserialize the SHAMapItem
161  auto node = SHAMapTreeNode::makeFromWire(makeSlice(path.front()));
162  if (!node || !node->isLeaf())
163  {
164  JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
165  return false;
166  }
167 
168  if (auto item = static_cast<SHAMapLeafNode*>(node.get())->peekItem())
169  {
170  replayer_.gotSkipList(info, item);
171  return true;
172  }
173 
174  JLOG(journal_.debug()) << "Bad message: Cannot get ShaMapItem";
175  return false;
176 }
177 
178 protocol::TMReplayDeltaResponse
181 {
182  protocol::TMReplayDeltaRequest& packet = *msg;
183  protocol::TMReplayDeltaResponse reply;
184 
185  if (!packet.has_ledgerhash() ||
186  packet.ledgerhash().size() != uint256::size())
187  {
188  JLOG(journal_.debug()) << "getReplayDelta: Invalid request";
189  reply.set_error(protocol::TMReplyError::reBAD_REQUEST);
190  return reply;
191  }
192  reply.set_ledgerhash(packet.ledgerhash());
193 
194  uint256 const ledgerHash{packet.ledgerhash()};
195  auto ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash);
196  if (!ledger || !ledger->isImmutable())
197  {
198  JLOG(journal_.debug())
199  << "getReplayDelta: Don't have ledger " << ledgerHash;
200  reply.set_error(protocol::TMReplyError::reNO_LEDGER);
201  return reply;
202  }
203 
204  // pack header
205  Serializer nData(128);
206  addRaw(ledger->info(), nData);
207  reply.set_ledgerheader(nData.getDataPtr(), nData.getLength());
208  // pack transactions
209  auto const& txMap = ledger->txMap();
210  txMap.visitLeaves(
211  [&](boost::intrusive_ptr<SHAMapItem const> const& txNode) {
212  reply.add_transaction(txNode->data(), txNode->size());
213  });
214 
215  JLOG(journal_.debug()) << "getReplayDelta for ledger " << ledgerHash
216  << " txMap hash " << txMap.getHash().as_uint256();
217  return reply;
218 }
219 
220 bool
223 {
224  protocol::TMReplayDeltaResponse& reply = *msg;
225  if (reply.has_error() || !reply.has_ledgerheader())
226  {
227  JLOG(journal_.debug()) << "Bad message: Error reply";
228  return false;
229  }
230 
231  auto info = deserializeHeader(
232  {reply.ledgerheader().data(), reply.ledgerheader().size()});
233  uint256 replyHash(reply.ledgerhash());
234  if (calculateLedgerHash(info) != replyHash)
235  {
236  JLOG(journal_.debug()) << "Bad message: Hash mismatch";
237  return false;
238  }
239  info.hash = replyHash;
240 
241  auto numTxns = reply.transaction_size();
244  try
245  {
246  for (int i = 0; i < numTxns; ++i)
247  {
248  // deserialize:
249  // -- TxShaMapItem for building a ShaMap for verification
250  // -- Tx
251  // -- TxMetaData for Tx ordering
252  Serializer shaMapItemData(
253  reply.transaction(i).data(), reply.transaction(i).size());
254 
255  SerialIter txMetaSit(makeSlice(reply.transaction(i)));
256  SerialIter txSit(txMetaSit.getSlice(txMetaSit.getVLDataLength()));
257  SerialIter metaSit(txMetaSit.getSlice(txMetaSit.getVLDataLength()));
258 
259  auto tx = std::make_shared<STTx const>(txSit);
260  if (!tx)
261  {
262  JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
263  return false;
264  }
265  auto tid = tx->getTransactionID();
266  STObject meta(metaSit, sfMetadata);
267  orderedTxns.emplace(meta[sfTransactionIndex], std::move(tx));
268 
269  if (!txMap.addGiveItem(
271  make_shamapitem(tid, shaMapItemData.slice())))
272  {
273  JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
274  return false;
275  }
276  }
277  }
278  catch (std::exception const&)
279  {
280  JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
281  return false;
282  }
283 
284  if (txMap.getHash().as_uint256() != info.txHash)
285  {
286  JLOG(journal_.debug()) << "Bad message: Transactions verify failed";
287  return false;
288  }
289 
290  replayer_.gotReplayDelta(info, std::move(orderedTxns));
291  return true;
292 }
293 
294 } // namespace ripple
ripple::Application
Definition: Application.h:116
ripple::Application::getNodeFamily
virtual Family & getNodeFamily()=0
ripple::makeSlice
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:241
ripple::sfMetadata
const SField sfMetadata
std::shared_ptr
STL class.
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:852
ripple::HashPrefix::txNode
@ txNode
transaction plus metadata
std::exception
STL class.
ripple::SHAMapLeafNode::peekItem
boost::intrusive_ptr< SHAMapItem const > const & peekItem() const
Definition: SHAMapLeafNode.cpp:44
ripple::SHAMapType::TRANSACTION
@ TRANSACTION
ripple::make_shamapitem
boost::intrusive_ptr< SHAMapItem > make_shamapitem(uint256 const &tag, Slice data)
Definition: SHAMapItem.h:160
std::vector
STL class.
ripple::LedgerReplayMsgHandler::LedgerReplayMsgHandler
LedgerReplayMsgHandler(Application &app, LedgerReplayer &replayer)
Definition: LedgerReplayMsgHandler.cpp:29
ripple::keylet::skip
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition: Indexes.cpp:154
std::map::emplace
T emplace(T... args)
ripple::LedgerReplayMsgHandler::processReplayDeltaRequest
protocol::TMReplayDeltaResponse processReplayDeltaRequest(std::shared_ptr< protocol::TMReplayDeltaRequest > const &msg)
Process TMReplayDeltaRequest and return TMReplayDeltaResponse.
Definition: LedgerReplayMsgHandler.cpp:179
ripple::LedgerMaster::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
Definition: LedgerMaster.cpp:1907
ripple::LedgerReplayMsgHandler::journal_
beast::Journal journal_
Definition: LedgerReplayMsgHandler.h:73
ripple::SHAMapTreeNode::makeFromWire
static std::shared_ptr< SHAMapTreeNode > makeFromWire(Slice rawNode)
Definition: SHAMapTreeNode.cpp:116
ripple::SHAMapLeafNode
Definition: SHAMapLeafNode.h:32
ripple::base_uint< 256 >::size
constexpr static std::size_t size()
Definition: base_uint.h:519
ripple::LedgerReplayer::gotSkipList
void gotSkipList(LedgerInfo const &info, boost::intrusive_ptr< SHAMapItem const > const &data)
Process a skip list (extracted from a TMProofPathResponse message)
Definition: LedgerReplayer.cpp:173
ripple::base_uint< 256 >
ripple::SHAMap::verifyProofPath
static bool verifyProofPath(uint256 const &rootHash, uint256 const &key, std::vector< Blob > const &path)
Verify the proof path.
Definition: SHAMapSync.cpp:826
ripple::LedgerReplayMsgHandler::processProofPathResponse
bool processProofPathResponse(std::shared_ptr< protocol::TMProofPathResponse > const &msg)
Process TMProofPathResponse.
Definition: LedgerReplayMsgHandler.cpp:106
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::SHAMap::addGiveItem
bool addGiveItem(SHAMapNodeType type, boost::intrusive_ptr< SHAMapItem const > item)
Definition: SHAMap.cpp:774
ripple::LedgerReplayMsgHandler::app_
Application & app_
Definition: LedgerReplayMsgHandler.h:71
ripple::calculateLedgerHash
uint256 calculateLedgerHash(LedgerInfo const &info)
Definition: Ledger.cpp:65
ripple::Serializer::getDataPtr
const void * getDataPtr() const
Definition: Serializer.h:190
ripple::SHAMap
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:95
ripple::SHAMapNodeType::tnTRANSACTION_MD
@ tnTRANSACTION_MD
ripple::LedgerReplayMsgHandler::processProofPathRequest
protocol::TMProofPathResponse processProofPathRequest(std::shared_ptr< protocol::TMProofPathRequest > const &msg)
Process TMProofPathRequest and return TMProofPathResponse.
Definition: LedgerReplayMsgHandler.cpp:39
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:64
ripple::SerialIter
Definition: Serializer.h:311
ripple::LedgerReplayer::gotReplayDelta
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)
Definition: LedgerReplayer.cpp:196
std::map
STL class.
memory
ripple::sfTransactionIndex
const SF_UINT32 sfTransactionIndex
ripple::Serializer
Definition: Serializer.h:40
ripple::LedgerReplayMsgHandler::replayer_
LedgerReplayer & replayer_
Definition: LedgerReplayMsgHandler.h:72
ripple::STObject
Definition: STObject.h:53
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::addRaw
void addRaw(LedgerHeader const &info, Serializer &s, bool includeHash)
Definition: protocol/impl/LedgerHeader.cpp:25
ripple::deserializeHeader
LedgerHeader deserializeHeader(Slice data, bool hasHash)
Deserialize a ledger header from a byte array.
Definition: protocol/impl/LedgerHeader.cpp:42
ripple::SerialIter::getVLDataLength
int getVLDataLength()
Definition: Serializer.cpp:470
ripple::LedgerReplayer
Manages the lifetime of ledger replay tasks.
Definition: LedgerReplayer.h:72
std::optional
beast::Journal::debug
Stream debug() const
Definition: Journal.h:314
ripple::SHAMapHash::as_uint256
uint256 const & as_uint256() const
Definition: SHAMapHash.h:43
ripple::Serializer::getLength
int getLength() const
Definition: Serializer.h:200
ripple::LedgerReplayMsgHandler::processReplayDeltaResponse
bool processReplayDeltaResponse(std::shared_ptr< protocol::TMReplayDeltaResponse > const &msg)
Process TMReplayDeltaResponse.
Definition: LedgerReplayMsgHandler.cpp:221
ripple::SerialIter::getSlice
Slice getSlice(std::size_t bytes)
Definition: Serializer.cpp:495