feat(chain): typed chain-error with an rpc case carrying revert bytes#214
Open
mfw78 wants to merge 1 commit into
Open
feat(chain): typed chain-error with an rpc case carrying revert bytes#214mfw78 wants to merge 1 commit into
mfw78 wants to merge 1 commit into
Conversation
Replace the unified host-error return of nexum:host/chain with a typed chain-error variant: a shared fault or a structured rpc-error record carrying the node code and any revert payload. The host now hex-decodes the upstream JSON-RPC error.data once into raw bytes, so a guest receives the abi-encoded revert body directly and hands it straight to decode_revert; the quote-stripping decode_revert_hex bridge is deleted. Project ProviderError into the new shape in host/error.rs: a structured ErrorResp becomes chain-error.rpc, and a transport failure classifies into a fault (timeout, unavailable, rate-limited). Mirror ChainError and RpcError in nexum-sdk with a HostFault impl and a From<ChainError> for HostError bridge so a module can still bubble a chain failure out of on_event. Update the wit-bindgen adapter, the chainlink helper, and the twap-monitor poll path to the typed surface.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #209; part of the typed-fault train stacked on the epic-80 stack, merges in stack order.
This gives the chain interface a typed error shape instead of the unified
host-errorenvelope. Guests no longer trim and hex-decode a JSON-quoted revert string by hand, and a JSON-RPC error code travels as a propers32instead of being smushed into a domain-relative field.Changes
wit/nexum-host/chain.witaddsrecord rpc-error { code: s32, message: string, data: option<list<u8>> }andvariant chain-error { fault(fault), rpc(rpc-error) }.request,request-batch, andrpc-result.errall carrychain-errorin place ofhost-error.provider_pool.rshex-decodes the upstream JSONerror.dataonce, in the request closure, soProviderError::Rpc.dataisOption<Vec<u8>>rather than a raw string.host/error.rsreplacesFrom<ProviderError> for HostErrorwithFrom<ProviderError> for ChainError. A structuredErrorRespbecomesChainError::Rpc; a transport failure becomesChainError::Faultvia a newtransport_faultclassifier (429 to rate-limited, 503 or backend-gone or pubsub to unavailable, a timeout substring to timeout, otherwise unavailable). A denied request becomes a chain-specificchain_deniedthat also returnsChainError.host/impls/chain.rsupdatesrequest,request_batch, andresolve_methodto returnChainError.nexum-sdkmirrorsRpcErrorandChainErroron the guest side, implementsHostFaultforChainError, and adds aFrom<ChainError> for HostErrorbridge soinitandon_event(which still returnhost-errorpending their own migration) can bubble a chain failure without a breaking signature change.decode_revert_hexis deleted;decode_revert(&[u8])is now the sole entry point, taking raw bytes rather than a hex string.modules/twap-monitorand the three example modules are updated to match: the poll path matchesChainError::Rpctodecode_revert(bytes)andChainError::FaulttoTryNextBlock.Test plan
cargo fmt --all --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace --all-features(all green, including doctests)chain.wit;nexum-runtime supervisor::tests::e2eandtwap_monitor_without_cow_extension_fails_to_bootpass against the rebuilt wasm, which exercises the regenerated world and thewit-bindgenchain-error adapter link in a real componentprovider_pool, RPC code preservation (including out-of-range saturation to the internal fallback code), and the timeout, unavailable, backend-gone, and rate-limited fault classificationsNotes for reviewer
The decode lives in
provider_pool, where alloy'sErrorPayloadis already being inspected, so theFrom<ProviderError> for ChainErrorimpl inerror.rsstays a pure projection over already-decoded bytes. A non-hexerror.data(a structured object rather than a revert string) decodes toNone, which matches the olddecode_revert_hexbehaviour for a non-revert payload.The rpc-versus-fault split keys on whether a code is present: a JSON-RPC
ErrorRespalways carries one, a transport failure never does, so the existing capture logic discriminates the two cleanly without new state.host-erroris deliberately untouched on every other interface (local-store, messaging, identity, remote-store, cow-api) and oninit/on_event; those migrate on their own steps in this train, which is why the SDK carries aFrom<ChainError> for HostErrorbridge for now rather than a wider signature change.Rate-limited was added to the transport classifier for a 429 response even though the issue named only timeout and unavailable; it is a faithful mapping onto the
rate-limitrecord already present in the shared fault vocabulary, not scope creep.Follow-ups intentionally left out of this PR: parsing a structured retry-after hint from rate-limit backoff into
Fault::RateLimited.retry_after_ms(currently alwaysNone); migrating the remaining interfaces offhost-errorso the bridge can eventually retire; and a short rustdoc note onrequest-batchdistinguishing a whole-batch fault from a per-entryrpc-result.err.AI Assistance: Claude Code (Opus 4.8 implementation and adversarial review, Sonnet 5 PR authoring) used for the full change.