Skip to content

Transaction relay configuration should reject non-HTTP upstream URLs #335

Description

@Kewe63

Summary

The --arc.tx.relays configuration currently accepts any URL that can be parsed by url::Url, including schemes that cannot be used by the transaction relay's HTTP transport.

For example, the following value is accepted during startup validation:

file:///tmp/upstream

The value is later passed to an explicitly HTTP-based RPC client. This allows the node to start with an unusable relay configuration instead of rejecting it immediately with a clear configuration error.


Affected Files

crates/node/src/main.rs
crates/evm-node/src/rpc_middleware.rs

The validation gap is in build_tx_relays() in crates/node/src/main.rs.


Observed Behavior

build_tx_relays() currently validates each configured relay by calling:

rust
url::Url::parse(s)

This only establishes that the input is a syntactically valid URL. It does not verify that its scheme is supported by the downstream transport.

As a result, this configuration is accepted:

--arc.tx.relays file:///tmp/upstream

The returned relay list contains:

["file:///tmp/upstream"]

However, the relay implementation later constructs each client with:

rust
RpcClient::new_http_with_client(...)

using a reqwest::Client. Therefore, a file:// URL cannot function as a transaction relay upstream.

The invalid configuration is detected only when forwarding is attempted, where it becomes a transport/failover error rather than a startup validation error.


Expected Behavior

--arc.tx.relays should only accept URL schemes supported by the transaction relay transport:

http
https

Unsupported schemes such as the following should be rejected during startup:

file://
ftp://
ws://
wss://

The error should identify the invalid --arc.tx.relays entry and explain that an HTTP or HTTPS URL is required.


Reproduction

I added the following focused regression test against current main:

rust
#[test]
fn test_build_tx_relays_rejects_non_http_url() {
let err = tx_relays_from_args(&[
"--arc.tx.relays",
"file:///tmp/upstream",
])
.expect_err("transaction relay upstreams must use HTTP or HTTPS");

assert!(
    err.to_string()
        .contains("invalid --arc.tx.relays entry")
);

}

The test fails because the current implementation returns the URL as a valid relay configuration:

thread 'tests::test_build_tx_relays_rejects_non_http_url' panicked:

transaction relay upstreams must use HTTP or HTTPS:
["file:///tmp/upstream"]

test tests::test_build_tx_relays_rejects_non_http_url ... FAILED

The test was executed against:

97f8da0

which was the current main SHA at the time of verification.


Root Cause

The validation boundary checks URL syntax but not transport compatibility:

rust
url::Url::parse(s)
.map(|_| s.to_string())

The downstream implementation assumes an HTTP transport:

rust
RpcClient::new_http_with_client(http.clone(), url)

Therefore, the validation contract is weaker than the runtime transport contract.


Why This Matters

Invalid relay configuration should fail before the node starts.

Accepting unsupported schemes can cause:

  • a node to appear correctly configured at startup
  • transaction forwarding to fail only when it is first needed
  • unnecessary failover attempts
  • misleading relay exhaustion or generic transport errors
  • longer diagnosis time for an operator configuration error

This is especially relevant because --arc.tx.relays is a prioritized list: one unsupported entry can introduce avoidable failures before a working upstream is selected.


Suggested Fix

After parsing each URL, validate its scheme:

rust
let url = url::Url::parse(s)
.map_err(|e| eyre::eyre!(
"invalid --arc.tx.relays entry {s:?}: {e}"
))?;

if !matches!(url.scheme(), "http" | "https") {
return Err(eyre::eyre!(
"invalid --arc.tx.relays entry {s:?}:
transaction relay upstreams must use HTTP or HTTPS"
));
}

The existing ordering and trimmed string behavior can otherwise remain unchanged.


Potential Regression Tests

Add focused tests verifying that:

  • http://a:8545 is accepted
  • https://a.example is accepted
  • file:///tmp/upstream is rejected
  • ftp://a.example is rejected
  • malformed URLs remain rejected
  • multiple HTTP/HTTPS relay URLs preserve their configured order

Scope

This should be a small fail-fast configuration fix.

It does not require changing:

  • transaction forwarding behavior
  • failover ordering
  • request timeout handling
  • the RPC client implementation
  • protocol or consensus behavior

Duplicate Check

I searched open and closed issues and pull requests using:

  • arc.tx.relays
  • transaction relay URL scheme
  • TxRelays HTTP upstream
  • file:// relay
  • new_http_with_client

I did not find a direct duplicate or an existing PR implementing this validation.

Issue #59 concerns the older singular --rpc.forwarder path and does not cover --arc.tx.relays scheme validation.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions