feat(host): add backend component traits over the concrete pools#99
Conversation
| fn request( | ||
| &self, | ||
| chain_id: u64, | ||
| method: &str, |
There was a problem hiding this comment.
Cleanup should be file at a later time whereby the typing should be stronger on this such that the methods should be GET / PUT/ DELETE etc, which are all enums, so can use some enum with IntoStaticStr perhaps (look at existing crates to reduce implementation scope).
| /// REST passthrough against the chain's orderbook base URL. | ||
| fn request( | ||
| &self, | ||
| chain_id: u64, |
There was a problem hiding this comment.
The chain_id can likely be strictly typed as well and from alloy_chains
| /// Open a `newHeads` block subscription on `chain_id`. | ||
| fn subscribe_blocks( | ||
| &self, | ||
| chain_id: u64, |
There was a problem hiding this comment.
chain_id can likely be strictly typed and from alloy_chains
| method: String, | ||
| params_json: String, |
There was a problem hiding this comment.
Check if there is anything in the alloy RPC types that can be used in place of raw method / params such that we can also close out security problems for potential eth_sign injection.
| /// Outbound HTTP backend for `http::fetch` (post-allowlist). | ||
| pub trait HttpClient { | ||
| /// Execute `req` and return the response. | ||
| fn fetch(&self, req: Request) -> impl Future<Output = Result<Response, HostError>> + Send; |
There was a problem hiding this comment.
Check if these Request / Response actually come from some inherent types already
| @@ -0,0 +1,18 @@ | |||
| //! Randomness seam mirroring the direct `getrandom::fill` call in the | |||
There was a problem hiding this comment.
Check if there's some natively injected randomness available from wasmtime
| /// Per-module key-value handle; mirrors the inherent `ModuleStore` API. | ||
| pub trait StateHandle { | ||
| /// Fetch a value; `Ok(None)` when absent. | ||
| fn get(&self, key: &str) -> Result<Option<Vec<u8>>, StorageError>; | ||
| /// Insert or overwrite. | ||
| fn set(&self, key: &str, value: &[u8]) -> Result<(), StorageError>; | ||
| /// Delete; idempotent. | ||
| fn delete(&self, key: &str) -> Result<(), StorageError>; | ||
| /// Enumerate module-visible keys starting with `prefix`. | ||
| fn list_keys(&self, prefix: &str) -> Result<Vec<String>, StorageError>; | ||
| } |
There was a problem hiding this comment.
Walking across the WASM boundary is expensive, therefore if there are batch operations to be done, such should be available to be done so that a transaction can be represented as a sequence of get/get_many/set_setmany, and potentially look at some combinators / filters so that filter of keys / values can be done within the WASM host side and not in the runtime necessarily before it crosses the boundary. At the same time, file another issue as we need to check if host resource use during some host function call counts for fuel in wasmtime (don't want to allow unlimited time to be burnt on host calls).
What
Adds the backend component seam: a new
host::componentmodule defining traits over the concrete capability backends.ChainProvider,CowApi, andHttpClientare async (declared inimpl Future + Sendform so generic consumers can hold the futures across await points in tokio tasks; deliberately not dyn-compatible, since the forthcoming runtime-generic layer consumes them through generic bounds only).StateStorewith its per-moduleStateHandle,Clock, andRandomstay sync, mirroring the underlying operations. The existing backends implement them in place:ProviderPool,OrderBookPool,LocalStore/ModuleStore, plus injectable defaultsSystemClock,OsRandom, andUnsupportedHttpwhose behaviour is identical to today's direct calls (including the byte-identical HTTP stub message).The change is purely additive: no caller,
HostState, supervisor, or dependency changes. Method shapes mirror the existing inherent signatures one-to-one, delegation is fully qualified to avoid name-shadowing recursion, and a conformance test module pins trait satisfaction, trait-versus-inherent dispatch equivalence, and the clock/random behaviour.Why
The concrete pools are wired directly into
HostState, so backends cannot be swapped or faked. This seam is the foundation theRuntimeTypesassociated-type lattice, the component builders, and the mock runtime preset all build on; landing it additively keeps the risk of the later generic refactor contained.Closes #85 (part of the epic in #77).
Testing
Full workspace verification through the nix dev shell (fmt, clippy with
-D warnings, rustdoc with-D warnings, tests), all green. The newhost::componenttests pass 4/4, including a trait-dispatch-equals-inherent-dispatch check againstProviderPooland behavioural checks onSystemClockandOsRandom. Every mirrored signature was verified against the real inherent method before writing; no mismatches.AI Assistance: Claude Code used for implementation, adversarial review, and PR preparation.