Skip to content

Commit f557bca

Browse files
feat: have AnchorStateRegistry use a single root
Updates the AnchorStateRegistry to use a single unified anchor root by checking with the OptimismPortal for the currently respected game type. Additionally makes the AnchorStateRegistry MCP ready. Users MUST deploy this contract as a new proxy and cannot upgrade their existing proxy.
1 parent e89248a commit f557bca

27 files changed

+1231
-410
lines changed

op-deployer/pkg/deployer/bootstrap/opcm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ func DeployOPCMInputForChain(release string, chainID uint64) (opcm.DeployOPCMInp
213213
ProxyAdminBlueprint: blueprints.ProxyAdmin,
214214
L1ChugSplashProxyBlueprint: blueprints.L1ChugSplashProxy,
215215
ResolvedDelegateProxyBlueprint: blueprints.ResolvedDelegateProxy,
216-
AnchorStateRegistryBlueprint: blueprints.AnchorStateRegistry,
217216
PermissionedDisputeGame1Blueprint: blueprints.PermissionedDisputeGame1,
218217
PermissionedDisputeGame2Blueprint: blueprints.PermissionedDisputeGame2,
219218

@@ -224,6 +223,7 @@ func DeployOPCMInputForChain(release string, chainID uint64) (opcm.DeployOPCMInp
224223
L1CrossDomainMessengerImpl: releases.L1CrossDomainMessenger.ImplementationAddress,
225224
L1StandardBridgeImpl: releases.L1StandardBridge.ImplementationAddress,
226225
DisputeGameFactoryImpl: releases.DisputeGameFactory.ImplementationAddress,
226+
AnchorStateRegistryImpl: releases.AnchorStateRegistry.ImplementationAddress,
227227
DelayedWETHImpl: releases.DelayedWETH.ImplementationAddress,
228228
MipsImpl: releases.MIPS.Address,
229229
}, nil

op-deployer/pkg/deployer/opcm/opcm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ type DeployOPCMInput struct {
1717
ProxyAdminBlueprint common.Address
1818
L1ChugSplashProxyBlueprint common.Address
1919
ResolvedDelegateProxyBlueprint common.Address
20-
AnchorStateRegistryBlueprint common.Address
2120
PermissionedDisputeGame1Blueprint common.Address
2221
PermissionedDisputeGame2Blueprint common.Address
2322

@@ -28,6 +27,7 @@ type DeployOPCMInput struct {
2827
L1CrossDomainMessengerImpl common.Address
2928
L1StandardBridgeImpl common.Address
3029
DisputeGameFactoryImpl common.Address
30+
AnchorStateRegistryImpl common.Address
3131
DelayedWETHImpl common.Address
3232
MipsImpl common.Address
3333
}
Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,36 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.0;
33

4+
import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol";
45
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
56
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
67
import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
8+
import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol";
79
import { GameType, Hash, OutputRoot } from "src/dispute/lib/Types.sol";
810

911
interface IAnchorStateRegistry {
10-
struct StartingAnchorRoot {
11-
GameType gameType;
12-
OutputRoot outputRoot;
13-
}
14-
15-
error InvalidGameStatus();
12+
error InvalidAnchorGame(string reason);
1613
error Unauthorized();
17-
error UnregisteredGame();
1814

15+
event AnchorNotUpdated(IFaultDisputeGame indexed game, string reason);
16+
event AnchorUpdated(IFaultDisputeGame indexed game);
1917
event Initialized(uint8 version);
2018

21-
function anchors(GameType) external view returns (Hash root, uint256 l2BlockNumber); // nosemgrep
19+
function anchorGame() external view returns (IFaultDisputeGame);
20+
function anchors(GameType) external view returns (Hash, uint256);
21+
function getAnchorRoot() external view returns (Hash, uint256);
2222
function disputeGameFactory() external view returns (IDisputeGameFactory);
23-
function initialize(
24-
StartingAnchorRoot[] memory _startingAnchorRoots,
25-
ISuperchainConfig _superchainConfig
26-
)
27-
external;
23+
function initialize(ISuperchainConfig _superchainConfig, IDisputeGameFactory _disputeGameFactory, IOptimismPortal2 _portal, OutputRoot memory _startingAnchorRoot) external;
24+
function isGameRegistered(IDisputeGame _game) external view returns (bool);
25+
function isGameBlacklisted(IDisputeGame _game) external view returns (bool);
26+
function isGameRespected(IDisputeGame _game) external view returns (bool);
27+
function isGameRetired(IDisputeGame _game) external view returns (bool);
28+
function isGameProper(IDisputeGame _game) external view returns (bool, string memory);
29+
function portal() external view returns (IOptimismPortal2);
2830
function setAnchorState(IFaultDisputeGame _game) external;
2931
function superchainConfig() external view returns (ISuperchainConfig);
3032
function tryUpdateAnchorState() external;
3133
function version() external view returns (string memory);
3234

33-
function __constructor__(IDisputeGameFactory _disputeGameFactory) external;
35+
function __constructor__() external;
3436
}

packages/contracts-bedrock/justfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,13 @@ test-upgrade *ARGS: build-go-ffi
7373
#!/bin/bash
7474
echo "Running upgrade tests at block $pinnedBlockNumber"
7575
export FORK_BLOCK_NUMBER=$pinnedBlockNumber
76-
export NO_MATCH_CONTRACTS="OptimismPortal2WithMockERC20_Test|OptimismPortal2_FinalizeWithdrawal_Test|AnchorStateRegistry_Initialize_Test|AnchorStateRegistry_TryUpdateAnchorState_Test|FaultDisputeGame_Test|FaultDispute_1v1_Actors_Test"
76+
export NO_MATCH_CONTRACTS="OptimismPortal2WithMockERC20_Test|OptimismPortal2_FinalizeWithdrawal_Test|'AnchorStateRegistry_*'|FaultDisputeGame_Test|FaultDispute_1v1_Actors_Test"
77+
export NO_MATCH_PATHS="test/dispute/AnchorStateRegistry.t.sol"
7778
FORK_RPC_URL=$ETH_RPC_URL \
7879
FORK_TEST=true \
7980
forge test --match-path "test/{L1,dispute}/**" \
8081
--no-match-contract "$NO_MATCH_CONTRACTS" \
82+
--no-match-path "$NO_MATCH_PATHS" \
8183
{{ARGS}}
8284

8385
test-upgrade-rerun *ARGS: build-go-ffi

packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -529,10 +529,6 @@ library ChainAssertions {
529529
Blueprint.parseBlueprintPreamble(address(blueprints.resolvedDelegateProxy).code);
530530
require(keccak256(rdProxyPreamble.initcode) == keccak256(vm.getCode("ResolvedDelegateProxy")), "CHECK-OPCM-180");
531531

532-
Blueprint.Preamble memory asrPreamble =
533-
Blueprint.parseBlueprintPreamble(address(blueprints.anchorStateRegistry).code);
534-
require(keccak256(asrPreamble.initcode) == keccak256(vm.getCode("AnchorStateRegistry")), "CHECK-OPCM-190");
535-
536532
Blueprint.Preamble memory pdg1Preamble =
537533
Blueprint.parseBlueprintPreamble(address(blueprints.permissionedDisputeGame1).code);
538534
Blueprint.Preamble memory pdg2Preamble =

packages/contracts-bedrock/scripts/deploy/Deploy.s.sol

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,6 @@ contract Deploy is Deployer {
380380
artifacts.save("DisputeGameFactoryProxy", address(deployOutput.disputeGameFactoryProxy));
381381
artifacts.save("PermissionedDelayedWETHProxy", address(deployOutput.delayedWETHPermissionedGameProxy));
382382
artifacts.save("AnchorStateRegistryProxy", address(deployOutput.anchorStateRegistryProxy));
383-
artifacts.save("AnchorStateRegistryImpl", address(deployOutput.anchorStateRegistryImpl));
384383
artifacts.save("PermissionedDisputeGame", address(deployOutput.permissionedDisputeGame));
385384
artifacts.save("OptimismPortalProxy", address(deployOutput.optimismPortalProxy));
386385
artifacts.save("OptimismPortal2Proxy", address(deployOutput.optimismPortalProxy));
@@ -855,24 +854,6 @@ contract Deploy is Deployer {
855854

856855
/// @notice Get the DeployInput struct to use for testing
857856
function getDeployInput() public view returns (OPContractsManager.DeployInput memory) {
858-
OutputRoot memory testOutputRoot = OutputRoot({
859-
root: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
860-
l2BlockNumber: cfg.faultGameGenesisBlock()
861-
});
862-
IAnchorStateRegistry.StartingAnchorRoot[] memory startingAnchorRoots =
863-
new IAnchorStateRegistry.StartingAnchorRoot[](5);
864-
startingAnchorRoots[0] =
865-
IAnchorStateRegistry.StartingAnchorRoot({ gameType: GameTypes.CANNON, outputRoot: testOutputRoot });
866-
startingAnchorRoots[1] = IAnchorStateRegistry.StartingAnchorRoot({
867-
gameType: GameTypes.PERMISSIONED_CANNON,
868-
outputRoot: testOutputRoot
869-
});
870-
startingAnchorRoots[2] =
871-
IAnchorStateRegistry.StartingAnchorRoot({ gameType: GameTypes.ASTERISC, outputRoot: testOutputRoot });
872-
startingAnchorRoots[3] =
873-
IAnchorStateRegistry.StartingAnchorRoot({ gameType: GameTypes.FAST, outputRoot: testOutputRoot });
874-
startingAnchorRoots[4] =
875-
IAnchorStateRegistry.StartingAnchorRoot({ gameType: GameTypes.ALPHABET, outputRoot: testOutputRoot });
876857
string memory saltMixer = "salt mixer";
877858
return OPContractsManager.DeployInput({
878859
roles: OPContractsManager.Roles({
@@ -886,7 +867,9 @@ contract Deploy is Deployer {
886867
basefeeScalar: cfg.basefeeScalar(),
887868
blobBasefeeScalar: cfg.blobbasefeeScalar(),
888869
l2ChainId: cfg.l2ChainID(),
889-
startingAnchorRoots: abi.encode(startingAnchorRoots),
870+
startingAnchorRoot: abi.encode(
871+
OutputRoot({ root: Hash.wrap(cfg.faultGameGenesisOutputRoot()), l2BlockNumber: cfg.faultGameGenesisBlock() })
872+
),
890873
saltMixer: saltMixer,
891874
gasLimit: uint64(cfg.l2GenesisBlockGasLimit()),
892875
disputeGameType: GameTypes.PERMISSIONED_CANNON,

packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol";
1313
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
1414
import { IMIPS } from "interfaces/cannon/IMIPS.sol";
1515
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
16-
16+
import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol";
1717
import { OPContractsManager } from "src/L1/OPContractsManager.sol";
1818
import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol";
1919
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol";
@@ -142,6 +142,7 @@ contract DeployImplementationsOutput is BaseDeployIO {
142142
IL1StandardBridge internal _l1StandardBridgeImpl;
143143
IOptimismMintableERC20Factory internal _optimismMintableERC20FactoryImpl;
144144
IDisputeGameFactory internal _disputeGameFactoryImpl;
145+
IAnchorStateRegistry internal _anchorStateRegistryImpl;
145146

146147
function set(bytes4 _sel, address _addr) public {
147148
require(_addr != address(0), "DeployImplementationsOutput: cannot set zero address");
@@ -158,6 +159,7 @@ contract DeployImplementationsOutput is BaseDeployIO {
158159
else if (_sel == this.l1StandardBridgeImpl.selector) _l1StandardBridgeImpl = IL1StandardBridge(payable(_addr));
159160
else if (_sel == this.optimismMintableERC20FactoryImpl.selector) _optimismMintableERC20FactoryImpl = IOptimismMintableERC20Factory(_addr);
160161
else if (_sel == this.disputeGameFactoryImpl.selector) _disputeGameFactoryImpl = IDisputeGameFactory(_addr);
162+
else if (_sel == this.anchorStateRegistryImpl.selector) _anchorStateRegistryImpl = IAnchorStateRegistry(_addr);
161163
else revert("DeployImplementationsOutput: unknown selector");
162164
// forgefmt: disable-end
163165
}
@@ -179,7 +181,8 @@ contract DeployImplementationsOutput is BaseDeployIO {
179181
address(this.l1ERC721BridgeImpl()),
180182
address(this.l1StandardBridgeImpl()),
181183
address(this.optimismMintableERC20FactoryImpl()),
182-
address(this.disputeGameFactoryImpl())
184+
address(this.disputeGameFactoryImpl()),
185+
address(this.anchorStateRegistryImpl())
183186
);
184187

185188
DeployUtils.assertValidContractAddresses(Solarray.extend(addrs1, addrs2));
@@ -242,10 +245,16 @@ contract DeployImplementationsOutput is BaseDeployIO {
242245
return _disputeGameFactoryImpl;
243246
}
244247

248+
function anchorStateRegistryImpl() public view returns (IAnchorStateRegistry) {
249+
DeployUtils.assertValidContractAddress(address(_anchorStateRegistryImpl));
250+
return _anchorStateRegistryImpl;
251+
}
252+
245253
// -------- Deployment Assertions --------
246254
function assertValidDeploy(DeployImplementationsInput _dii) public view {
247255
assertValidDelayedWETHImpl(_dii);
248256
assertValidDisputeGameFactoryImpl(_dii);
257+
assertValidAnchorStateRegistryImpl(_dii);
249258
assertValidL1CrossDomainMessengerImpl(_dii);
250259
assertValidL1ERC721BridgeImpl(_dii);
251260
assertValidL1StandardBridgeImpl(_dii);
@@ -387,6 +396,12 @@ contract DeployImplementationsOutput is BaseDeployIO {
387396

388397
require(address(factory.owner()) == address(0), "DG-10");
389398
}
399+
400+
function assertValidAnchorStateRegistryImpl(DeployImplementationsInput) internal view {
401+
IAnchorStateRegistry registry = anchorStateRegistryImpl();
402+
403+
DeployUtils.assertInitialized({ _contractAddress: address(registry), _isProxy: false, _slot: 0, _offset: 0 });
404+
}
390405
}
391406

392407
contract DeployImplementations is Script {
@@ -406,6 +421,7 @@ contract DeployImplementations is Script {
406421
deployPreimageOracleSingleton(_dii, _dio);
407422
deployMipsSingleton(_dii, _dio);
408423
deployDisputeGameFactoryImpl(_dio);
424+
deployAnchorStateRegistryImpl(_dio);
409425

410426
// Deploy the OP Contracts Manager with the new implementations set.
411427
deployOPContractsManager(_dii, _dio);
@@ -438,6 +454,7 @@ contract DeployImplementations is Script {
438454
l1CrossDomainMessengerImpl: address(_dio.l1CrossDomainMessengerImpl()),
439455
l1StandardBridgeImpl: address(_dio.l1StandardBridgeImpl()),
440456
disputeGameFactoryImpl: address(_dio.disputeGameFactoryImpl()),
457+
anchorStateRegistryImpl: address(_dio.anchorStateRegistryImpl()),
441458
delayedWETHImpl: address(_dio.delayedWETHImpl()),
442459
mipsImpl: address(_dio.mipsSingleton())
443460
});
@@ -569,7 +586,7 @@ contract DeployImplementations is Script {
569586
// | Contract | Proxied | Deployment | MCP Ready |
570587
// |-------------------------|---------|-----------------------------------|------------|
571588
// | DisputeGameFactory | Yes | Bespoke | Yes |
572-
// | AnchorStateRegistry | Yes | Bespoke | No |
589+
// | AnchorStateRegistry | Yes | Bespoke | Yes |
573590
// | FaultDisputeGame | No | Bespoke | No | Not yet supported by OPCM
574591
// | PermissionedDisputeGame | No | Bespoke | No |
575592
// | DelayedWETH | Yes | Two bespoke (one per DisputeGame) | Yes *️⃣ |
@@ -586,6 +603,7 @@ contract DeployImplementations is Script {
586603
// here we deploy:
587604
//
588605
// - DisputeGameFactory (implementation)
606+
// - AnchorStateRegistry (implementation)
589607
// - OptimismPortal2 (implementation)
590608
// - DelayedWETH (implementation)
591609
// - PreimageOracle (singleton)
@@ -594,7 +612,6 @@ contract DeployImplementations is Script {
594612
// For contracts which are not MCP ready neither the Proxy nor the implementation can be shared, therefore they
595613
// are deployed by `DeployOpChain.s.sol`.
596614
// These are:
597-
// - AnchorStateRegistry (proxy and implementation)
598615
// - FaultDisputeGame (not proxied)
599616
// - PermissionedDisputeGame (not proxied)
600617
// - DelayedWeth (proxies only)
@@ -690,6 +707,19 @@ contract DeployImplementations is Script {
690707
_dio.set(_dio.disputeGameFactoryImpl.selector, address(impl));
691708
}
692709

710+
function deployAnchorStateRegistryImpl(DeployImplementationsOutput _dio) public virtual {
711+
vm.broadcast(msg.sender);
712+
IAnchorStateRegistry impl = IAnchorStateRegistry(
713+
DeployUtils.createDeterministic({
714+
_name: "AnchorStateRegistry",
715+
_args: DeployUtils.encodeConstructor(abi.encodeCall(IAnchorStateRegistry.__constructor__, ())),
716+
_salt: _salt
717+
})
718+
);
719+
vm.label(address(impl), "AnchorStateRegistryImpl");
720+
_dio.set(_dio.anchorStateRegistryImpl.selector, address(impl));
721+
}
722+
693723
// -------- Utilities --------
694724

695725
function etchIOContracts() public returns (DeployImplementationsInput dii_, DeployImplementationsOutput dio_) {
@@ -769,6 +799,7 @@ contract DeployImplementationsInterop is DeployImplementations {
769799
l1CrossDomainMessengerImpl: address(_dio.l1CrossDomainMessengerImpl()),
770800
l1StandardBridgeImpl: address(_dio.l1StandardBridgeImpl()),
771801
disputeGameFactoryImpl: address(_dio.disputeGameFactoryImpl()),
802+
anchorStateRegistryImpl: address(_dio.anchorStateRegistryImpl()),
772803
delayedWETHImpl: address(_dio.delayedWETHImpl()),
773804
mipsImpl: address(_dio.mipsSingleton())
774805
});

0 commit comments

Comments
 (0)