refactor(oracle): split generic relayer core - #416
Conversation
Adopt the fixed-size OracleSourceState progress API and preserve legacy source type 0 delivery through the canonical NativeOracle batch envelope. Fail closed on malformed or non-sequential source data, reconcile known and unknown source positions, serialize same-URI polls, and persist empty scan cursors. Keep Binance and Polygon providers, provider gas policy, and SDK runtime wiring out of this split. Tracking: Galxe/gravity-audit#1038
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6365413498
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| error OracleBatchArrayLengthMismatch( | ||
| uint256 noncesLength, | ||
| uint256 blockNumbersLength, | ||
| uint256 payloadsLength, | ||
| uint256 gasLimitsLength | ||
| ); |
There was a problem hiding this comment.
Preserve decoding of the legacy batch-length error
When replaying or diagnosing a pre-upgrade block whose NativeOracle returns the former three-argument OracleBatchArrayLengthMismatch(uint256,uint256,uint256), its selector no longer matches this replacement four-argument declaration, so decode_revert_error classifies the known fatal contract error as an unknown revert. Keep a separately named legacy ABI declaration and handle both selectors to retain pre-hardfork error compatibility.
Useful? React with 👍 / 👎.
| #[derive(Debug)] | ||
| enum StartupScenario { |
There was a problem hiding this comment.
Keep the manager primary type before private helpers
Move the newly added private StartupScenario and SourceEntry helpers below OracleRelayerManager and its implementation. Placing them first buries the file's primary type and directly violates the repository's required Rust type-ordering convention for file-local helper types.
AGENTS.md reference: AGENTS.md:L403-L407
Useful? React with 👍 / 👎.
## Summary - wire `gravity_node` to the merged generic Reth Oracle relayer API - decode the fixed-size `OracleState` snapshot from the latest committed Gravity block - reconcile providers by the shared `(source_type, source_id)` URI identity - retain and re-emit a pending observation until the authoritative on-chain nonce catches up - suppress stale or already-committed observations before they become guaranteed-revert system transactions - keep provider endpoints validator-local and redact credentials, paths, and query strings from logs ## Runtime behavior `add_uri` now requires an authoritative on-chain source state before warming the Reth provider with its `latest_nonce` and `latest_position`. `get_last_state` follows the same snapshot and fails closed when `OracleState` is unavailable, malformed, or missing the requested source. After a provider returns an update, the wrapper caches that exact `PollResult`. While its nonce is ahead of the committed state, later observations return the cached payload instead of polling again. Once execution catches up, polling resumes. A provider result with `observed_nonce <= onchain_nonce` is marked unchanged so it cannot inject a `recordBatch` that must revert with `NonceNotSequential`. The state-read error path does not mutate the pending tracker, so a transient committed-state failure cannot erase an observation waiting for execution. ## Dependency alignment - pin Gravity Aptos to the merged Oracle state API revision from Galxe/gravity-aptos#79 - pin Gravity Reth to the merged generic relayer core plus dependency correction from Galxe/gravity-reth#416 and Galxe/gravity-reth#417 - align the node CLI and transaction-pool type aliases with Reth 2.3 - keep Alloy and Reth helper crates on versions compatible with the SDK Rust 1.93 toolchain The lockfile is necessarily large because the existing SDK branch moves from its older Reth/Aptos dependency graphs to those merged revisions. ## Non-goals - no Binance source implementation - no Polygon or Polymarket source implementation - no external-network E2E or frontend demo Those remain isolated provider and E2E slices in the split plan. ## Validation - `RUSTFLAGS='--cfg tokio_unstable' cargo +1.93.0 check -p gravity_node --tests --locked` - `RUSTFLAGS='--cfg tokio_unstable' cargo +1.93.0 test -p gravity_node relayer::tests --locked` (12 passed) - `cargo +nightly fmt --all -- --check` - `cargo +1.93.0 metadata --locked --no-deps --format-version 1` ## Tracking - Galxe/gravity-audit#1038 - Addresses Galxe/gravity-audit#908
Summary
Split the generic Oracle execution and relayer core out of draft #368.
This PR depends on the already merged protocol prerequisites:
OracleSourceState { source_type, source_id, latest_nonce, latest_position }Part of Galxe/gravity-audit#1038 and follows the split finding in Galxe/gravity-audit#1033.
What changed
gravity-api-typesto the merged Aptos API revisiona64f8adcgetLatestNonce/getRecordfallbacklatestNonce > 0 && latestPosition == 0as an unknown transition position, never as source genesis(nonce, sourcePosition, callbackPayload)envelope before constructingrecordBatchDataRecordedand currentOracleDeliveredevents only from the NativeOracle emitterNonceNotSequentialand four-length batch errors while retaining legacy error decoding(sourceType, sourceId)Compatibility and activation
recordBatchABI is unchanged.latest_positionand the updated relayer API. Merging the code alone does not activate the new wire shape.Validation
cargo test -p reth-pipe-exec-layer-relayer --quietcargo test -p reth-pipe-exec-layer-ext-v2 --lib -- --skip system_caller_migration::tests::test_migration_defensive_when_system_caller_absentcargo test -p reth-pipe-exec-layer-ext-v2 --lib onchain_configcargo test -p reth-pipe-exec-layer-ext-v2 --lib extract_gravity_eventscargo check -p reth-pipe-exec-layer-relayer -p reth-pipe-exec-layer-ext-v2cargo fmt --all -- --checkgit diff --checkExisting main failure
The unfiltered execute suite has one failure:
system_caller_migration::tests::test_migration_defensive_when_system_caller_absentThe same exact test and panic reproduce on clean
origin/mainatbc817c642, so it is not introduced by this PR. All other 94 execute tests pass here.Review notes
The most important invariants to review are: