Skip to content

[BUG] RpcClient.call() quarantines healthy endpoints on application-level errors, enabling single-request DoS of the RPC layer #182

Description

@N-thnI

Priority: High

Description

RpcClient.call() quarantines an endpoint for 30s on any exception from the callback, without distinguishing network/connectivity failures from application-level errors (malformed XDR, validation errors). Since call() retries up to MAX_RETRIES=3 times on a new endpoint each time, one bad request can cascade-quarantine up to 3 healthy endpoints simultaneously.

Location

engine-bridge/src/rpc-client.ts:30-48 (call)

Current Behavior

try {
  const server = new SorobanRpc.Server(ep.url, {...});
  return await fn(server);
} catch (err) {
  lastError = err;
  ep.deadUntil = Date.now() + QUARANTINE_MS; // any error at all
  logger.warn(`[RpcClient] ${ep.url} quarantined -- ${(err as Error).message}`);
}

Expected Behavior

Only network/transport-level errors (timeouts, connection refused, 5xx) should quarantine an endpoint; application-level errors that will fail identically everywhere should propagate immediately without punishing the endpoint.

Repro / Evidence

Construct RpcClient with 3 URLs, make fn synchronously throw new Error("invalid XDR"); observe all 3 endpoints' deadUntil set after a single call().

Impact

A single malformed/invalid submission can quarantine every configured RPC endpoint for 30s, denying service to all other concurrent callers of the shared RpcClient (used by EventPropagator, HeartbeatMonitor, GasOracle, NonceManager, TxAggregator) — a low-cost, repeatable self-inflicted DoS.

Suggested Fix

Classify errors before quarantining — only quarantine on network/transport failures; rethrow application-level errors immediately without marking the endpoint dead.

Acceptance Criteria

  • AC-1: A validation/application error doesn't set deadUntil.
  • AC-2: A network/timeout error still quarantines as today.
  • AC-3: New test reproducing the cascade — fails on current code.

Definition of Done

  • Fix merged with all AC items checked
  • Regression test passes in CI
  • No new eslint warnings

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26Third CampaignCampaign: Third CampaignbugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions