Skip to content

refactor(events): rename the eth log event to chain-log#185

Open
mfw78 wants to merge 4 commits into
refactor/modules-tracing-macrosfrom
refactor/chain-logs-nomenclature
Open

refactor(events): rename the eth log event to chain-log#185
mfw78 wants to merge 4 commits into
refactor/modules-tracing-macrosfrom
refactor/chain-logs-nomenclature

Conversation

@mfw78

@mfw78 mfw78 commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #184.

Renames the chain-event log kind to chain-log at full depth (WIT, manifest, generated bindings, runtime dispatch, SDK, docs) so the on-chain event vocabulary no longer collides with the diagnostics logging pipeline, which is untouched.

This PR is stacked on #183 (refactor/modules-tracing-macros) and targets that branch; it carries only the chain-log rename and merges after #183 lands.

Changes

WIT (wit/nexum-host/types.wit and mirrored docs): record log renamed to record chain-log; event arm logs(list<log>) renamed to chain-logs(list<chain-log>). Fields unchanged, including log-index. The block, tick, message arms and the event envelope are untouched.

Generated bindings (wit-bindgen/wasmtime): types::Log to types::ChainLog; Event::Logs to Event::ChainLogs.

Manifest (manifest/types.rs): Subscription::Log to Subscription::ChainLog with #[serde(rename = "chain-log")]; every in-tree module.toml using the log kind (twap-monitor, ethflow-watcher) updated to kind = "chain-log". A manifest still carrying the retired kind = "log" now fails to load with an unknown-variant error that names the valid set (block, chain-log, cron).

Runtime chain-event path: subscribe_logs to subscribe_chain_logs; LogStream to ChainLogStream; open_log_streams to open_chain_log_streams; reconnecting_log_task to reconnecting_chain_log_task; TaggedLogStream to TaggedChainLogStream; log_streams to chain_log_streams; NextEvent::Log to NextEvent::ChainLog; dispatched_logs to dispatched_chain_logs; Supervisor::dispatch_log to dispatch_chain_log; log_subscriptions to chain_log_subscriptions; project_log to project_chain_log. Metric and event-kind labels (kind => "log", dispatch-kind "log", StreamPanic("log")) all become "chain-log", and the associated tracing message strings follow the same rename.

SDK and modules: strategy view LogView to ChainLogView; handler on_logs to on_chain_logs (twap-monitor, ethflow-watcher, shepherd-backtest replay, fixtures, and report); the on_chain_logs parameter and loop variable renamed from logs/log to chain_logs/chain_log; module Event::Logs match arms become Event::ChainLogs.

