mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-22 23:00:55 +00:00
fix: Handle malformed ledger replay responses
This commit is contained in:
@@ -13,6 +13,7 @@ extern Charge const kFeeRequestNoReply; // A request that we cannot satisfy.
|
||||
extern Charge const kFeeInvalidSignature; // An object whose signature we had to check that failed.
|
||||
extern Charge const kFeeUselessData; // Data we have no use for.
|
||||
extern Charge const kFeeInvalidData; // Data we have to verify before rejecting.
|
||||
extern Charge const kFeeMalformedData; // Data that no honest peer would send.
|
||||
|
||||
// RPC loads
|
||||
extern Charge const kFeeMalformedRpc; // An RPC request that we can immediately tell is invalid.
|
||||
|
||||
@@ -9,6 +9,7 @@ Charge const kFeeRequestNoReply(10, "unsatisfiable request");
|
||||
Charge const kFeeInvalidSignature(2000, "invalid signature");
|
||||
Charge const kFeeUselessData(150, "useless data");
|
||||
Charge const kFeeInvalidData(400, "invalid data");
|
||||
Charge const kFeeMalformedData(2000, "malformed data");
|
||||
|
||||
Charge const kFeeMalformedRpc(100, "malformed RPC");
|
||||
Charge const kFeeReferenceRpc(20, "reference RPC");
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <format>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -958,7 +960,8 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
auto reply = std::make_shared<protocol::TMProofPathResponse>(
|
||||
server.msgHandler.processProofPathRequest(request));
|
||||
BEAST_EXPECT(reply->has_error());
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::BadData);
|
||||
}
|
||||
{
|
||||
// request, wrong hash
|
||||
@@ -982,7 +985,7 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
auto reply = std::make_shared<protocol::TMProofPathResponse>(
|
||||
server.msgHandler.processProofPathRequest(request));
|
||||
BEAST_EXPECT(!reply->has_error());
|
||||
BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply));
|
||||
BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::Ok);
|
||||
|
||||
{
|
||||
// bad reply: invalid hash/key sizes
|
||||
@@ -990,37 +993,49 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
// reply with undersized ledgerhash (31 bytes)
|
||||
auto bad = std::make_shared<protocol::TMProofPathResponse>(*reply);
|
||||
bad->set_ledgerhash(std::string(31, '\x01'));
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
{
|
||||
// reply with oversized ledgerhash (33 bytes)
|
||||
auto bad = std::make_shared<protocol::TMProofPathResponse>(*reply);
|
||||
bad->set_ledgerhash(std::string(33, '\x01'));
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
{
|
||||
// reply with empty ledgerhash
|
||||
auto bad = std::make_shared<protocol::TMProofPathResponse>(*reply);
|
||||
bad->set_ledgerhash(std::string());
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
{
|
||||
// reply with undersized key (31 bytes)
|
||||
auto bad = std::make_shared<protocol::TMProofPathResponse>(*reply);
|
||||
bad->set_key(std::string(31, '\x01'));
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
{
|
||||
// reply with oversized key (33 bytes)
|
||||
auto bad = std::make_shared<protocol::TMProofPathResponse>(*reply);
|
||||
bad->set_key(std::string(33, '\x01'));
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
{
|
||||
// reply with empty key
|
||||
auto bad = std::make_shared<protocol::TMProofPathResponse>(*reply);
|
||||
bad->set_key(std::string());
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,13 +1045,18 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
std::string r(reply->ledgerheader());
|
||||
r.back()--;
|
||||
reply->set_ledgerheader(r);
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(reply) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
r.back()++;
|
||||
reply->set_ledgerheader(r);
|
||||
BEAST_EXPECT(server.msgHandler.processProofPathResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(reply) == ReplayMsgStatus::Ok);
|
||||
// bad proof path
|
||||
reply->mutable_path()->RemoveLast();
|
||||
BEAST_EXPECT(!server.msgHandler.processProofPathResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processProofPathResponse(reply) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1054,14 +1074,16 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
auto reply = std::make_shared<protocol::TMReplayDeltaResponse>(
|
||||
server.msgHandler.processReplayDeltaRequest(request));
|
||||
BEAST_EXPECT(reply->has_error());
|
||||
BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::BadData);
|
||||
// request, wrong hash
|
||||
uint256 hash(1234567);
|
||||
request->set_ledgerhash(hash.data(), hash.size());
|
||||
reply = std::make_shared<protocol::TMReplayDeltaResponse>(
|
||||
server.msgHandler.processReplayDeltaRequest(request));
|
||||
BEAST_EXPECT(reply->has_error());
|
||||
BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::BadData);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1071,7 +1093,8 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
auto reply = std::make_shared<protocol::TMReplayDeltaResponse>(
|
||||
server.msgHandler.processReplayDeltaRequest(request));
|
||||
BEAST_EXPECT(!reply->has_error());
|
||||
BEAST_EXPECT(server.msgHandler.processReplayDeltaResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::Ok);
|
||||
|
||||
{
|
||||
// bad reply: invalid hash sizes
|
||||
@@ -1079,19 +1102,25 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
// reply with undersized ledgerhash (31 bytes)
|
||||
auto bad = std::make_shared<protocol::TMReplayDeltaResponse>(*reply);
|
||||
bad->set_ledgerhash(std::string(31, '\x01'));
|
||||
BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
{
|
||||
// reply with oversized ledgerhash (33 bytes)
|
||||
auto bad = std::make_shared<protocol::TMReplayDeltaResponse>(*reply);
|
||||
bad->set_ledgerhash(std::string(33, '\x01'));
|
||||
BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
{
|
||||
// reply with empty ledgerhash
|
||||
auto bad = std::make_shared<protocol::TMReplayDeltaResponse>(*reply);
|
||||
bad->set_ledgerhash(std::string());
|
||||
BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(bad));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(bad) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1101,17 +1130,77 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
std::string r(reply->ledgerheader());
|
||||
r.back()--;
|
||||
reply->set_ledgerheader(r);
|
||||
BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(reply) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
r.back()++;
|
||||
reply->set_ledgerheader(r);
|
||||
BEAST_EXPECT(server.msgHandler.processReplayDeltaResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(reply) == ReplayMsgStatus::Ok);
|
||||
// bad txns
|
||||
reply->mutable_transaction()->RemoveLast();
|
||||
BEAST_EXPECT(!server.msgHandler.processReplayDeltaResponse(reply));
|
||||
BEAST_EXPECT(
|
||||
server.msgHandler.processReplayDeltaResponse(reply) ==
|
||||
ReplayMsgStatus::Malformed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testTruncatedHeader()
|
||||
{
|
||||
testcase("TruncatedLedgerHeader");
|
||||
LedgerServer server(*this, {.initLedgers = 1});
|
||||
auto const l = server.ledgerMaster.getClosedLedger();
|
||||
|
||||
auto runNoThrow = [this](auto fn, char const* what) {
|
||||
try
|
||||
{
|
||||
BEAST_EXPECT(fn() == ReplayMsgStatus::Malformed);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
fail(
|
||||
std::format("processor threw on truncated header ({}): {}", what, e.what()),
|
||||
__FILE__,
|
||||
__LINE__);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
fail(
|
||||
std::format("processor threw unknown exception ({}) on truncated header", what),
|
||||
__FILE__,
|
||||
__LINE__);
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
auto request = std::make_shared<protocol::TMReplayDeltaRequest>();
|
||||
request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
|
||||
auto reply = std::make_shared<protocol::TMReplayDeltaResponse>(
|
||||
server.msgHandler.processReplayDeltaRequest(request));
|
||||
BEAST_EXPECT(!reply->has_error());
|
||||
|
||||
reply->set_ledgerheader(std::string(1, '\x00'));
|
||||
runNoThrow(
|
||||
[&] { return server.msgHandler.processReplayDeltaResponse(reply); }, "ReplayDelta");
|
||||
}
|
||||
|
||||
{
|
||||
auto request = std::make_shared<protocol::TMProofPathRequest>();
|
||||
request->set_ledgerhash(l->header().hash.data(), l->header().hash.size());
|
||||
request->set_type(protocol::TMLedgerMapType::lmACCOUNT_STATE);
|
||||
request->set_key(keylet::skip().key.data(), keylet::skip().key.size());
|
||||
auto reply = std::make_shared<protocol::TMProofPathResponse>(
|
||||
server.msgHandler.processProofPathRequest(request));
|
||||
BEAST_EXPECT(!reply->has_error());
|
||||
|
||||
reply->set_ledgerheader(std::string(1, '\x00'));
|
||||
runNoThrow(
|
||||
[&] { return server.msgHandler.processProofPathResponse(reply); }, "ProofPath");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testTaskParameter()
|
||||
{
|
||||
@@ -1514,6 +1603,7 @@ struct LedgerReplayer_test : public beast::unit_test::Suite
|
||||
{
|
||||
testProofPath();
|
||||
testReplayDelta();
|
||||
testTruncatedHeader();
|
||||
testTaskParameter();
|
||||
testConfig();
|
||||
testHandshake();
|
||||
|
||||
@@ -101,42 +101,54 @@ LedgerReplayMsgHandler::processProofPathRequest(
|
||||
return reply;
|
||||
}
|
||||
|
||||
bool
|
||||
ReplayMsgStatus
|
||||
LedgerReplayMsgHandler::processProofPathResponse(
|
||||
std::shared_ptr<protocol::TMProofPathResponse> const& msg)
|
||||
{
|
||||
protocol::TMProofPathResponse const& reply = *msg;
|
||||
if (reply.has_error() || !reply.has_key() || !reply.has_ledgerhash() || !reply.has_type() ||
|
||||
if (reply.has_error())
|
||||
{
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: peer reported error";
|
||||
return ReplayMsgStatus::BadData;
|
||||
}
|
||||
if (!reply.has_key() || !reply.has_ledgerhash() || !reply.has_type() ||
|
||||
!reply.has_ledgerheader() || reply.path_size() == 0 ||
|
||||
reply.ledgerhash().size() != uint256::size() || reply.key().size() != uint256::size())
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Error reply";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed (missing or wrong-size fields)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
if (reply.type() != protocol::lmACCOUNT_STATE)
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: we only support the state ShaMap for now";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed (unsupported map type)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
// deserialize the header
|
||||
auto info = deserializeHeader({reply.ledgerheader().data(), reply.ledgerheader().size()});
|
||||
LedgerHeader info;
|
||||
try
|
||||
{
|
||||
info = deserializeHeader(makeSlice(reply.ledgerheader()));
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed header (" << e.what() << ")";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
uint256 const replyHash = uint256::fromRaw(reply.ledgerhash());
|
||||
if (calculateLedgerHash(info) != replyHash)
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Hash mismatch";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed (hash mismatch)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
info.hash = replyHash;
|
||||
|
||||
uint256 const key = uint256::fromRaw(reply.key());
|
||||
if (key != keylet::skip().key)
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: we only support the short skip list for now. "
|
||||
"Key in reply "
|
||||
<< key;
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed (unexpected key " << key << ")";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
// verify the skip list
|
||||
@@ -149,26 +161,35 @@ LedgerReplayMsgHandler::processProofPathResponse(
|
||||
|
||||
if (!SHAMap::verifyProofPath(info.accountHash, key, path))
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Proof path verify failed";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed (proof path verify failed)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
// deserialize the SHAMapItem
|
||||
auto node = SHAMapTreeNode::makeFromWire(makeSlice(path.front()));
|
||||
SHAMapTreeNodePtr node;
|
||||
try
|
||||
{
|
||||
node = SHAMapTreeNode::makeFromWire(makeSlice(path.front()));
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed SHAMap node (" << e.what() << ")";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
if (!node || !node->isLeaf())
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed (not a leaf node)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
if (auto item = safeDowncast<SHAMapLeafNode*>(node.get())->peekItem())
|
||||
{
|
||||
replayer_.gotSkipList(info, item);
|
||||
return true;
|
||||
return ReplayMsgStatus::Ok;
|
||||
}
|
||||
|
||||
JLOG(journal_.debug()) << "Bad message: Cannot get ShaMapItem";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ProofPathResponse: malformed (no SHAMapItem)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
protocol::TMReplayDeltaResponse
|
||||
@@ -210,24 +231,38 @@ LedgerReplayMsgHandler::processReplayDeltaRequest(
|
||||
return reply;
|
||||
}
|
||||
|
||||
bool
|
||||
ReplayMsgStatus
|
||||
LedgerReplayMsgHandler::processReplayDeltaResponse(
|
||||
std::shared_ptr<protocol::TMReplayDeltaResponse> const& msg)
|
||||
{
|
||||
protocol::TMReplayDeltaResponse const& reply = *msg;
|
||||
if (reply.has_error() || !reply.has_ledgerheader() || !reply.has_ledgerhash() ||
|
||||
if (reply.has_error())
|
||||
{
|
||||
JLOG(journal_.debug()) << "ReplayDeltaResponse: peer reported error";
|
||||
return ReplayMsgStatus::BadData;
|
||||
}
|
||||
if (!reply.has_ledgerheader() || !reply.has_ledgerhash() ||
|
||||
reply.ledgerhash().size() != uint256::size())
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Error reply";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (missing or wrong-size fields)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
auto info = deserializeHeader({reply.ledgerheader().data(), reply.ledgerheader().size()});
|
||||
LedgerHeader info;
|
||||
try
|
||||
{
|
||||
info = deserializeHeader(makeSlice(reply.ledgerheader()));
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed header (" << e.what() << ")";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
uint256 const replyHash = uint256::fromRaw(reply.ledgerhash());
|
||||
if (calculateLedgerHash(info) != replyHash)
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Hash mismatch";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (hash mismatch)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
info.hash = replyHash;
|
||||
|
||||
@@ -252,8 +287,8 @@ LedgerReplayMsgHandler::processReplayDeltaResponse(
|
||||
auto tx = std::make_shared<STTx const>(txSit);
|
||||
if (!tx)
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (tx deserialize)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
auto tid = tx->getTransactionID();
|
||||
STObject meta(metaSit, sfMetadata);
|
||||
@@ -262,25 +297,26 @@ LedgerReplayMsgHandler::processReplayDeltaResponse(
|
||||
if (!txMap.addGiveItem(
|
||||
SHAMapNodeType::TnTransactionMd, makeShamapitem(tid, shaMapItemData.slice())))
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (tx map add)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Cannot deserialize";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed transactions (" << e.what()
|
||||
<< ")";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
if (txMap.getHash().asUInt256() != info.txHash)
|
||||
{
|
||||
JLOG(journal_.debug()) << "Bad message: Transactions verify failed";
|
||||
return false;
|
||||
JLOG(journal_.debug()) << "ReplayDeltaResponse: malformed (transactions verify failed)";
|
||||
return ReplayMsgStatus::Malformed;
|
||||
}
|
||||
|
||||
replayer_.gotReplayDelta(info, std::move(orderedTxns));
|
||||
return true;
|
||||
return ReplayMsgStatus::Ok;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -10,6 +10,15 @@ namespace xrpl {
|
||||
class Application;
|
||||
class LedgerReplayer;
|
||||
|
||||
/**
|
||||
* Outcome of processing an incoming ledger-replay response.
|
||||
*/
|
||||
enum class ReplayMsgStatus {
|
||||
Ok, ///< Accepted.
|
||||
BadData, ///< Peer reported has_error() (legitimate "cannot fulfill" signal).
|
||||
Malformed, ///< Protocol-level violation; no honest peer would produce this.
|
||||
};
|
||||
|
||||
class LedgerReplayMsgHandler final
|
||||
{
|
||||
public:
|
||||
@@ -19,31 +28,31 @@ public:
|
||||
/**
|
||||
* Process TMProofPathRequest and return TMProofPathResponse
|
||||
* @note check has_error() and error() of the response for error
|
||||
* @return TMProofPathResponse with the proof path, or with error() set if
|
||||
* the request cannot be fulfilled
|
||||
*/
|
||||
protocol::TMProofPathResponse
|
||||
processProofPathRequest(std::shared_ptr<protocol::TMProofPathRequest> const& msg);
|
||||
|
||||
/**
|
||||
* Process TMProofPathResponse
|
||||
* @return false if the response message has bad format or bad data;
|
||||
* true otherwise
|
||||
*/
|
||||
bool
|
||||
ReplayMsgStatus
|
||||
processProofPathResponse(std::shared_ptr<protocol::TMProofPathResponse> const& msg);
|
||||
|
||||
/**
|
||||
* Process TMReplayDeltaRequest and return TMReplayDeltaResponse
|
||||
* @note check has_error() and error() of the response for error
|
||||
* @return TMReplayDeltaResponse with the ledger delta, or with error() set
|
||||
* if the request cannot be fulfilled
|
||||
*/
|
||||
protocol::TMReplayDeltaResponse
|
||||
processReplayDeltaRequest(std::shared_ptr<protocol::TMReplayDeltaRequest> const& msg);
|
||||
|
||||
/**
|
||||
* Process TMReplayDeltaResponse
|
||||
* @return false if the response message has bad format or bad data;
|
||||
* true otherwise
|
||||
*/
|
||||
bool
|
||||
ReplayMsgStatus
|
||||
processReplayDeltaResponse(std::shared_ptr<protocol::TMReplayDeltaResponse> const& msg);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1565,9 +1565,16 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMProofPathResponse> const& m)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ledgerReplayMsgHandler_.processProofPathResponse(m))
|
||||
switch (ledgerReplayMsgHandler_.processProofPathResponse(m))
|
||||
{
|
||||
fee_.update(Resource::kFeeInvalidData, "proof_path_response");
|
||||
case ReplayMsgStatus::Ok:
|
||||
break;
|
||||
case ReplayMsgStatus::BadData:
|
||||
fee_.update(Resource::kFeeInvalidData, "proof_path_response");
|
||||
break;
|
||||
case ReplayMsgStatus::Malformed:
|
||||
fee_.update(Resource::kFeeMalformedData, "proof_path_response malformed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1615,9 +1622,16 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMReplayDeltaResponse> const& m)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ledgerReplayMsgHandler_.processReplayDeltaResponse(m))
|
||||
switch (ledgerReplayMsgHandler_.processReplayDeltaResponse(m))
|
||||
{
|
||||
fee_.update(Resource::kFeeInvalidData, "replay_delta_response");
|
||||
case ReplayMsgStatus::Ok:
|
||||
break;
|
||||
case ReplayMsgStatus::BadData:
|
||||
fee_.update(Resource::kFeeInvalidData, "replay_delta_response");
|
||||
break;
|
||||
case ReplayMsgStatus::Malformed:
|
||||
fee_.update(Resource::kFeeMalformedData, "replay_delta_response malformed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user