Skip to content

refactor(oracle): split generic relayer core - #416

Merged
ByteYue merged 1 commit into
mainfrom
codex/oracle-relayer-core
Aug 3, 2026
Merged

refactor(oracle): split generic relayer core#416
ByteYue merged 1 commit into
mainfrom
codex/oracle-relayer-core

Conversation

@ByteYue

@ByteYue ByteYue commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Split the generic Oracle execution and relayer core out of draft #368.

This PR depends on the already merged protocol prerequisites:

Part of Galxe/gravity-audit#1038 and follows the split finding in Galxe/gravity-audit#1033.

What changed

  • pin gravity-api-types to the merged Aptos API revision a64f8adc
  • read fixed-size NativeOracle source progress, with a pre-hardfork getLatestNonce/getRecord fallback
  • treat legacy latestNonce > 0 && latestPosition == 0 as an unknown transition position, never as source genesis
  • validate and re-encode the canonical (nonce, sourcePosition, callbackPayload) envelope before constructing recordBatch
  • preserve source type 0 and its existing 500,000 callback gas policy
  • decode both historical DataRecorded and current OracleDelivered events only from the NativeOracle emitter
  • decode current NonceNotSequential and four-length batch errors while retaining legacy error decoding
  • serialize polls for the same URI, persist empty finalized scans, and reconcile local cursor/nonce/position checkpoints
  • sort source events by nonce, require contiguous delivery, and fail the whole scan on malformed matching logs before advancing the cursor
  • validate URI coordinates against the registered (sourceType, sourceId)

Compatibility and activation

  • The external recordBatch ABI is unchanged.
  • Pre-hardfork state remains readable through the legacy progress fallback.
  • Historical and current NativeOracle delivery events are both accepted.
  • Existing source type 0 behavior and callback gas are preserved.
  • This PR intentionally contains no Binance/source type 3 provider, Polygon/source type 6 provider, provider-specific gas policy, resolver contract, live-network test, or demo code.
  • Runtime activation must wait for SDK PR 1 to consume latest_position and the updated relayer API. Merging the code alone does not activate the new wire shape.

Validation

  • cargo test -p reth-pipe-exec-layer-relayer --quiet
    • 20 passed, 1 ignored external-RPC test
  • cargo test -p reth-pipe-exec-layer-ext-v2 --lib -- --skip system_caller_migration::tests::test_migration_defensive_when_system_caller_absent
    • 94 passed, 0 failed, 1 explicitly filtered
  • cargo test -p reth-pipe-exec-layer-ext-v2 --lib onchain_config
    • 28 passed
  • cargo test -p reth-pipe-exec-layer-ext-v2 --lib extract_gravity_events
    • 3 passed
  • cargo check -p reth-pipe-exec-layer-relayer -p reth-pipe-exec-layer-ext-v2
  • cargo fmt --all -- --check
  • git diff --check
  • relayer Clippy completed successfully; remaining warnings are pre-existing in untouched relayer modules
  • changed-file scan found no credentials or user-specific absolute paths

Existing main failure

The unfiltered execute suite has one failure:

system_caller_migration::tests::test_migration_defensive_when_system_caller_absent

The same exact test and panic reproduce on clean origin/main at bc817c642, so it is not introduced by this PR. All other 94 execute tests pass here.

Review notes

The most important invariants to review are:

  1. unknown legacy positions replay from a safe watermark while filtering through the authoritative on-chain nonce
  2. callback execution receives only the inner payload after canonical wrapper validation
  3. malformed, duplicate, or gapped source events cannot advance a persisted cursor
  4. provider-specific behavior remains excluded from this core split

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +63 to +68
error OracleBatchArrayLengthMismatch(
uint256 noncesLength,
uint256 blockNumbersLength,
uint256 payloadsLength,
uint256 gasLimitsLength
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines 18 to 19
#[derive(Debug)]
enum StartupScenario {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@ByteYue
ByteYue merged commit c654278 into main Aug 3, 2026
36 of 39 checks passed
@ByteYue
ByteYue deleted the codex/oracle-relayer-core branch August 3, 2026 07:25
ByteYue added a commit to Galxe/gravity-sdk that referenced this pull request Aug 3, 2026
## 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
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.

3 participants