Untouched diagnostics boundary, deliberately: the entire host/logs/ subtree (LogRecord, LogRouter, RunLogStore, LogSource, LogPipeline, LogPage, LogRetentionLimits), [limits.logs], the nexum:host/logging WIT log: function and LoggingHost, stdio capture, and capture_tracing are all unchanged, since separating this vocabulary from the diagnostics one is the point of the rename. Ethereum RPC literals that genuinely mean eth_getLogs/eth_subscribe(logs) (alloy's subscribe_logs, the EthGetLogs method variant) are kept as-is, since those are the upstream wire names, not ours.

Docs updated: docs/02-modules-events-packaging.md, docs/00-overview.md, docs/01-runtime-environment.md, docs/05-sdk-design.md, docs/07-rpc-namespace-design.md, docs/08-platform-generalisation.md, docs/production.md, docs/diagrams/{diagrams.md, engine-boot.mmd, subscription-dispatch.mmd}, the top-level README.md, docs/operations/e2e-reports/e2e-report.template.md, and docs/operations/m3-testnet-runbook.md. Dated historical reports (e2e-report-2026-06-18, load-*) and ADR-0009 are left frozen, since they record what happened at the time.

Migration note added to docs/migration/0.1-to-0.2.md, covering the manifest kind change, the rebuild requirement for components built against the old world, and the on_logs to on_chain_logs handler rename.

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo doc --workspace --all-features -- -D warnings
  • cargo build --release --target wasm32-wasip2 for all 11 in-tree modules
  • cargo test --workspace --all-features (all suites green, no skipped tests)
  • Supervisor e2e e2e_ethflow_watcher_log_dispatch and e2e_twap_monitor_block_dispatch pass end-to-end against in-tree wasms, driving the renamed chain-logs subscription and Event::ChainLogs dispatch through the dispatch_chain_log path
  • New manifest test load_rejects_the_retired_log_kind confirms a stale kind = "log" manifest fails to load with an error naming the valid kind set
  • wasm-tools component wit on a built module confirms the shipped component carries the extended record chain-log (full RPC shape) and the batch-level record chain-logs carrying chain-id, with no old-shape log survivor
  • cargo test -p nexum-runtime covers project_chain_log_preserves_mined_log and project_chain_log_leaves_pending_fields_none, proving the host projection preserves every block-scoped field on a mined log and leaves them None, not zero-defaulted, on a pending log
  • Guest wasm size delta measured for twap-monitor (+353 bytes, +0.1 per cent) confirming alloy-rpc-types-eth pulls no new heavyweight dependency into the guest cone
  • docs/01-runtime-environment.md and docs/08-platform-generalisation.md WIT snippets verified consistent with the authoritative wit/nexum-host/types.wit

Notes for reviewer

This is a guest-visible world break: any component built against the previous WIT world (the log record, the logs event arm) no longer links against the current world and must be rebuilt, and any manifest with kind = "log" fails to load. Both are called out in the migration note.

The diagnostics logging pipeline is intentionally untouched throughout this diff; if you see a log token survive in the diff, check whether it is diagnostics-side (correct, leave it) or chain-event-side (should have been renamed) before flagging it.

Alloy log seam (appended)

The PR gained a second, related change on top of the rename: chain logs now cross the host-guest boundary as the real alloy_rpc_types_eth::Log type on both sides, rather than a bespoke payload. The guiding principle is no invented types at the seam: the wire vocabulary is exactly alloy's own RPC vocabulary, so there is no domain-specific log type of ours to keep in sync as alloy's Log evolves.

The seam shape is alloy Log on the host, converted to the WIT chain-log record for the wasm boundary, converted back to an alloy Log on the guest. Conversions live only at the two edges, project_chain_log on the host in supervisor.rs and assemble_log on the guest in nexum-sdk's new events module, so every consumer in between (runtime dispatch, module strategies, the backtest replay harness) operates on the same alloy Log type end to end instead of a bespoke intermediate view.

The chain-log WIT record was extended to the full RPC shape (block-hash, block-number, block-timestamp, transaction-hash, transaction-index, log-index, removed), each field's optionality mirroring alloy's own Option semantics rather than being defaulted away. The chain id was deliberately lifted out of the per-record chain-log and placed on a new batch-level chain-logs record instead, because alloy's Log itself carries no chain id and the supervisor already delivers logs per (module, chain, filter), so every log in one dispatch_chain_log batch shares a single chain by construction; stamping the chain id on each record would have been redundant, and lifting it let project_chain_log drop an argument.

The dependency verdict on alloy-rpc-types-eth (workspace pin 2.1, default-features = false, features = ["std"]) is that it is fully usable on wasm32-wasip2 and was added only to nexum-sdk; it built clean on the guest target and pulled in only the pure alloy primitives (consensus, eips, trie, serde, network-primitives) already transitively resident in the guest cone via cowprotocol. The measured guest wasm size delta for twap-monitor was 376240 to 376593 bytes, +353 bytes (+0.1 per cent), independently confirmed in review at +351 bytes; negligible, since Log is a thin envelope over primitives the guest already carried.

Net effect on conversion code is deletion: the host-side projection became lossless and intermediate-free, the guest gained a single conversion home (assemble_log plus one bind-macro-generated From<chain-log> for events::Log), and each consumer's bespoke view type was deleted outright, ChainLogView removed from both twap-monitor and ethflow-watcher, with their raw-bytes decode paths replaced by SolEvent::decode_log(&log.inner) against the real alloy type.

An adversarial review pass confirmed the round trip is lossless across every alloy Log field with correct Option semantics, then raised two non-blocking findings, both since fixed. docs/01-runtime-environment.md and docs/08-platform-generalisation.md still showed the pre-extension chain-log WIT snippet and lacked the batch-level chain-logs record; both are now aligned with the authoritative wit/nexum-host/types.wit. The host-side project_chain_log projection had no dedicated test; it is now covered by the two new nexum-runtime tests listed in the Test plan above.

AI Assistance: Claude Code (Opus 4.8 implementation and adversarial review, Sonnet 5 PR authoring) used for the full change.

mfw78 added 2 commits July 5, 2026 11:18
…config, and sdk

Rename the Ethereum contract-event-log concept (eth_getLogs /
eth_subscribe "logs") from `log`/`logs` to `chain-log`/`chain-logs`
throughout, so it no longer collides with the diagnostics logging
pipeline. The block, tick, and message events keep their names.

Wire (guest-visible world break, sanctioned pre-1.0): the WIT `log`
record becomes `chain-log` and the `logs(list<log>)` event arm becomes
`chain-logs(list<chain-log>)`. Record fields, including `log-index`,
are unchanged.

Config: the subscription `kind = "log"` becomes `kind = "chain-log"`.
The manifest discriminator renames to `ChainLog` with a `chain-log`
serde tag, so a stale `kind = "log"` manifest fails load with an
unknown-kind error naming the valid set (block, chain-log, cron).

Runtime: the chain-event subscription source and dispatch path rename
(subscribe_chain_logs, ChainLogStream, open_chain_log_streams,
dispatch_chain_log, the Subscription::ChainLog arm, and the stream
metric label). The diagnostics logging pipeline is untouched.

SDK and modules: guest bindings regenerate from the WIT as ChainLog /
Event::ChainLogs; the strategy view type becomes ChainLogView and the
handler becomes on_chain_logs across twap-monitor, ethflow-watcher, and
the backtest harness.

Docs: the event-kind nomenclature is swept across the module, overview,
sdk, and diagram pages, and the breaking world change is recorded in
the migration guide.
mfw78 added 2 commits July 5, 2026 12:30
Package chain-log deliveries as the native alloy_rpc_types_eth::Log
rather than an SDK-invented view. The WIT chain-log record now mirrors
the eth_getLogs shape field for field (adding block-hash,
block-timestamp, transaction-index, removed; widening the indices to
u64; making block-scoped fields optional for pending logs), so a guest
reconstructs the alloy log without loss.

The chain id moves off each record onto a new chain-logs batch record,
since a subscription delivery always shares one chain and the alloy log
carries no chain id of its own. The host projects an alloy Log straight
into the record with no intermediate; the SDK bind macro emits the
inverse conversion at the guest edge, so module glue maps a batch to
Vec<Log> and strategies decode sol! events against log.inner.

Migrate twap-monitor and ethflow-watcher onto &[Log], the backtest
replay harness onto the assemble_log constructor, and extend the WIT
and payload-shape docs.
The universal-world snippets in docs 01 and 08 kept the pre-rename
chain-log record while pointing the event arm at chain-logs, leaving both
files referencing an undefined type and listing stale fields. Reshape the
record to match the authoritative wit (optional block-scoped fields plus
removed) and add the chain-logs batch record that carries the chain id.

Add host-side coverage for project_chain_log on a mined log (every
block-scoped field present) and a pending log (each left None), closing
the projection's test gap.
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.

1 participant