Skip to content

Phase A4 slice 1: adopt evm-fork-cache cold-start (V2/V3 planners) - #9

Merged
KaiCode2 merged 2 commits into
mainfrom
codex/phase-a4-slice1-cold-start
Jun 24, 2026
Merged

Phase A4 slice 1: adopt evm-fork-cache cold-start (V2/V3 planners)#9
KaiCode2 merged 2 commits into
mainfrom
codex/phase-a4-slice1-cold-start

Conversation

@KaiCode2

Copy link
Copy Markdown
Owner

Summary

Adopts the new protocol-neutral evm_fork_cache::cold_start mechanism. Replaces the imperative AmmAdapter::cold_start with a per-adapter ColdStartPlanner driven by EvmCache::run_cold_start, and replaces the cached_storage(..).is_none() proxy with the upstream per-slot SlotFetch classification (the archive-miss fix). V2/V3 only this slice — Balancer V2 (discover→verify) is slice 2; the reactive RepairAction::ColdStart executor is slice 3.

⚠️ Two merge caveats

  1. Interim dependency pin. evm-fork-cache is bumped from 27ae8762 to the cold-start-sync branch tip 903af3d (= 27ae8762 + the additive cold-start module), because evm-fork-cache#12 is not yet merged. The bump is purely additive. Re-pin to the main merge commit before merging this to evm-amm-state main.
  2. Stacked on #8. This branches off the A8 tip because it ports A8's *_strict_* / missing_liquidity cold-start tests. The diff shows A8 + slice-1 until Phase A8 (slice): adapter test-matrix hardening #8 merges — merge Phase A8 (slice): adapter test-matrix hardening #8 first.

What changed

New src/adapters/cold_start.rs (always-on — cold_start rides the default-on reactive feature we already depend on):

  • AdapterColdStartPlanner — upstream initial_plan/on_results + a finish hook mapping accumulated state + run report → ColdStartOutcome (mutating pool metadata/status).
  • private Bridge newtype forwarding to evm_fork_cache::cold_start::ColdStartPlanner (no trait-upcasting).
  • AdapterRegistry::cold_start(&mut PoolRegistration, &mut EvmCache, ColdStartPolicy) -> Result<ColdStartOutcome, ColdStartError> — resolves the adapter, drives the bounded loop, finalizes. Missing adapter / unsupported → Ok(Unsupported); an upstream ColdStartError propagates as Err.

Trait (traits.rs): cold_startcold_start_planner(&self, &PoolRegistration, ColdStartPolicy) -> Result<Box<dyn AdapterColdStartPlanner>, UnsupportedReason>.

V2 planner (single verify-only round): reproduces the prior end-state (slots 6/7/8, metadata merge preserving config fee_bps, Lazy/HotSlotsOnly), sourcing the reserves verdict from SlotFetch. Key improvement — a genuine on-chain Zero (degenerate → PurgeSlots) and a FetchFailed archive miss (→ VerifySlots) now produce distinct repairs.

