mirror of
https://github.com/Xahau/xahaud.git
synced 2026-09-28 16:08:05 +00:00
fix(manifest): discard oversized legacy dumps without disconnecting
This commit is contained in:
@@ -386,7 +386,7 @@ public:
|
||||
void
|
||||
testManifestFrameLimit()
|
||||
{
|
||||
testcase("manifest frame limits before payload allocation");
|
||||
testcase("manifest frame limits and legacy discard alignment");
|
||||
struct Handler
|
||||
{
|
||||
bool
|
||||
@@ -442,12 +442,18 @@ public:
|
||||
(reject ? make_error_code(boost::system::errc::message_size)
|
||||
: boost::system::error_code{}));
|
||||
BEAST_EXPECT(handler.received == 0);
|
||||
if (!reject)
|
||||
BEAST_EXPECT(hint == wire);
|
||||
};
|
||||
check(maxManifestMessageSize, maxManifestMessageSize, false, false);
|
||||
check(maxManifestMessageSize + 1, 0, false, true);
|
||||
check(1, maxManifestMessageSize + 1, true, true);
|
||||
check(maxManifestMessageSize + 1, 1, true, true);
|
||||
check(maxManifestMessageSize + 1, 0, false, enforceManifestFrameLimit);
|
||||
check(1, maxManifestMessageSize + 1, true, enforceManifestFrameLimit);
|
||||
check(maxManifestMessageSize + 1, 1, true, enforceManifestFrameLimit);
|
||||
check(maxManifestMessageSize, maxManifestMessageSize, true, false);
|
||||
// Legacy tolerance never bypasses the generic hard ceiling, even
|
||||
// when only the compressed header (no payload) has arrived.
|
||||
check(1, maximiumMessageSize + 1, true, true);
|
||||
check(1, maximiumMessageSize + 1, true, true, protocol::mtLEDGER_DATA);
|
||||
check(
|
||||
maxManifestMessageSize + 1,
|
||||
0,
|
||||
@@ -476,6 +482,47 @@ public:
|
||||
hint);
|
||||
BEAST_EXPECT(!second.second && second.first == bytes.size());
|
||||
BEAST_EXPECT(handler.received == 3);
|
||||
|
||||
for (bool const compressed : {false, true})
|
||||
{
|
||||
Serializer frame;
|
||||
std::uint32_t const wire =
|
||||
compressed ? 1u : maxManifestMessageSize + 1;
|
||||
frame.add32(wire | (compressed ? 0x90000000u : 0u));
|
||||
frame.add16(protocol::mtMANIFESTS);
|
||||
if (compressed)
|
||||
frame.add32(std::uint32_t(maxManifestMessageSize + 1));
|
||||
// Deliberately invalid protobuf/LZ4. Discard must not decode it,
|
||||
// nor consume the good frame coalesced behind it.
|
||||
frame.addRaw(Blob(wire, 0xff));
|
||||
auto const discardedSize = frame.size();
|
||||
frame.addRaw(bytes.data(), bytes.size());
|
||||
int const received = handler.received;
|
||||
auto discarded = invokeProtocolMessage(
|
||||
boost::asio::buffer(frame.data(), frame.size()), handler, hint);
|
||||
BEAST_EXPECT(handler.received == received);
|
||||
if (enforceManifestFrameLimit)
|
||||
{
|
||||
BEAST_EXPECT(discarded.first == 0);
|
||||
BEAST_EXPECT(
|
||||
discarded.second ==
|
||||
make_error_code(boost::system::errc::message_size));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!discarded.second);
|
||||
BEAST_EXPECT(discarded.first == discardedSize);
|
||||
auto next = invokeProtocolMessage(
|
||||
boost::asio::buffer(
|
||||
reinterpret_cast<std::uint8_t const*>(frame.data()) +
|
||||
discarded.first,
|
||||
frame.size() - discarded.first),
|
||||
handler,
|
||||
hint);
|
||||
BEAST_EXPECT(!next.second && next.first == bytes.size());
|
||||
BEAST_EXPECT(handler.received == received + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -37,10 +37,13 @@ namespace ripple {
|
||||
|
||||
constexpr std::size_t maximiumMessageSize = megabytes(64);
|
||||
|
||||
// Manifests are small identity records, not bulk ledger data. Apply the frame
|
||||
// limit before allocating/decompressing its payload, and the entry limits
|
||||
// before queuing signature work. Outbound gossip uses the same limits.
|
||||
// Manifests are small identity records, not bulk ledger data. Bound parsing
|
||||
// and signature work; outbound gossip uses the same packet/entry limits.
|
||||
constexpr std::size_t maxManifestMessageSize = kilobytes(256);
|
||||
// TODO: negotiate xahau-onchain-manifests and requireProtocolFeature at the
|
||||
// agreed activation boundary before enabling disconnects. Until then, discard
|
||||
// oversized legacy cache dumps without parsing; the generic 64 MiB cap stays.
|
||||
constexpr bool enforceManifestFrameLimit = false;
|
||||
constexpr int maxManifestEntries = 256;
|
||||
constexpr std::size_t maxManifestSize = 1024;
|
||||
// Node-wide overload cutoff for bounded signature batches, not a per-peer
|
||||
|
||||
@@ -361,11 +361,13 @@ invokeProtocolMessage(
|
||||
// whose size exceeds this may result in the connection being dropped. A
|
||||
// larger message size may be supported in the future or negotiated as
|
||||
// part of a protocol upgrade.
|
||||
auto const sizeLimit = header->message_type == protocol::mtMANIFESTS
|
||||
? maxManifestMessageSize
|
||||
: maximiumMessageSize;
|
||||
if (header->payload_wire_size > sizeLimit ||
|
||||
header->uncompressed_size > sizeLimit)
|
||||
bool const oversizedManifest =
|
||||
header->message_type == protocol::mtMANIFESTS &&
|
||||
(header->payload_wire_size > maxManifestMessageSize ||
|
||||
header->uncompressed_size > maxManifestMessageSize);
|
||||
if (header->payload_wire_size > maximiumMessageSize ||
|
||||
header->uncompressed_size > maximiumMessageSize ||
|
||||
(enforceManifestFrameLimit && oversizedManifest))
|
||||
{
|
||||
result.second = make_error_code(boost::system::errc::message_size);
|
||||
return result;
|
||||
@@ -387,6 +389,12 @@ invokeProtocolMessage(
|
||||
return result;
|
||||
}
|
||||
|
||||
// Old peers send their cache in one packet. Consume exactly that frame,
|
||||
// without decompression, protobuf parsing or dispatch, and keep the link.
|
||||
// Buffering is still bounded by the generic ceiling checked above.
|
||||
if (oversizedManifest)
|
||||
return {header->total_wire_size, {}};
|
||||
|
||||
bool success;
|
||||
|
||||
switch (header->message_type)
|
||||
|
||||
Reference in New Issue
Block a user