docs(registry): commit arctic-1 alongside pacific-1 and atlantic-2 - #75
docs(registry): commit arctic-1 alongside pacific-1 and atlantic-2#75bdchatham wants to merge 1 commit into
Conversation
arctic-1 was excluded because it can be re-genesised. It can, but we control that and intend not to, and the exclusion cost more than the risk. Supplying the file from a deployment instead lets anyone who can edit that source point a run at a contract of their choosing, and the code-hash check cannot catch it: the check proves the address holds the code the file recorded, not that the code is ours. Committing removes that exposure and puts every address change through review. Two corrections to what the section claimed about a re-genesis. It does not break a run. Resolve returns "deploy" when the chain key does not match, with no error, so a run whose committed entries have gone stale deploys its own contracts — which is what every run did before this directory held a file. Recovery is a pull request here at whatever pace suits. What does not degrade quietly is a recorded address whose code has changed: Verify fails and the run stops at startup. It also omitted the requirement that makes committing work at all. The registry keys on genesisHash, so a profile that omits it matches nothing, and a run that omits it on a chain the registry describes already fails at startup with that explanation. Any profile reading a committed entry has to carry it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PR SummaryLow Risk Overview Policy: arctic-1 moves from “always supply via Operational behavior the section now states explicitly: after re-genesis, registry keys no longer match so runs deploy their own contracts (not a hard outage); changed code at a recorded address fails
Reviewed by Cursor Bugbot for commit 26c1a64. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Doc-only change reversing the arctic-1 exclusion policy in registry/chains/README.md. The genesisHash and Verify claims check out against the code, but two security/failure-mode claims in the new prose are stronger than what the code supports.
Findings: 0 blocking | 2 non-blocking | 2 posted inline
Blockers
- None at the file/PR level.
Non-blocking
- None at the file/PR level.
- 2 suggestion(s)/nit(s) flagged inline on specific lines.
| That alternative is supplying the file from a deployment. Anyone who can edit | ||
| that source then points a run at a contract of their choosing. The code-hash | ||
| check cannot catch it: the check proves the address holds the code the *file* | ||
| recorded, not that the code is ours. Committing removes that exposure. It also |
There was a problem hiding this comment.
[suggestion] "Committing removes that exposure" overstates what committing achieves. --chain-file is still accepted (main.go:71, config.ChainFiles), and Registry.add replaces an entry under the same chainID+genesisHash key, so a supplied file still wins over the compiled-in one (registry/registry.go:132-144; main.go:71 documents "a later file wins"). Anyone who can edit the deployment source can therefore still redirect an arctic-1 run to a contract of their choosing, and the code-hash check still cannot catch it. Committing removes the need to supply a file and gives a reviewed default, but the override path remains — worth stating as the residual trust boundary rather than claiming the exposure is gone.
| A re-genesis changes the chain's genesis hash, and the committed entries stop | ||
| matching. A run then deploys its own contracts, which is what every run did | ||
| before this directory held a file. Recovery is therefore a pull request here, at | ||
| whatever pace suits, rather than an outage. |
There was a problem hiding this comment.
[suggestion] The graceful-degradation claim holds only when the profile's genesisHash is updated at the same time as the re-genesis. genesisHash comes from the profile config (config/config.go:25, read at generator/prepare.go:233), not from the chain. If a profile still names the pre-re-genesis hash, Resolve matches the stale committed entry, Verify reads no code at the recorded address, and the run fails at startup with MismatchError — whose own message names re-genesis as "the usual cause" (registry/resolve.go:42-48). That is the outage this paragraph says will not happen; "a run then deploys its own contracts" is only reached once the profile carries the new hash. Since the profiles live outside this repo, recovery is still a coordinated profile change, which weakens the trade-off argument as written.
|
Collapsed into #73. Reviewing these apart cost more than the separate boundaries were worth: the Disperse fix and the Value field were in #74, the read headroom in #76, and the newest estimator fixes in #73, so no branch was individually correct and each review pass had to reason about where a fix actually lived. Every commit is preserved in #73's history. Nothing is dropped. |
…#73) Replaces the numbers this tool hard-codes with numbers it asks the chain for. Sei charges 72,000 for a storage write that takes a slot from zero, against the EVM default of 20,000. Every gas constant in the repo was calibrated against the default, so every contract scenario was short on Sei — and a short limit does not fail visibly. The transaction reaches a block, burns the whole limit, and a run with `trackReceipts` off reports it as sent. | | was | arctic-1 needs | |---|---|---| | `AMM.swapAToB` | 85,000 | 185,711 | | `ERC20.transfer` | 72,156 | 175,242 | | `ERC721.mint` | 22,460 | 175,000 | | fee cap (all paths) | 20 gwei | 55 gwei | ## What it does A scenario declares `GasEstimateCalls()`; the run prices them once at startup, after the contracts are bound, and the send path reads a number. `ContractScenarioBase` does not implement the method, so a scenario added without one does not compile. The fee cap comes from `eth_gasPrice` at startup. Contract addresses for arctic-1 ship in `registry/chains/`, so a run binds them instead of redeploying on every restart. Pricing failure stops the run. There is no fallback constant, because a fallback constant is what this removes. ## Also here - `/healthz` and `/readyz`, and readiness now drops on every exit rather than only on a signal - an `amm` scenario, and ERC721's gas constant fixed before it was deleted ## Verification Run against arctic-1: contracts bound from the registry with no deployment sent, gas quoted per operation, transactions executed — the AMM reserve moved off its floor and ERC721 token 1 has an owner. Every fix broken on purpose first. Four review rounds found five, three, two and one defect; all are fixed here. Twice a fix introduced its own mirror image: the value-carrying estimate now funds its caller through a state override, and the per-quote timeout runs through `WithinBudget` so a hung endpoint reads as a failure rather than a clean shutdown. `gofmt`, `go vet`, `golangci-lint` clean; 15 packages passing. ## Known - committing `registry/chains/arctic-1.json` makes `genesisHash` required for any arctic-1 profile that drives a contract scenario; `profiles/arctic-1.json` now carries it, but a profile kept outside this repo needs it added - the gas tip is still a constant while the cap is chain-derived, and StorageRW packs its calldata twice per send; both are flagged non-blocking on the PR - ERC721's token counter restarts at 1, so reusing a recorded contract wastes gas until it passes the previous high-water mark (PLT-1107) - gas and fee cap are resolved once and held; a long run outliving either is undetected - `--duration N` exits 1 at the end of a bounded run Collapsed from #74, #75 and #76, which are closed. Deploys via sei-protocol/platform#1587. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fifth on the stack. Doc-only; no code changes.
The policy change
arctic-1 was excluded from
registry/chains/because it can be re-genesised. Itcan, but we control that and intend not to, and the exclusion costs more than the
risk.
The argument inverts once you look at what the alternative buys. Supplying the
file from a deployment lets anyone who can edit that source point a run at a
contract of their choosing, and the code-hash check cannot catch it — the check
proves the address holds the code the file recorded, not that the code is ours.
Committing removes that exposure and puts every address change through review.
Two corrections to what the section claimed
Both found by reading the code rather than trusting the prose, and both make the
trade look better than it did.
A re-genesis does not break a run.
Resolvereturns "deploy" when the chainkey does not match, with no error:
So a run whose committed entries have gone stale deploys its own contracts, which
is what every run did before this directory held a file. Recovery is a pull
request here at whatever pace suits, not an outage. What does not degrade
quietly is a recorded address whose code has changed:
Verifyfails and the runstops at startup rather than binding something else.
The section omitted the requirement that makes committing work. The registry
keys on
genesisHash, so a profile that omits it matches nothing.prepare.goalready catches that and says why:
Any profile reading a committed entry has to carry it — including the three in
platform#1587, which currently do not. That is a prerequisite for the embedding
work, not an optional extra.
The values, for whoever does the embedding
Computed from
sei-config, and cross-checked against a second independentcheckout — both agree:
Bare SHA-256 over the exact file bytes, which is what the controller records:
I verified arctic-1's against the running chain via
/genesis_chunked. The bytehashes differ, and the reason is benign: the endpoint returns a re-marshalled
document with node defaults filled in (
block.max_gas_wanted,block.min_txs_in_block). Everything that identifies the chain is identical —chain_id,genesis_time,app_hash, all 30 validators, and 516,993 bytes ofapp_state. So the sei-config file is arctic-1's genesis.One caveat worth recording: arctic-1 has no
SeiNetwork, so the controller neverassembled or hashed it and there is no
Status.GenesisHashto copy. Using thesei-config file hash is reproducible and consistent with how the controller
computes one, but it is us establishing the value rather than reading it back.
🤖 Generated with Claude Code