V3 planner (multi-round): the prior current-tick-word warm-up re-expressed as data-dependent Continue rounds (slot0+liquidity → current-tick bitmap word → that word's initialized tick {0,3} slots); HotSlotsOnly stops after round 1, Lazy defers the word, a cold/unfetchable slot0 → NeedsRepair. The multi-word adaptive scan stays deferred (future Continue rounds — no upstream change needed). Config V3 metadata preserved.

Tests

  • New manager-authored tests/cold_start_adoption.rs (6 acceptance tests: the Zero-vs-FetchFailed distinction, Lazy==Eager invariant, V3 ready/missing-layout/failed-slot0).
  • The 14 existing trait-level cold-start tests in tests/adapter_reactive.rs ported to registry.cold_start(..), assertions' intent preserved (incl. the warm→ExactFromInput-no-resync synergy).
  • The 2 non-address-keyed cases in tests/adapter_a1.rs adapted to assert cold_start_planner(..) returns Err(Custom) (MockCache can't drive the EvmCache loop).
  • Spec: docs/phase-a4-slice1-spec.md.

Validation

Full CI matrix green locally: fmt; clippy default + adapters-only + no-default (-D warnings); cargo test default (109+22+4+28+6) + adapters-only + no-default; cargo doc -D warnings. The cold-start path compiles in the adapters-only (heavy-dep-free) build.

🤖 Generated with Claude Code

KaiCode2 and others added 2 commits June 23, 2026 13:41
Close the highest-value coverage gaps in the adapter layer while A4 cold-start
is blocked on evm-fork-cache. All additions are tests against existing,
unchanged production behavior (characterization + previously-untested paths).

Negative / malformed event-decode coverage (tests/adapter_a1.rs) — the
decode_event error branches had zero coverage. Calls decode_event directly and
asserts the exact AdapterEventResult:
- V2 Sync: wrong-topic ignored, malformed data, non-address-keyed pool.
- V3 Swap: malformed data, missing layout (Unsupported), non-address-keyed pool,
  no-topics / unknown-topic ignored.
- V3 Mint/Burn: malformed data; missing tick topics (confirmed caught by
  decode_log_data_validate — the explicit per-topic guards are defensive).
- Balancer V2 Swap: wrong-topic ignored, malformed data.
- cold_start: V2/V3 non-address-keyed -> Unsupported.

V3-family shifted-layout repair + policy coverage (tests/adapter_reactive.rs):
- Pancake V3 and Slipstream Mint repair target their shifted-layout slots
  (previously only Uniswap V3 was exercised; asserts != the Uniswap layout).
- Strict cold-start policy for V2/V3 (locks the current Strict==Eager behavior).
- V3 cold-start with a cold liquidity slot still reaches Ready (slot0 is the
  only mandatory slot; liquidity is reapplied by the next reactive Swap).

A coverage cross-check confirms every reachable decode error/ignore branch in
uniswap_v2 / uniswap_v3 / balancer_v2 now has a test; the untested branches are
unreachable behind decode_log_data_validate. Full CI matrix green (fmt; clippy
default + adapters-only + no-default; tests default + adapters-only + no-default;
cargo doc -D warnings). No production code changed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the imperative `AmmAdapter::cold_start` with a per-adapter
`ColdStartPlanner` driven by `EvmCache::run_cold_start`, and replace the
`cached_storage(..).is_none()` proxy with the upstream per-slot `SlotFetch`
classification (the archive-miss fix). V2/V3 only; Balancer = slice 2, reactive
`RepairAction::ColdStart` wiring = slice 3.

INTERIM dependency pin: evm-fork-cache is bumped from 27ae8762 to the
`cold-start-sync` tip (903af3d = 27ae8762 + the additive cold-start module),
since evm-fork-cache#12 is not yet merged to main. The bump is purely additive
(our existing code compiles unchanged). Re-pin to the main merge commit before
this consumer work merges to evm-amm-state main.

New `src/adapters/cold_start.rs` (always-on — the upstream `cold_start` module
rides the default-on `reactive` feature we already depend on):
- `AdapterColdStartPlanner` trait: the upstream initial_plan/on_results surface
  plus a `finish` hook that maps accumulated state + the run report into a
  `ColdStartOutcome` and mutates the pool's metadata/status.
- private `Bridge` newtype forwarding to `evm_fork_cache::cold_start::ColdStartPlanner`
  (no trait-upcasting).
- `AdapterRegistry::cold_start(&mut PoolRegistration, &mut EvmCache, ColdStartPolicy)
  -> Result<ColdStartOutcome, ColdStartError>`: resolves the adapter, drives the
  bounded loop, finalizes. Missing adapter / unsupported -> Ok(Unsupported); an
  upstream ColdStartError propagates as Err.

Trait change (`traits.rs`): `cold_start` -> `cold_start_planner(&self, &PoolRegistration,
ColdStartPolicy) -> Result<Box<dyn AdapterColdStartPlanner>, UnsupportedReason>`.

V2 planner (single verify-only round): reproduces the prior end-state (slots
6/7/8, metadata merge preserving config `fee_bps`, Lazy/HotSlotsOnly), sourcing
the reserves verdict from `SlotFetch`. The key improvement: a genuine on-chain
`Zero` (degenerate pool -> PurgeSlots) and a `FetchFailed` archive miss
(-> VerifySlots) now yield DISTINCT repairs.

V3 planner (multi-round): the prior current-tick-word warm-up re-expressed as
`Continue` rounds — round 1 slot0+liquidity, round 2 current-tick bitmap word,
round 3 that word's initialized tick {0,3} info slots; HotSlotsOnly stops after
round 1, Lazy defers the word, a cold/unfetchable slot0 -> NeedsRepair. The
multi-word adaptive scan stays deferred (future Continue rounds, no upstream
change needed). Config V3 metadata preserved.

Tests: new manager-authored `tests/cold_start_adoption.rs` (6 acceptance tests
incl. the Zero-vs-FetchFailed distinction and Lazy==Eager invariant). The 14
existing trait-level cold-start tests in `tests/adapter_reactive.rs` ported to
`registry.cold_start(..)`, assertions' intent preserved (incl. the slot0/reserves
warm -> exact-no-resync synergy). The 2 non-address-keyed cases in
`tests/adapter_a1.rs` adapted to assert `cold_start_planner(..)` returns
`Err(Custom)` (MockCache cannot drive the EvmCache loop). Spec at
`docs/phase-a4-slice1-spec.md`.

Full CI matrix green: fmt; clippy default + adapters-only + no-default
(-D warnings); tests default + adapters-only + no-default; cargo doc -D warnings.
The cold-start path compiles in the adapters-only (heavy-dep-free) build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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