Skip to content

feat(executor): private-RPC transaction submitter#44

Merged
obchain merged 4 commits intomainfrom
feat/19-private-rpc-submit
Apr 24, 2026
Merged

feat(executor): private-RPC transaction submitter#44
obchain merged 4 commits intomainfrom
feat/19-private-rpc-submit

Conversation

@obchain
Copy link
Copy Markdown
Owner

@obchain obchain commented Apr 21, 2026

Closes #19

Wraps eth_sendRawTransaction against a private-RPC endpoint so pending liquidation txs bypass the public mempool (bloxroute / blocknative on BSC).

  • Submitter::connect(url, timeout) async constructor; reuses a single provider + connection pool across submissions
  • submit(raw_bytes) — posts the signed envelope, returns tx hash. Retries once on timeout (6 s default, ≈ 8 BSC blocks). Non-timeout RPC errors (revert, bad nonce, bad signature) fail immediately
  • ChainConfig.private_rpc_url — optional per-chain endpoint; callers fall back to http_url when unset
  • config/default.toml documents BSC_PRIVATE_RPC_URL as the expected env var for v0.1

Two unit tests: default timeout invariant, connect rejects invalid URL. Live submission testing deferred until the pipeline can produce a signed tx (blocks on upstream PRs merging).

Depends on feat/18-gas-and-nonce.

Wraps `eth_sendRawTransaction` against a private-RPC endpoint so
pending liquidation txs bypass the public mempool. Primary target on
BSC is a bloxroute / blocknative private feed; L2 sequencer endpoints
fit the same surface.

- `Submitter::connect(url, timeout)` async constructor; reuses a
  single provider + connection pool across submissions
- `submit(raw_bytes)` — posts the signed envelope, returns tx hash.
  Retries once on timeout (6 s default, ≈ 8 BSC blocks). Non-timeout
  RPC errors (revert, bad nonce, bad signature) fail immediately —
  no point retrying a deterministic rejection
- `ChainConfig.private_rpc_url` — optional per-chain private-RPC
  endpoint. When unset, callers should fall back to `http_url`
- `config/default.toml` now documents `BSC_PRIVATE_RPC_URL` as the
  expected env var for v0.1

Two unit tests: default timeout invariant, connect rejects invalid URL.
This was referenced Apr 23, 2026
obchain added 2 commits April 23, 2026 16:40
Close #192, #193, #198.

- ChainConfig.private_rpc_url becomes Option<SecretString> with a
  manual Debug impl that redacts both it and the new private_rpc_auth
  field, so API keys embedded in vendor URLs stop leaking via
  tracing / panic output.
- Add allow_public_mempool bool (default false) as an explicit opt-in
  for testnet / dev.
- Config::validate refuses to start when a chain has a deployed
  liquidator but no private_rpc_url and has not opted in to public
  mempool; wired into the CLI before any submitter spins up.
- Rename BSC_PRIVATE_RPC_URL to CHARON_BSC_PRIVATE_RPC_URL in
  default.toml and .env.example; add CHARON_BSC_PRIVATE_RPC_AUTH for
  header-based vendors.
Close #194, #195, #196, #197, #200, #201, #202.

- Submitter::connect now takes &SecretString explicitly; no silent
  fallback to http_url exists anywhere.
- Reject any scheme other than https / wss at connect time
  (SubmitError::InsecureScheme). Covers http, ws, ftp, missing scheme.
- Typed SubmitError (#[non_exhaustive]) replaces anyhow, with
  Timeout / RpcRejected / ConnectionLost / InsecureScheme /
  InvalidEndpoint variants; RpcError is classified so 4xx / 429 map
  to RpcRejected while 5xx and transport-level failures map to
  ConnectionLost for the caller to reconnect.
- Optional bearer-token auth threaded through connect(); attached as
  a sensitive Authorization header for HTTP and via WsConnect::with_auth
  for WSS.
- Remove internal retry. submit() is single-shot: the pipeline owns
  the staleness / re-quote decision along with the opportunity queue
  TTL, not the transport layer.
- Debug impl on Submitter prints a scheme+host label only; the raw
  URL (which may embed an API key) never surfaces.
- httpmock-backed tests cover hash parsing, 429 / JSON-RPC error
  classification, single-shot timeout under tokio::time::pause, and
  ConnectionLost against a closed TCP port.
obchain added a commit that referenced this pull request Apr 23, 2026
BNB_TESTNET_WS_URL / BNB_TESTNET_HTTP_URL violate the repo-wide
CHARON_* namespace convention enforced on every new env var since
PR #42 and PR #44. The existing mainnet BNB_* vars predate the
convention and stay unrenamed pending a separate repo-wide pass —
only the testnet pair, landed this branch, shifts to the compliant
prefix.

Renames `config/testnet.toml` substitution references and updates
`.env.example` with a short note pointing at #245 so future readers
see the scope. The `config_profiles` integration test exports the
new names.

Closes #245
@obchain obchain changed the base branch from feat/18-gas-and-nonce to main April 24, 2026 12:05
…ubmit

# Conflicts:
#	.env.example
#	Cargo.lock
#	Cargo.toml
#	crates/charon-core/Cargo.toml
#	crates/charon-core/src/config.rs
#	crates/charon-core/src/lib.rs
#	crates/charon-executor/Cargo.toml
#	crates/charon-executor/src/lib.rs
@obchain obchain merged commit 2fa97f4 into main Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[executor] Private RPC submission for BSC (bloxroute / blocknative) + per-chain routing

1 participant