Deterministic Rocket Pool RocketStorage Upgrade Verification Gate
rsg is a standalone, open-source CLI tool and library ecosystem that deterministically replays Rocket Pool protocol upgrades and verifies whether the upgrade transaction produced exactly the declared RocketStorage mutations and external calls—with no undeclared side effects.
Targeting the executed Rocket Pool v1.4 / Saturn 1 mainnet upgrade, rsg compares observed on-chain state mutations against a reviewed, source-anchored expected-effects manifest and generates a cryptographic proof bundle with reproducible PASS, FAIL, or UNKNOWN attestations.
Standard smart contract verification confirms that published source code, bytecode, and deployed contract addresses match. However, it leaves a critical gap:
Did the upgrade transaction make every expected typed RocketStorage change—and absolutely no undeclared or malicious changes?
RocketStorage uses opaque bytes32 keys and generic typed mutators (setUint, setAddress, setBool, deleteAddress, addUint, etc.). Raw transaction traces display only obscure hashes and hex values. rsg adds the missing semantic decoding layer, translating raw keys into human-auditable paths and strictly verifying them against an independently authored and reviewed manifest.
rocket_storage/
├── Cargo.toml
├── rust-toolchain.toml
├── key-catalogue.yaml # Canonical catalogue of RocketStorage keys
├── crates/
│ ├── rsg-types/ # Shared data model, serialization, and error types
│ ├── rsg-decode/ # Keccak256 key decoder & semantic dictionary
│ ├── rsg-capture/ # Live archive RPC tracer (alloy 2.x callTracer)
│ ├── rsg-compare/ # Strict verdict engine (PASS / FAIL / UNKNOWN)
│ ├── rsg-attest/ # Proof bundle generator (JSON + Markdown reports)
│ └── rsg-cli/ # Command-line interface (`rsg`)
├── fixtures/v1.4-mainnet/
│ └── frozen-trace.json # Canonical frozen upgrade trace
├── manifests/v1.4-mainnet/
│ ├── manifest.yaml # Source-anchored expected effects manifest
│ └── review-record.json # Dual-signoff reviewer record
└── tests/
└── adversarial/ # 11 adversarial test fixtures testing all failure modes
| Parameter | Value |
|---|---|
| Protocol Upgrade | Rocket Pool v1.4 / Saturn 1 |
| Network | Ethereum Mainnet (Chain ID: 1) |
| Pre-upgrade Block | 24,479,993 |
| Execution Block | 24,479,994 |
| Upgrade Contract | 0x5b3B5C76391662e56d0ff72F31B89C409316c8Ba |
| Upgrade Transaction | 0x2fc10aad3c1b00bdfa9b6fddab79e0f2688609848f8f7a1a6449ab42da38530c |
| RocketStorage | 0x1d8f8f00cfa6758d7bE78336684788Fb0ee0Fa46 |
| Source Commit | fb7d9c428dc3dddc3fbd3e634e3cb365655df89e |
Requirements: Rust toolchain (2024 edition, Rust 1.85+).
# Build the workspace
cargo build --release
# Run all unit and integration tests
cargo testBinary is output at target/release/rsg.
Verify an upgrade trace against the reviewed manifest without network access:
rsg attest \
--fixture fixtures/v1.4-mainnet/frozen-trace.json \
--manifest manifests/v1.4-mainnet/manifest.yaml \
--review-record manifests/v1.4-mainnet/review-record.json \
--output-dir attestations/v1.4-mainnet/Capture the upgrade trace directly from an Ethereum archive node RPC:
rsg capture \
--rpc-url https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY \
--output fixtures/v1.4-mainnet/frozen-trace.jsonOr combine capture and attestation in a single run:
rsg attest \
--rpc-url https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY \
--manifest manifests/v1.4-mainnet/manifest.yaml \
--review-record manifests/v1.4-mainnet/review-record.json \
--output-dir attestations/v1.4-mainnet/Decode an arbitrary bytes32 RocketStorage key into its human-readable semantic path:
rsg decode-key 0x11b1f53204d03a3a08dc0a52f30bb09ab26aeb2b07023ce8b7b8aef1c1fa3e9frsg implements fail-closed verification designed for automated CI/CD pipelines:
| Verdict | Exit Code | Description |
|---|---|---|
PASS |
0 |
All observed mutations and external calls match the reviewed manifest exactly. |
FAIL |
1 |
A known requirement is violated (e.g., undeclared write, wrong value, duplicate mutation, unexpected call). |
UNKNOWN |
2 |
An undecodable key, unsupported call format, or incomplete trace was encountered. Fails closed. |
The test suite includes 11 dedicated adversarial test cases validating that every failure mode halts with the exact expected verdict:
undeclared-write.json: An unmanifested mutation occurs →FAIL(UndeclaredMutation)wrong-uint.json: New value differs from declared →FAIL(WrongNewValue)swapped-address.json: Address points to incorrect contract →FAIL(WrongNewValue)missing-deletion.json: Required deletion was not executed →FAIL(MissingRequiredEffect)duplicate-mutation.json: Multiple writes to the same key →FAIL(MultiplicityMismatch)wrong-multiplicity.json: Effect count does not match requirement →FAIL(MultiplicityMismatch)wrong-selector.json: External call with unauthorized selector →FAIL(UnexpectedExternalCall)unexpected-initializer.json: External call to non-allowed contract →FAIL(UnexpectedExternalCall)type-drift.json: Mutator called with wrong type method →FAIL(OpMismatch)wrong-chain.json: Fixture executed on wrong chain ID →FAIL(WrongChainId)reordered-manifest.json: Different manifest declaration order →PASS(set-based reconciliation)
Running rsg attest produces deterministic artifacts in the output directory:
attestations/v1.4-mainnet/
├── attestation.json # Deterministic JSON attestation with SHA-256 bindings
├── attestation.md # Reviewer-readable Markdown report
├── observed-trace.json # Canonical normalized trace
├── manifest.lock # SHA-256 lockfile of the manifest
└── review-record.json # Signed record of independent review
- Observation Boundary:
rsginspects calls to theRocketStoragecontract and immediate outbound calls originating from the upgrade contract. Internal storage changes within other contracts (e.g., proxy implementation slots) are outside this boundary. - Non-Goals:
rsgdoes not replace Foundry or Anvil.rsgis not a smart contract audit and does not claim that the upgrade logic is safe.rsgdoes not automatically infer governance intent from text RPIPs.