feat: new tool - exit_certificate#1582
Conversation
|
Claude finished @krlosMata's task in 4m 37s —— View job PR Review: exit_certificate Tool ✅🚀 What's NewA new standalone CLI tool ( 🐛 Bug FixesNone. 📋 Config UpdatesNew config file: Required fields:
Optional fields:
|
6d18df4 to
85a1fa9
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new standalone exit-certificate CLI tool under tools/exit_certificate/ to generate Agglayer exit certificates for aggchain migration by scanning L2/L1 state and producing an agglayer/types.Certificate with BridgeExit entries.
Changes:
- Implements a 6-step pipeline (0 → A → B → C → D → E) for LBT generation, address discovery, balance scanning, SC-locked computation, certificate building, and unclaimed L1→L2 deposit detection.
- Adds JSON-RPC batching/concurrency utilities plus step-wise resumable output persisted to an output directory.
- Adds unit/integration tests and documentation/config examples for running the tool.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/exit_certificate/worker.go | Generic worker-pool helper used to parallelize step workloads. |
| tools/exit_certificate/types.go | Shared data structures for step outputs and deposit/event models. |
| tools/exit_certificate/step_0.go | Step 0 implementation: generate LBT by scanning bridge logs + supplies. |
| tools/exit_certificate/step_a.go | Step A implementation: scan blocks/txs and trace touched addresses. |
| tools/exit_certificate/step_b.go | Step B implementation: EOA/contract classification and balance scanning. |
| tools/exit_certificate/step_c.go | Step C implementation: compute SC-locked values from LBT vs EOA totals. |
| tools/exit_certificate/step_d.go | Step D implementation: build the exit certificate BridgeExits. |
| tools/exit_certificate/step_e.go | Step E implementation: scan L1 BridgeEvents and add unclaimed deposits. |
| tools/exit_certificate/rpc.go | JSON-RPC client utilities: batch/single RPC, retries, concurrency batching. |
| tools/exit_certificate/hex.go | Hex/decimal parsing helpers and ABI safety conversions. |
| tools/exit_certificate/config.go | Config loading/validation, defaults, and LBT file parsing helpers. |
| tools/exit_certificate/run.go | CLI execution wiring: full pipeline + step-by-step resumability and I/O. |
| tools/exit_certificate/cmd/main.go | CLI binary entrypoint using urfave/cli. |
| tools/exit_certificate/README.md | Tool documentation: config, steps, usage, outputs, testing. |
| tools/exit_certificate/.gitignore | Ignore local parameters/output/binary artifacts for this tool. |
| tools/exit_certificate/parameters.json.example | Example standalone JSON config for running the tool. |
| tools/exit_certificate/step_a_test.go | Unit tests for hex block parsing helper(s) used in Step A. |
| tools/exit_certificate/step_b_test.go | Unit tests for hex-to-bigint helper used in Step B. |
| tools/exit_certificate/step_c_test.go | Unit tests for SC-locked computation behavior and edge cases. |
| tools/exit_certificate/step_d_test.go | Unit tests for certificate construction from EOA + SC-locked inputs. |
| tools/exit_certificate/step_e_test.go | Unit tests for BridgeEvent decoding and claimed-set filtering logic. |
| tools/exit_certificate/rpc_test.go | Unit tests for batch/single RPC, retry behavior, and error handling. |
| tools/exit_certificate/run_test.go | Unit tests for block parsing and JSON save/load helpers. |
| tools/exit_certificate/config_test.go | Unit tests for config parsing, defaults, and LBT parsing helpers. |
| tools/exit_certificate/integration_test.go | Integration-style tests for production-like config/data shapes (skippable). |
4936ffa to
63a43be
Compare
|
- Add overflow checks for big.Int to uint32/uint64 conversions (safeUint32, safeUint8) - Add max metadata size validation (1MB) in decodeBridgeEvent to prevent DoS - Cap batch size to RPCBatchSize in fetchTotalSupplies - Return error from parseBlockNumber on invalid input instead of silent zero - Extract globalIndex magic numbers to named constants - Add progress logging to Step D - Document native token handling in step_c indexByAddress - Fix all golangci-lint issues (errcheck, gci, gosec, lll, mnd, prealloc, unparam) Made-with: Cursor
- Scan L2 bridge for ClaimEvent logs so Step E correctly identifies already-claimed deposits instead of treating all as unclaimed (joanestebanr) - Fail on trace/scan errors instead of warn+continue: traceTransactions, fetchL1BridgeEvents now propagate errors (partial scans are unsafe) - Fix encodeBalanceOf: use zero-padding (LeftPadBytes) instead of space-padding (%064s) which produced invalid hex calldata - Use strconv.ParseUint instead of fmt.Sscanf to reject trailing non-numeric input like "123abc" - Set MaxIdleConnsPerHost=100 instead of 0 (0 defaults to 2 in net/http) - Preserve OriginNetwork/OriginTokenAddress from LBT for native token entries (supports chains with custom gas tokens) - Add decodeClaimEvent tests Made-with: Cursor
- Extract magic number 32 to named constant abiWordSize in step_b.go - Pre-allocate claims slice in fetchClaimEventsInRange Made-with: Cursor
- Replace ClaimEvent log scanning with isClaimed(depositCount, 0) eth_call on L2 bridge contract (authoritative claimed bitmap) - Extract helper functions across all steps to bring every function under diffguard thresholds (complexity ≤ 10, size ≤ 50 lines) Made-with: Cursor
Add exit_certificate binary to the Makefile build-tools target so it builds alongside the other tools. Add maskRPCURL helper that strips the path from RPC URLs before logging, preventing API key exposure in error messages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ndling and logging - Add L2StartBlock option to config so block scanning starts from a configurable block instead of always from block 0 - Add label parameter to concurrentBatchRPC to identify each call site in progress logs (e.g. "L2 RPC/blockHeaders", "L2 RPC/balanceOf") - Improve batchRPC: log individual RPC-level errors via log.Warn and return the first error instead of silently dropping failed responses; add response-count validation - Add detailed app.Description to the CLI listing all pipeline steps (0, A, B, C, D, E) and how to run individual steps - Add .PHONY declarations for build-tools targets in Makefile Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ac0936d to
2122813
Compare
Revert the step A split (A1 + A2) back to a single RunStepA to avoid OOM caused by json.MarshalIndent serialising all tx hashes while they were still live in memory. Add a new SIGN step that signs the exit certificate with a local keystore and exposes signerKeyPath / signerKeyPassword in config and as CLI flags. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ript Replace signerKeyPath/signerKeyPassword in Config with signertypes.SignerConfig, matching the same type aggsender uses for AggsenderPrivateKey. The JSON config now uses a flat signerConfig object (Method, Path, Password at top level). Update configuration_based_on_kurtosis.sh to download the sequencer keystore from the aggkit-sequencer-keystore artifact and extract the password from config.toml, producing a fully configured signerConfig block. Also add agglayerRpcUrl and agglayerGrpcUrl (needed for steps H and SUBMIT). Remove obsolete --signer-key-path/--signer-key-password CLI flags. Align README.md and CLAUDE.md with the current pipeline (steps H, I, SUBMIT, corrected step order, updated config fields and output file names). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion When a chain uses a custom gas token (non-zero origin address, e.g. a token from network 0), resolveTokenAddresses was falling through to the wrapped-token lookup path and failing because getTokenWrappedAddress returns zero — the token is native, not a wrapped ERC-20. Fix: fetch gasTokenInfo from the real L2 RPC in RunStepG (same pattern as step 0) and pass it to resolveTokenAddresses. Bridge exits whose TokenInfo matches the gas token are now treated as isNative=true, so bridgeAsset is called with token=address(0) as the contract expects. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, and align docs - Add step_check.go: prerequisite verification (Anvil, L1 RPC reachable, L2 network ID match, sovereignRollupAddr, PP type, threshold=1, gas token) - Add step_wait.go: polls agglayer every 5s until certificate is Settled or InError; handles pre-existing pending certs before polling submitted one - Add l1GlobalExitRootAddress config field; step I now fetches L1InfoTreeLeafCount by scanning L1 backwards for UpdateL1InfoTreeV2 events - Fix step I: use resolveLatestBlock(L1) instead of ResolvedTargetBlock (L2) to determine the scan starting point for L1 events - kurtosis script: extract polygonZkEVMGlobalExitRootAddress from config.toml and write it as l1GlobalExitRootAddress in the generated config - Align CLAUDE.md and README.md with actual implementation: pipeline order, Step CHECK full check list, Step I L1InfoTreeLeafCount, Step WAIT section, config fields sovereignRollupAddr/l1GlobalExitRootAddress, Step G reads Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…king, balance capping, and ignoreUnclaimed --step flag now supports range notation: "f-i" expands to f,g,h,i and "f-" expands to f through sign (submit/wait always require explicit opt-in). Step G reads InitialLocalExitRoot from the bridge contract before replaying exits (via Anvil fork, or against the real L2 RPC for the empty-exits case). A 1-minute sleep separates the last bridgeAsset call from the final getRoot read. Step H verifies that its agglayer settled LER matches the InitialLocalExitRoot reported by step G, returning a hard error on mismatch. Step I (single-step mode) now prefers step-f-capped-certificate.json over step-e-exit-certificate.json, consistent with step G. Step F balance capping is rewritten: buildCapMap + capBridgeExits are replaced by a single capCertificateExits function that processes exits in order, deducting each exit's amount from a per-token RemainingBalance (= min(LBT, agglayer)). Exits that exceed the remaining budget are capped to it; exits that arrive when the budget is exhausted are dropped. RemainingBalance is carried on TokenBalanceCheck (json:"-"). Step E gains options.ignoreUnclaimed: when true, unclaimed deposits are detected and logged as warnings but not added to the certificate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ging Apply crypto.Keccak256 to raw BridgeEvent metadata before assigning it to BridgeExit.Metadata in Step I, matching aggsender's convertBridgeMetadata behaviour. Without this, BridgeExit.Hash() produced a different value than aggsender, causing CertificateID and therefore the certificate hash to diverge — making the signature unverifiable by the agglayer. Also log signer address, certificate fields (networkID, height, LERs), CertificateID, and hash-to-sign in Step SIGN to aid future debugging. Add a pipeline step summary table to the README. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…filtering
Add optional bridge service cross-check to Step E and split unclaimed
L1→L2 deposits by leaf type.
Changes:
- config: add `bridgeServiceURL` and `bridgeServiceType` options
("aggkit" or "zkevm") for configuring the bridge service endpoint
- step_e: separate unclaimed deposits into assets (leaf_type=0) and
messages (leaf_type=1); only assets are added to the certificate
- step_e: log a single info line with the message count instead of
per-deposit warnings
- step_e: log a single token-grouped summary for ignored unclaimed
assets (name and decimals fetched from contract; ETH shown in ETH)
- step_e: when bridgeServiceURL is set, compare the bridge service's
pending-bridges set against the L1 scan unclaimed set and error only
on discrepancies; supports both aggkit (/bridge/v1/bridges) and
zkevm-bridge-service (/pending-bridges) APIs
- run: always save `step-e-unclaimed-messages.json` (even when empty)
- rpc: add `httpGetJSON` helper for REST GET calls
- kurtosis script: auto-detect and configure zkevm-bridge-service-001
as the bridge service when available
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rors
Per the function contract ("individual RPC errors are logged and become
nil entries"), per-item RPC errors must not bubble up as a Go error.
Remove the early-exit check on responses[0].Error and the firstRPCErr
accumulator — errors are already logged as warnings and the result slot
is left nil.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
…al Step E behavior Remove unused functions depositsToImportedExits and depositsToExits from step_e.go; these were never called and represented unimplemented logic (Merkle proof support for adding unclaimed L1→L2 deposits to the certificate). Remove unused ABI selector constants gasTokenAddressSelector and gasTokenNetworkSelector from step_0.go. Fix README.md and CLAUDE.md to reflect what Step E actually does: - When unclaimed asset deposits are found and ignoreUnclaimed=false → pipeline errors (Merkle proof support not yet implemented) - When ignoreUnclaimed=true → deposits are detected and logged, certificate unchanged - imported_bridge_exits is not populated by Step E today - Step I prefers step-f-capped-certificate.json over step-e-exit-certificate.json when it exists - Add missing abortOnGenesisBalance option to the options table Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…factor fetch logic - Fix zkevmDeposit JSON tags and TotalCnt type to match actual API response - Fix dest_net query param and restrict cross-check to leaf_type=0 (assets) - Refactor bridge service fetchers to accept leafType and share comparison logic - Fix formatTokenAmount precision loss for small sub-unit values - Always persist unclaimed files even when Step E fails Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ross-check The bridge service check only covers leaf_type=0 (assets), so the comparison must use the asset subset rather than all unclaimed deposits. Also split by leaf type before the check so the log line can report asset/message counts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Explain why l1RpcUrl matters in practice, warn that exitAddress must be a key you control, document the signerConfig format, and add a table describing when to use continueOnTraceError, abortOnGenesisBalance and ignoreUnclaimed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion options Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
It is needed by Step E and Step I; without it the certificate is incomplete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…EADME List l1RpcUrl, exitAddress and signerConfig as the fields that must be filled in before running the tool, and link to the main README for the full field reference. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… API Introduce options.agglayerAdminToken to pass an Authorization: Bearer header when calling admin_getTokenBalance in Step F. Required when agglayerAdminURL is protected by Google Cloud IAP. Also replaces the flat agglayerGrpcUrl string option with a structured agglayerClient config object (agglayer.ClientConfig), enabling TLS, timeout and retry customization for gRPC steps H, SUBMIT, and WAIT. Add ready-to-use config examples for zkevm-cardona and zkevm-mainnet in config-examples/. Documentation updated with IAP token instructions and environment-specific service account / audience values for spec, bali, cardona, and mainnet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tools/exit_certificate: fix lll, mnd, gci, whitespace, goconst, gocritic, makezero, unparam, prealloc, and errorlint issues; add named constants (abiWordBytes, ethDecimals, hexBase, etc.) to hex.go; remove unused params from fetchGasTokenInfo and checkNativeGasToken; expand unit test coverage with hex_test.go, step_g_test.go and additional cases in rpc_test.go, config_test.go, step_f_test.go - aggsender, bridgeservice, multidownloader, scripts, backward_forward_let: suppress gosec false-positives with nolint directives - db/migrations/testutils: add gosec nolint alongside existing mnd nolint - l1infotreesync/migrations: preallocate migrations slice - sync/evmdownloader_test: preallocate testCases slice Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds G204, G602, G703, G118 to the global gosec excludes in .golangci.yml so local and CI golangci-lint produce identical results regardless of version. Removes now-redundant //nolint:gosec directives from 6 files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
G703 and G118 are not valid rule IDs in gosec as bundled with golangci-lint v2.4.0 (used by CI). Move them from gosec.excludes (schema-validated) to exclusions.rules with text matching, which is version-agnostic. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
… for SC-locked exits (#1622) ## 🔄 Changes Summary ### Fix F-01: `ensureERC20Balance` storage patching for SC-locked ERC-20 exits - Implements `ensureERC20Balance` in Step G, which was a stub that always returned an error without actually patching Anvil storage. - The function now patches `_balances[account]` via `hardhat_setStorageAt` using a two-layout detection strategy, verifying `balanceOf` after each attempt: 1. **OZ v4 non-upgradeable**: `_balances` mapping at storage slot 0 2. **OZ v5 upgradeable**: `_balances` inside the namespaced `ERC20Storage` struct at `ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00` - Adds a package-level `erc20NamespacedStorageLocation` constant documenting the OZ v5 storage namespace derivation. ### Refactor: remove `lbtFile` config option - `lbtFile` was an escape hatch to skip Step 0 by providing a pre-generated LBT. Step 0 now always runs, so the field is removed. - Merges `RunStepCWithEntries` back into `RunStepC` (simpler API, no config dependency). - Updates `resolveOrGenerateLBT`, `loadWrappedTokensFromLBT`, `runSingleC`, `runSingleB`, `runSingleF`, `runSingleG` accordingly. ### Kurtosis script improvements - Adds two helper scripts for the Kurtosis test environment. - Embeds a pre-generated exit address keypair (`0xe25f5B65E4976025f670e52b790a9746F27A3DB6`) in `configuration_based_on_kurtosis.sh` so the exit address is stable across runs without requiring Foundry at script runtime. The private key and an encrypted keystore (password: `test`) are written to `tmp/` on first execution. ##⚠️ Breaking Changes - `lbtFile` config field removed. Any existing config files using it will have the field silently ignored (unknown JSON fields are not errors, but Step 0 will now always run). ## 📋 Config Updates - `lbtFile` removed from `Config` and `rawConfig`. Step 0 is no longer skippable via config. ## ✅ Testing - 🤖 **Automatic**: Existing unit tests pass (`ok github.com/agglayer/aggkit/tools/exit_certificate`) - 🖱️ **Manual**: 1. Run `tools/exit_certificate/scripts/reproduce_sc_locked.sh` against a live Kurtosis `aggkit` enclave 2. The script deploys a `TokenHolder` smart contract on L2, transfers wrapped ERC-20 tokens to it, then drives the exit-certificate tool from steps 0→G 3. Before fix: Step G failed with `ERC20InsufficientBalance` (`0xe450d38c`) when replaying the SC-locked `BridgeExit` 4. After fix: Step G completes and emits a valid `NewLocalExitRoot` ## 🐞 Issues - Fixes: #1624 ## 🔗 Related PRs - N/A ## 📝 Notes - `TokenWrapped` (wTTK) deployed by `AgglayerBridge` uses OZ v5 upgradeable storage, so the slot-0 attempt is a no-op. The second candidate (namespaced storage) is the one that matches and patches the balance correctly. - The two-layout approach is safe: a failed slot write leaves the token balance unchanged and the loop moves to the next candidate. If neither layout works the function returns a descriptive error. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…runs (#1627) ## 🔄 Changes Summary - Changed `cfg.TargetBlock` type from `string` to `aggkittypes.BlockNumberFinality`, enabling finality keywords (`LatestBlock`, `FinalizedBlock`, `SafeBlock`, `PendingBlock`), decimal/hex block numbers, and offset notation (e.g. `LatestBlock/-10`). - Added `Step0Result.TargetBlock uint64` — the concrete resolved block number is now part of the Step 0 output and persisted to `step-0-l2_target_block.json` (new file). - Removed `ResolvedTargetBlock` from `Config`; the resolved block number is passed as an explicit `targetBlock uint64` parameter to `RunStepA`, `RunStepB`, and `RunStepG`. - Single-step runners (`runSingleA/B/G`) load the block from `step-0-l2_target_block.json` via a new `loadTargetBlock` helper. - Updated README with target-block resolution table and updated Step 0 output list. - Added output-directory cleanup hint at the end of the kurtosis configuration script. ##⚠️ Breaking Changes - 🛠️ **Config — `targetBlock` values renamed**: existing `parameters.json` files must update their `targetBlock` field to use the new PascalCase keywords: - `"latest"` → `"LatestBlock"` - `"finalized"` → `"FinalizedBlock"` - `"safe"` → `"SafeBlock"` - `"pending"` → `"PendingBlock"` The default (empty string) still resolves to `LatestBlock`. Decimal and hex block numbers are unchanged. - 🗑️ **New output file**: `step-0-l2_target_block.json` is a new file produced by Step 0. Note: `step-0-result.json` (from a previous PR) was already renamed to `step-0-lbt.json`; any tooling still reading `step-0-result.json` must be updated to `step-0-lbt.json`. ## 📋 Config Updates ```json // Before "targetBlock": "latest" // After "targetBlock": "LatestBlock" // or "FinalizedBlock", "SafeBlock", "PendingBlock" "targetBlock": "LatestBlock/-10" // latest minus 10 blocks "targetBlock": "12345678" // decimal (unchanged) "targetBlock": "0xBCDE34" // hex (unchanged) ``` ## ✅ Testing - 🖱️ **Manual**: Run full pipeline with `targetBlock: "LatestBlock"` and verify `step-0-l2_target_block.json` is written with a valid block number; subsequent single-step runs for A, B, and G should pick it up automatically. ## 🐞 Issues - Closes #1625 ## 🔗 Related PRs - Base branch: `feat/exit_certificate_f01_token_sclocked` --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## 🔄 Changes Summary
- Propagate trace errors through the worker pool and abort all in-flight
workers on first failure when `ContinueOnTraceError=false` (F-09)
- Add `StepAWindowSize` config option to tune Step A chunk size
independently from `blockRange`
- Replace `[]common.Hash failedTraces` with `[]FailedTrace{Hash, Error}`
so callers get the RPC error alongside the hash
- Promote `fetchSetSovereignTokenEvents` /
`applySovereignTokenOverrides` errors from silent `log.Warn` to returned
errors in `RunStep0`
- Fix variable shadowing bug for `nativeEntry` in `RunStep0` (`:=` →
`=`)
- Remove dead `lbtFile` config field and merge `RunStepCWithEntries`
back into `RunStepC`
## ⚠️ Breaking Changes
- 🛠️ **Config**: `lbtFile` option removed from `Options` — it was an
escape hatch to skip Step 0 that is no longer needed since Step 0 always
runs
- 🛠️ **Config**: `blockRange` no longer controls the block window size
in Step A — `stepAWindowSize` is now used exclusively for that (defaults
to 5000). Existing configs that relied on `blockRange` to tune Step A
throughput should add an explicit `stepAWindowSize`
- 🔌 **API/CLI**: `runWorkerPool`, `startWorkers`, `collectResults` now
require a `context.Context` as first argument
## 📋 Config Updates
- 🧾 New optional field `stepAWindowSize` (default: 5000):
```json
"options": {
"blockRange": 10000,
"stepAWindowSize": 10000
}
```
## ✅ Testing
- 🤖 **Automatic**:
- Unit tests for `traceOneTransaction` (success, dedup, RPC error, bad
JSON, null+error)
- Unit tests for `traceTransactions` (continueOnError path,
abort-on-error path)
- End-to-end `TestRunStepA_AbortOnTraceError` against a fake HTTP server
verifying context cancellation stops the pool
- 🖱️ **Manual**: Run Step A with a node that returns trace errors with
`continueOnTraceError=false` and verify the tool exits immediately with
the offending hash and error message
## 🐞 Issues
- Closes agglayer/pm#346
- Partially fixes agglayer/pm#349 (`Problem 2 — Variable shadowing makes
nil-check dead code`)
## 🔗 Related PRs
- Base: feat/exit_certificate_f05_target_block (block finality
resolution for Step 0)
## 📝 Notes
- `StepAWindowSize` exists because `debug_traceTransaction` RPC calls
are more expensive than `eth_getLogs`; operators may want a smaller
window for Step A without changing the log-query range used by Steps 0,
B, and E
- Context cancellation in `collectResults` drains `resultCh` in a
background goroutine to let workers release resources cleanly instead of
blocking
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
… rollup diagnostics (#1630) ## 🔄 Changes Summary - **Step A → A1 + A2 split**: Step A is now two sub-steps. A1 runs `debug_traceTransaction` (prestateTracer + diffMode) as before and records failed hashes. A2 recovers addresses from `eth_getTransactionReceipt` for each A1 failure, extracting from/to/contractAddress/log emitters. The combined `step-a-addresses.json` is the union of both. - **Step aliases**: `--step a` expands to `a1,a2`; both sub-steps are individually addressable (`--step a1`, `--step a2`). Range syntax works too (`a-b` → `a1,a2,b`). - **Migration**: on startup, legacy `step-a-*` files are renamed to `step-a1-*` so existing output dirs remain usable without re-running A1. - **Legacy rollup diagnostics**: when `AGGCHAINTYPE()` fails (pre-aggchainbase contract), `logLegacyRollupInfo` queries the rollup manager to surface `rollupID`, `rollupTypeID`, `chainID`, `forkID`, `rollupVerifierType`, and full `rollupTypeMap` info (consensusImpl, verifier, obsolete, genesis, programVKey) as diagnostic log lines. ##⚠️ Breaking Changes - 🔌 **CLI**: `--step a` still works as before (runs both sub-steps). `step-a1-addresses.json` and `step-a1-failed-traces.json` are the new canonical A1 outputs; `step-a-failed-traces.json` is no longer written directly (migrated from legacy on startup). ## ✅ Testing - 🤖 **Automatic**: `TestParseStepList` extended with `a`, `a-b`, `a2-b` cases. - 🖱️ **Manual**: run `--step a` on a chain with trace failures to verify A2 recovers addresses from receipts. ## 📝 Notes - A2 never aborts on receipt failures — it logs a warning and skips, so the pipeline always produces a result even when receipts are also unavailable. - The legacy rollup diagnostics path does not modify check failures or results; it is purely informational output to help diagnose pre-aggchainbase deployments. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>





🔄 Changes Summary
New
exit-certificateCLI tool undertools/exit_certificate/that generates exit certificates for aggchain migration. It scans L2 state from genesis to a target block, discovers all addresses with value (ETH + wrapped tokens), computes smart-contract-locked balances, detects unclaimed L1→L2 bridge deposits, verifies balances against the agglayer, computes the new LocalExitRoot via a shadow-fork, and produces a fully signed agglayerCertificateready for submission.Full pipeline: CHECK → 0 → A → B → C → D → E → F → G → H → I → SIGN → SUBMIT → WAIT
NewWrappedToken/SetSovereignTokenAddressevents, fetchestotalSupplyper tokendebug_traceTransactionwithprestateTracer+diffModeCertificatewithBridgeExitentriesadmin_getTokenBalance; proportional capping on mismatchNewLocalExitRootcomputation via Anvil shadow-fork of the L2 chainPreviousLocalExitRootfrom agglayer via gRPCL1InfoTreeLeafCountfrom L1)go_signerSettledorInErrorSteps can be run individually or as a full pipeline via
--stepflag. Intermediate results are persisted to an output directory, enabling step-by-step execution and resumability.Additional changes in this PR:
options.agglayerAdminToken)hex,rpc,config,step_f, andstep_gutilities📋 Config Updates
tools/exit_certificate/parameters.json(standalone JSON). Key fields:{ "l2RpcUrl": "https://your-l2-rpc.example.com", "l1RpcUrl": "https://your-l1-rpc.example.com", "l2BridgeAddress": "0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe", "l2NetworkId": 1, "targetBlock": "latest", "exitAddress": "0x0000000000000000000000000000000000000001", "destinationNetwork": 0, "sovereignRollupAddr": "0x...", "l1GlobalExitRootAddress": "0x...", "signerConfig": { "Method": "local", "Path": "keystore.json", "Password": "..." }, "options": { "blockRange": 5000, "concurrencyLimit": 20, "rpcBatchSize": 200, "outputDir": "./output", "agglayerAdminURL": "https://admin-agglayer.example.com", "agglayerAdminToken": "<IAP bearer token>", "agglayerClient": { "GRPC": { "URL": "agglayer.example.com:50051", "UseTLS": true } } } }✅ Testing
tools/exit_certificate/(hex, rpc, config, step_c, step_f, step_g)🐞 Issues
📝 Notes
anvil(Foundry) in$PATHfor Step Gdebug_traceTransaction)