WNE-41: reconnect bootstrap-window authorization on OPPInbound.epochIn - #82
Open
brianjohnson5972 wants to merge 1 commit into
Open
WNE-41: reconnect bootstrap-window authorization on OPPInbound.epochIn#82brianjohnson5972 wants to merge 1 commit into
brianjohnson5972 wants to merge 1 commit into
Conversation
Change-Id: Ie1b3a354da8d05f78c8e4b670076d6e6cd076a54
brianjohnson5972
requested review from
heifner,
huangminghuang and
jglanz
and removed request for
heifner and
huangminghuang
August 21, 2026 20:34
Author
|
Connected with: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
wire-tools-ts — response to wire-ethereum PR #191 (WNE-41) review, finding 1
This is the paired change the wire-ethereum review called for:
Confirmed, and this is it. The two PRs should land together — wire-ethereum #191
alone leaves
epochIncallable by nobody on a test cluster.The finding
OPPInbound.epochInauthorizes against the AccessManager for as long as thegenesis bootstrap window is open (
rosterInitialized == false), because thebatch-operator roster it would otherwise consult does not exist yet.
OutpostManager.setupOPPRolesregisters theepochInselector underOPP_INBOUND_ROLEand grants that role to nobody, so the window is closed bydefault and a deployment must name its genesis deliverer.
deployLocal.tsgrants the hardhat deployer. On a WIRE cluster that is the wrongaddress. Verified on all three legs:
wire-sysio/plugins/outpost_ethereum_client_plugin—deliver_outbound_envelopecalls
epoch_inthrough a client whose signer is the daemon's own key(
get_signer_address()), and the ladder-B gate readsmsg.sender.ClusterBuildDefaults— batch operators getethereumHdIndex: index + 1; thedeployer is HD 0.
grep -rn "opp_inbound\|grantRole" packages/*/src/— nothing. The harness hadno grant path and never calls
epochInitself.Result: epoch 1 reverts
AccessManagedUnauthorized,nextEpochIndexstays 1,the depot's
chkconsnever firesadvance, and everyflow-*dies on an epochstall.
Why the fix could not live in wire-ethereum
Two independent reasons, either one sufficient:
Cluster Prerequisites; operators areprovisioned later, in
Cluster Post Contract Deployment. The accounts do notexist when
deployLocal.tsruns, so it cannot grant them.KEYsignature provider the operator EM keys derive fromEthereumOutpostBootstrapper.AnvilMnemonic, so an HD-band grant would haveworked. Under SSM they derive from a generated cluster mnemonic anvil has
never seen — which is exactly why
BatchOperatorEthereumFundingWeiexists.No band of anvil-derived addresses covers that mode, so an HD-band grant would
have fixed KEY-mode clusters and left SSM-mode ones silently broken.
The grant therefore has to happen in the harness, after provisioning, keyed on
the operators' real addresses.
The change
packages/cluster-tool/src/tools/ethereum/EthereumOutpostManagerTool.ts(new)The
OutpostManagerAccessManager-administration surface. One Step factorytoday:
planGrantBootstrapDelivery(actor, name, description, options, operatorLabel)→
ClusterBuildStep(:89)runGrantBootstrapDelivery(ctx, input, signal)— the named runner (:112).Resolves the operator from
ctx.keyStore, asserts it carries an Ethereumaddress, and performs exactly one
grantRole(OPP_INBOUND_ROLE, <EOA>)write with an explicitly resolved nonce.
loadOutpostManager(ctx)(:149) — a pure value helper binding the deployedOutpostManagerfrom this cluster'soutpost-addrs.jsontoctx.ethereum.wallet.signer. That signer is anvil HD 0, the deploy owner andthe only identity holding
ADMIN_ROLEon the outpost authority — which is whatgrantRole'srestrictedmodifier requires.One write per Step, so each grant lands in the Report as its own validated
checkpoint rather than disappearing into a loop.
packages/cluster-tool/src/orchestration/ClusterBuildDefaults.ts:940-958A
GrantBootstrapDeliveryphase insidepostContractDeployment, carrying oneStep per batch operator. Placement is load-bearing in both directions:
Create batchops & uws— the accounts must exist to be granted.OperatorNodes— the operators must hold the role before theirdaemons start delivering.
Gated on
!isExternalOutpost. In external mode this run deployed no outpost andholds no admin authority over the ones it talks to; those deliverers are
authorized out of band.
Underwriters are deliberately not granted — only batch-operator daemons run
the
outpost_ethereum_clientdelivery path.Tests
packages/cluster-tool/tests/tools/ethereum/EthereumOutpostManagerTool.test.tsplanGrantBootstrapDeliverycaptures the typed input and binds the namedrunner.
loadOutpostManagerbinds the artifact ABI to the deployed address and isbound to the deploy owner by identity, not merely by address — a
same-address signer on another provider would submit to the wrong chain.
OutpostManageris absent from the address map.chain (granting
address(0)would leaveepochIncallable by nobody,silently), refuses an unknown label, and honours an already-aborted signal.
packages/cluster-tool/tests/orchestration/ClusterBuildDefaultsBootstrapDelivery.test.tsasserted, so a future refactor into a single looping Step fails here.
OperatorNodesandEpochBootstrap.Verification:
pnpm buildclean, full-repoeslint .clean, fullcluster-tooljest 131 suites / 1167 tests passing, including the 9 newcases.
Two things reviewers should know
No flow ran end to end. This change is verified by composition tests and unit
tests, not against a live cluster — the real proof for finding 1 is a green
flow-*run, and that needs awire-sysiobuild the authoring machine did nothave. Worth running one flow (or the e2e gate with both branches) before merging
the pair.
Pre-existing build errors in the checkout, unrelated to this change.
pnpm buildreports 13 errors incluster-tool-sharedand theflow-swap-*packages.Confirmed pre-existing by stashing this change and rebuilding to an identical
error set; none are in touched files. Root cause is environmental: with no
wire-sysio/build/opp/typescriptpresent,@wireio/opp-typescript-modelsresolves from the registry into
wire-libraries-ts/packages/sdk-core/node_modules/, producing a TS2883portability error on
ClusterConfigSchemathat cascades intoClusterConfignotbeing exported. That is also a sighting of the dep edge
cross-repo.mdcalls ared flag (
opp-*-modelsunder awire-libraries-tspath) — worth tracingseparately, but it is this checkout's install state rather than anything in this
PR.