mirror of
https://github.com/Xahau/xahaud.git
synced 2026-08-23 08:20:52 +00:00
feat(export): wip export system limits
- max_export per hook: 4 → 2 - maxPendingExports: cap exported directory at 8 entries (tecDIR_FULL) - clamp inbound signature processing in PeerImp to directory cap The directory cap is the root DoS constraint: each pending export requires every validator to sign and broadcast every round. Inbound processing and signing throughput are transitively bounded by it.
This commit is contained in:
@@ -402,7 +402,7 @@ const uint16_t max_state_modifications = 256;
|
|||||||
const uint8_t max_slots = 255;
|
const uint8_t max_slots = 255;
|
||||||
const uint8_t max_nonce = 255;
|
const uint8_t max_nonce = 255;
|
||||||
const uint8_t max_emit = 255;
|
const uint8_t max_emit = 255;
|
||||||
const uint8_t max_export = 4;
|
const uint8_t max_export = 2;
|
||||||
const uint8_t max_params = 16;
|
const uint8_t max_params = 16;
|
||||||
const double fee_base_multiplier = 1.1f;
|
const double fee_base_multiplier = 1.1f;
|
||||||
|
|
||||||
|
|||||||
32
include/xrpl/hook/ExportLimits.h
Normal file
32
include/xrpl/hook/ExportLimits.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef RIPPLE_HOOK_EXPORT_LIMITS_H_INCLUDED
|
||||||
|
#define RIPPLE_HOOK_EXPORT_LIMITS_H_INCLUDED
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
// Export system caps.
|
||||||
|
//
|
||||||
|
// These limits bound the DoS surface of the export signature system:
|
||||||
|
// - Each pending export requires every validator to sign it every round
|
||||||
|
// (sign-once, broadcast-many via TMValidation)
|
||||||
|
// - Inbound signature processing involves crypto verification per sig
|
||||||
|
// - The directory cap (maxPendingExports) is the root constraint;
|
||||||
|
// signing throughput and inbound processing are transitively bounded by it
|
||||||
|
struct ExportLimits
|
||||||
|
{
|
||||||
|
// Maximum exports a single hook execution may produce
|
||||||
|
// (also enforced by hook_api::max_export in Enum.h)
|
||||||
|
static constexpr std::uint8_t maxExportsPerHook = 2;
|
||||||
|
|
||||||
|
// Maximum pending exports in the exported directory at any time.
|
||||||
|
// This transitively caps:
|
||||||
|
// - signatures per TMValidation message (1 per pending export)
|
||||||
|
// - inbound signature processing in PeerImp (clamped to this)
|
||||||
|
// - validator signing work per round
|
||||||
|
static constexpr std::uint8_t maxPendingExports = 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,8 +7,10 @@
|
|||||||
#include <xrpld/app/misc/TxQ.h>
|
#include <xrpld/app/misc/TxQ.h>
|
||||||
#include <xrpld/app/tx/detail/Import.h>
|
#include <xrpld/app/tx/detail/Import.h>
|
||||||
#include <xrpld/app/tx/detail/NFTokenUtils.h>
|
#include <xrpld/app/tx/detail/NFTokenUtils.h>
|
||||||
|
#include <xrpld/ledger/View.h>
|
||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/basics/Slice.h>
|
#include <xrpl/basics/Slice.h>
|
||||||
|
#include <xrpl/hook/ExportLimits.h>
|
||||||
#include <xrpl/protocol/ErrorCodes.h>
|
#include <xrpl/protocol/ErrorCodes.h>
|
||||||
#include <xrpl/protocol/TxFlags.h>
|
#include <xrpl/protocol/TxFlags.h>
|
||||||
#include <xrpl/protocol/st.h>
|
#include <xrpl/protocol/st.h>
|
||||||
@@ -1735,6 +1737,43 @@ hook::finalizeHookResult(
|
|||||||
|
|
||||||
if (!sleExported)
|
if (!sleExported)
|
||||||
{
|
{
|
||||||
|
// Enforce maxPendingExports on the exported directory.
|
||||||
|
// Each pending export costs validator signing + broadcast
|
||||||
|
// work every round, so this is the root DoS constraint.
|
||||||
|
{
|
||||||
|
Keylet const expDirKey{keylet::exportedDir()};
|
||||||
|
std::size_t dirSize = 0;
|
||||||
|
std::shared_ptr<SLE const> sleDirNode;
|
||||||
|
unsigned int uDirEntry{0};
|
||||||
|
uint256 dirEntry{beast::zero};
|
||||||
|
if (cdirFirst(
|
||||||
|
applyCtx.view(),
|
||||||
|
expDirKey.key,
|
||||||
|
sleDirNode,
|
||||||
|
uDirEntry,
|
||||||
|
dirEntry))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
++dirSize;
|
||||||
|
} while (cdirNext(
|
||||||
|
applyCtx.view(),
|
||||||
|
expDirKey.key,
|
||||||
|
sleDirNode,
|
||||||
|
uDirEntry,
|
||||||
|
dirEntry));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirSize >= ExportLimits::maxPendingExports)
|
||||||
|
{
|
||||||
|
JLOG(j.warn()) << "HookError[" << HR_ACC() << "]: "
|
||||||
|
<< "Export directory at cap ("
|
||||||
|
<< ExportLimits::maxPendingExports
|
||||||
|
<< "), rejecting export " << id;
|
||||||
|
return tecDIR_FULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exported_txnid.emplace_back(id);
|
exported_txnid.emplace_back(id);
|
||||||
|
|
||||||
sleExported = std::make_shared<SLE>(exportedId);
|
sleExported = std::make_shared<SLE>(exportedId);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <xrpl/basics/random.h>
|
#include <xrpl/basics/random.h>
|
||||||
#include <xrpl/basics/safe_cast.h>
|
#include <xrpl/basics/safe_cast.h>
|
||||||
#include <xrpl/beast/core/LexicalCast.h>
|
#include <xrpl/beast/core/LexicalCast.h>
|
||||||
|
#include <xrpl/hook/ExportLimits.h>
|
||||||
#include <xrpl/protocol/digest.h>
|
#include <xrpl/protocol/digest.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
@@ -3065,7 +3066,19 @@ PeerImp::checkValidation(
|
|||||||
{
|
{
|
||||||
auto const currentSeq = val->getFieldU32(sfLedgerSequence);
|
auto const currentSeq = val->getFieldU32(sfLedgerSequence);
|
||||||
|
|
||||||
for (int i = 0; i < packet->exportsignatures_size(); ++i)
|
// Clamp inbound export signatures to the directory cap.
|
||||||
|
// A legitimate validator can only have maxPendingExports
|
||||||
|
// pending, so anything beyond that is either a bug or abuse.
|
||||||
|
auto const sigCount = std::min(
|
||||||
|
packet->exportsignatures_size(),
|
||||||
|
static_cast<int>(ExportLimits::maxPendingExports));
|
||||||
|
if (sigCount < packet->exportsignatures_size())
|
||||||
|
{
|
||||||
|
JLOG(p_journal_.warn())
|
||||||
|
<< "Export: clamping " << packet->exportsignatures_size()
|
||||||
|
<< " signatures to cap " << sigCount;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < sigCount; ++i)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user