test(ledger-suite-orchestrator): migrate integration tests to PocketIC - #10949
Conversation
Add a PocketIC-based test fixture (LedgerSuiteOrchestrator, AddErc20TokenFlow, ManagedCanistersAssert, UniversalCanister, new_pocket_ic()) alongside the existing StateMachine one in test_utils, and migrate tests/tests.rs to it. The StateMachine fixture stays untouched at its current paths since rs/ethereum/cketh still consumes it; it will be deleted once cketh migrates to PocketIC in a later PR of this stack. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR migrates the ledger-suite-orchestrator integration tests from the ic-state-machine-tests harness to PocketIC by introducing a parallel PocketIC-based fixture in test_utils and switching tests/tests.rs to use it, while leaving the existing StateMachine fixture in place for downstream users (e.g., ckETH) until later PRs in the stack.
Changes:
- Added a new PocketIC-based test fixture module (
test_utils/src/pocket_ic) including orchestrator setup, flows/assert helpers, and a PocketIC universal canister helper. - Migrated
rs/ethereum/ledger-suite-orchestrator/tests/tests.rsto use the new PocketIC fixture and PocketIC error types/APIs. - Updated Cargo/Bazel dependencies to include PocketIC and PocketIC-enabled metrics assertions, and wired PocketIC server binary into the Bazel
rust_ic_test.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| rs/ethereum/ledger-suite-orchestrator/tests/tests.rs | Migrates the integration tests to the new PocketIC fixture and updates calls/assertions accordingly. |
| rs/ethereum/ledger-suite-orchestrator/test_utils/src/pocket_ic/mod.rs | Introduces the PocketIC-based LedgerSuiteOrchestrator fixture and PocketIC builder/helpers. |
| rs/ethereum/ledger-suite-orchestrator/test_utils/src/pocket_ic/flow.rs | Adds PocketIC-based test flows and managed-canister assertions used by the migrated tests. |
| rs/ethereum/ledger-suite-orchestrator/test_utils/src/pocket_ic/universal_canister.rs | Adds a PocketIC-based universal canister helper for management-canister interactions in tests. |
| rs/ethereum/ledger-suite-orchestrator/test_utils/src/lib.rs | Exposes the new pocket_ic module alongside existing test utilities. |
| rs/ethereum/ledger-suite-orchestrator/test_utils/Cargo.toml | Enables ic-metrics-assert PocketIC feature and adds a pocket-ic dependency. |
| rs/ethereum/ledger-suite-orchestrator/test_utils/BUILD.bazel | Switches to the PocketIC-enabled ic-metrics-assert Bazel target and adds //packages/pocket-ic. |
| rs/ethereum/ledger-suite-orchestrator/Cargo.toml | Drops ic-state-machine-tests from test deps and adds pocket-ic. |
| rs/ethereum/ledger-suite-orchestrator/BUILD.bazel | Adds PocketIC server binary + env wiring for the Bazel test target and updates deps accordingly. |
| Cargo.lock | Updates lockfile for the new pocket-ic dependency wiring. |
Comments suppressed due to low confidence (1)
rs/ethereum/ledger-suite-orchestrator/tests/tests.rs:93
- This expectation hardcodes a specific principal string for the index canister. To keep the test invariant across PocketIC ID allocation changes, assert the metadata equals the actual
index_idobtained fromManagedCanisterIds.
MetadataKey::parse(MetadataKey::ICRC106_INDEX_PRINCIPAL).unwrap(),
LedgerMetadataValue::from("xbze6-vd777-77777-aaaba-cai"),
),
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
🤖🧐 VERDICT: CHANGES_REQUESTED — 0 blockers, 2 mediums, 6 nits; CI pending (22 pass / 7 pending / 0 red — Neither medium is a semantics problem: the port itself is faithful. Both are the same finding — two Review detailsVerified by running
(Plain Faithfulness of the port
Scope / boundary
Maintainability accounting
Test pyramidNot applicable as a coverage question — this is a harness migration with no production-behaviour change, so "a new test per behaviour change" is satisfied by the existing suite continuing to pass unmodified in content. |
LedgerSuiteOrchestrator and ManagedCanistersAssert each carried an AsRef<PocketIc> impl left over from porting the StateMachine fixture, where it satisfied `T: AsRef<StateMachine>` bounds on stop_canister/ out_of_band_upgrade and a manual CanisterHttpQuery impl. Those call sites now take `&PocketIc` directly and go through PocketIcHttpQuery, so neither impl has a caller left (G9/G12). Addresses review comments: #10949 (comment) #10949 (comment) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- mod.rs: replace 13 inline `crate::` paths (default_init_arg, the wasm
loaders, GIT_COMMIT_HASH, MAX_TICKS) with a single `use crate::{...}`
block, matching the plain `use crate::MINTER_PRINCIPAL;` style already used
in the sibling flow.rs. This also lets wait_for's panic message go back to
inline-capture ("...{MAX_TICKS} ticks...") instead of a positional arg.
- mod.rs: alias `ic_cdk::management_canister::CanisterStatusResult` as
`CdkCanisterStatusResult` to disambiguate it from the
`ic_management_canister_types::CanisterStatusResult` imported in the same
file, instead of spelling out the full path twice.
- flow.rs: import `ic_management_canister_types::CanisterId` instead of
fully qualifying it once, for the same reason mod.rs already imports it.
Addresses review comments:
#10949 (comment)
#10949 (comment)
#10949 (comment)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ledger_canister_status() returns an owned CanisterStatusResult temporary, so module_hash can be moved straight out of it instead of being cloned first (R3). Addresses review comment: #10949 (comment) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This comment was carried over verbatim from the StateMachine fixture and still referenced "10ms per transfer with state machine tests" inside the module that specifically does not use StateMachine (C2). Dropping the parenthetical rather than guessing a PocketIC-specific number. Addresses review comment: #10949 (comment) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
//:pocket-ic-server was listed in both `data` (needed for the $(rootpath //:pocket-ic-server) used by POCKET_IC_BIN) and `deps`. It's a runtime binary reached only through that env var, not linked, so `data` alone is the accurate declaration -- matching rs/ledger_suite/icp/BUILD.bazel (data only), as opposed to rs/bitcoin/checker and rs/dogecoin/ckdoge/minter (deps only, where the binary is invoked differently). Verified bazel test //rs/ethereum/ledger-suite-orchestrator:integration_tests still passes (POCKET_IC_BIN resolves fine from data alone). Addresses review comment: #10949 (comment) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🤖🧐 VERDICT: READY (re-review of Re-review detailsPer-finding resolution
Copilot's thread on Verified by running (on
|
| Command | Result |
|---|---|
bazel test //rs/ethereum/ledger-suite-orchestrator:integration_tests --nocache_test_results (dev container) |
PASSED in 15.2s, 1/1 |
cargo check --all-targets --all-features -p ic-ledger-suite-orchestrator-test-utils -p ic-ledger-suite-orchestrator |
clean, no warnings |
git diff --stat 522634fb44 de18dda2f9 |
10 files, all under rs/ethereum/ledger-suite-orchestrator/ + Cargo.lock — component boundary still respected |
| old-fixture check | test_utils/src/{flow,universal_canister}.rs still byte-identical to master; lib.rs still +1 line (pub mod pocket_ic;) |
Nothing new introduced
The five commits are strictly subtractive or rename-only — no call sites, senders, tick sequences, or assertions were touched. The faithfulness conclusions from the first pass (21/21 tests, identical function-name set, API mapping per spec, preserved tick semantics and assertion strength) still hold; the net effect on the diff is −14 lines.
One forward-looking note for PR 4: consolidating into a single use crate::{...} block makes the hoist easier than the scattered crate:: prefixes did — if pocket_ic/mod.rs is merged into lib.rs, that one import line is deleted rather than 13 path prefixes rewritten. No action needed here.
Outstanding
Only CI. Nothing is red, but Bazel Test All, Bazel Test arm64-{linux,darwin}, Cargo Build/Lint Linux, Build IC, Lock Generate, Candid compatibility checks, Autofix, Bazel Run Fuzzers and RBE / Infer Bazel Targets were still running when this verdict was written. Final approval and merge are the human's call.
…ty#10947) Adds a single end-to-end test proving the ckERC20 balance scan works against a real EVM, complementing the existing mock-based integration tests. The test drives the full production path — minter → **real EVM RPC canister** → Ethereum — with no JSON-RPC mocking: - A new PocketIC *live* harness in the cketh `test_utils` crate owns a local `anvil` node and installs the minter and the EVM RPC canister, configuring the latter with an `overrideProvider` that routes every provider to that node. In live mode the EVM RPC canister issues genuine HTTPS outcalls that reach anvil for real. The new harness is required because current integration tests infrastructure uses the `StateMachine` that cannot issue real HTTP request. Migrating the integration test infrastructure to PocketIC is deferred to DEFI-2262 (see dfinity#10949). - Supported tokens (ckUSDC, ckUSDT) are registered directly through the minter's `add_ckerc20_token` endpoint by pointing its orchestrator id at a principal the harness controls, so no real orchestrator or spawned ledgers are needed. - The harness places the two tokens at their real mainnet addresses on anvil (`anvil_setCode`) and credits the minter's derived deposit address above the candidate threshold (`anvil_setStorageAt`). The test then asserts the minter's periodic scan reads those real balances and flags the address as a deposit candidate for both tokens. Stacked on top of dfinity#10873. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: IDX GitHub Automation <infra+github-automation@dfinity.org>
The StateMachine fixture had to address the management canister itself to upgrade a canister as its controller. PocketIc exposes that directly and builds the very same install_code argument, down to the install mode, so call it instead of assembling the argument by hand. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
✅ No security or compliance issues detected. Reviewed everything up to e0c6621. Security Overview
Detected Code Changes
|
…rals in integration tests (dfinity#10950) ## Summary Small preparatory cleanup for the cketh integration tests ahead of the PocketIC migration (DEFI-2262). No framework change here — tests still run on `ic-state-machine-tests` and stay green. - Deduplicated the inline raw-transaction and transaction-hash string literals in `minter/tests/cketh.rs` that were byte-identical to the `DEFAULT_WITHDRAWAL_TRANSACTION` / `DEFAULT_WITHDRAWAL_TRANSACTION_HASH` constants already exported by `cketh/test_utils`. Since PR 3 regenerates these signatures for the PocketIC fixture, keeping every occurrence tied to the single constant means the regeneration only needs to touch one place instead of risking a missed or inconsistent literal. ## 📚 PR stack 1. dfinity#10949 — test(ledger-suite-orchestrator): migrate integration tests to PocketIC 2. **dfinity#10950 — test(cketh): deduplicate signed-transaction literals in integration tests** 👈 you are here 3. dfinity#10955 — test(cketh): migrate integration tests to PocketIC 4. dfinity#10956 — test(ledger-suite-orchestrator): drop the StateMachine test fixture 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
## 📚 PR stack 1. ~~dfinity#10949~~ — test(ledger-suite-orchestrator): migrate integration tests to PocketIC (merged) 2. ~~dfinity#10950~~ — test(cketh): deduplicate signed-transaction and transaction-hash literals (merged) 3. **dfinity#10955 — test(cketh): migrate integration tests to PocketIC** 👈 you are here 4. ~~dfinity#10956~~ — test(ledger-suite-orchestrator): drop the StateMachine test fixture — **its content is part of this PR**, see below Follow-up, based on this PR: dfinity#11123 (PocketIC server lifetime). ## Summary Flips `rs/ethereum/cketh/test_utils` and the minter's `cketh.rs`/`ckerc20.rs` integration tests from `ic-state-machine-tests` onto the sync `pocket_ic` client, following the pattern established for the ledger-suite-orchestrator in dfinity#10949. The minter is now initialized against the fiduciary subnet's `"key_1"` ECDSA key (StateMachine's `"master_ecdsa_public_key"` isn't available on PocketIC's fiduciary subnet), which changes the minter's derived Ethereum address. Every signature-derived constant is regenerated as a consequence: `MINTER_ADDRESS`, `DEFAULT_WITHDRAWAL_TRANSACTION(_HASH)`, `DEFAULT_CKERC20_WITHDRAWAL_TRANSACTION(_HASH)`, the r/s of the default ERC20 signed transaction, the per-account deposit address in `should_record_address_to_deposit`, and the resubmitted-transaction literal in `should_resubmit_new_transaction_with_same_max_fee_per_gas_when_price_increased`. Canister-http mocking is rebuilt around PocketIC's `get_canister_http()` / `mock_canister_http_response()`, preserving the legacy `"Http body exceeds size limit of {n} bytes."` reject that the minter's response-size check matches on. `tests/dump_stable_memory.rs` and `tests/deposit_from_cex_demo.rs` are untouched. ## Also included: dropping the StateMachine fixture from the orchestrator This was meant to be a separate PR (dfinity#10956) reviewed on top of this one. It was marked merged by mistake — see [the note there](dfinity#10956 (comment)) — and since GitHub cannot reopen a merged PR, its content stays here rather than being shuffled again. With the ckETH minter's tests on PocketIC, nothing in `rs/ethereum` uses the orchestrator's StateMachine-based fixture, so it is deleted along with the now-unused `ic-state-machine-tests`, `ic-types`, `ic-management-canister-types-private` and `assert_matches` dependencies. The environment-agnostic helpers the `pocket_ic` module and cketh still import (wasm loaders, init-arg builders, `usdc()`/`usdt()`, constants) stay at their existing paths. After this PR, no Rust target under `rs/ethereum` compiles against `ic-state-machine-tests`. ## Behavioural differences PocketIC forces, and how they are handled PocketIC differs from StateMachine in two ways the tests are sensitive to. Both are handled in the fixture, in one place each, rather than worked around per test. **Time advances kill the outcalls in flight.** PocketIC fails canister-http requests once they cross `CANISTER_HTTP_TIMEOUT_INTERVAL`; StateMachine left them pending indefinitely. The requests also stay listed until a round processes the failures, so a stub could bind to a request that was already dead and see its response discarded. Worse, a scraping cycle awaiting such a request keeps holding its `TimerGuard`, so the firing due at the new time is dropped as `AlreadyProcessing` and the query the test expects is never issued. `CkEthSetup::advance_time` therefore fails those outcalls up front and deterministically, doing what the advance would have done anyway. It is a no-op when nothing is in flight, because a fixture that has executed no round is expected to trigger the first scraping cycle itself. **A stop request takes effect only in the following round.** The outcalls the minter's timers issue in that last running round become visible after it, so `stop_minter` ticks once before draining them. The block number stubs also now match on `["finalized", false]`, which is what the scraping cycle actually queries — unconstrained, they could be consumed by the block height refresh timer's query for the latest block. ## Runtime Measured against master with identical in-test instrumentation on both sides: **+5% (ckETH) and +11% (ckERC20)** of wall-clock at default parallelism (+15%/+20% single-threaded). Fixture-light tests are indistinguishable from master; the difference tracks the number of IC rounds a test drives, since PocketIC runs out of process. The dominant cost in both harnesses is tests that rebuild the whole fixture several times within one `#[test]`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Migrates the ledger-suite-orchestrator (LSO) integration tests from the internal
ic-state-machine-testsharness to PocketIC, following the pattern already used for the EVM-RPC canister (dfinity/evm-rpc-canister#294). This is DEFI-2262: a pure refactor of the test harness — same tests, same coverage, same semantics.CkErc20Setupinrs/ethereum/ckethembeds LSO's fixture and shares aStateMachinewith it, so flipping LSO's fixture in place would break cketh in the same commit. To keep this change single-component and the tree green, this PR adds a PocketIC fixture in LSO'stest_utilsalongside the existing StateMachine one (precedent:rs/ledger_suite/icp/test_utils'sstate_machine_helpers/pocket_ic_helperscoexisting) and migrates onlyledger-suite-orchestrator/tests/tests.rsto it. The StateMachine fixture stays untouched at its current paths and is still exercised bycketh; it is deleted only in the last PR of this stack, once cketh no longer needs it.Summary of changes
pocket_icmodule inledger-suite-orchestrator/test_utils(LedgerSuiteOrchestrator,AddErc20TokenFlow,ManagedCanistersAssert,UniversalCanister,new_pocket_ic()), mirroring the existing StateMachine-based types and method names one-for-one so later PRs in the stack only need to swap import paths.new_pocket_ic()builds a system subnet (LSO tests assert exact cycle balances, which only hold on a non-charging subnet) with canister-execution rate limiting disabled (LSO repeatedly installs/upgrades ledger, index and archive canisters).ic-metrics-assert'sPocketIcHttpQuery(featurepocket_ic) instead of a hand-rolledCanisterHttpQueryimpl.tests/tests.rsfully migrated to the new fixture.Cargo.toml/BUILD.bazelupdated accordingly;test_utilskeepsic-state-machine-testsfor now (still needed by the old fixture).Coverage
tests/tests.rsfully migrated, old fixture/paths untouched,ckethstill builds against the untouched fixture.📚 PR stack
test(ledger-suite-orchestrator): drop the StateMachine test fixture #10956— test(ledger-suite-orchestrator): drop the StateMachine test fixture (wrongly marked merged; its content is part of test(cketh): migrate integration tests to PocketIC #10955)🤖 Generated with Claude Code