Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce AnchorStateRegistry #9835

Merged
merged 2 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 111 additions & 66 deletions op-bindings/bindings/faultdisputegame.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions op-bindings/bindings/faultdisputegame_more.go

Large diffs are not rendered by default.

54 changes: 27 additions & 27 deletions op-challenger/game/fault/contracts/faultdisputegame.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,29 @@ import (
)

var (
methodGameDuration = "gameDuration"
methodMaxGameDepth = "maxGameDepth"
methodAbsolutePrestate = "absolutePrestate"
methodStatus = "status"
methodRootClaim = "rootClaim"
methodClaimCount = "claimDataLen"
methodClaim = "claimData"
methodL1Head = "l1Head"
methodResolve = "resolve"
methodResolveClaim = "resolveClaim"
methodAttack = "attack"
methodDefend = "defend"
methodStep = "step"
methodAddLocalData = "addLocalData"
methodVM = "vm"
methodGenesisBlockNumber = "genesisBlockNumber"
methodGenesisOutputRoot = "genesisOutputRoot"
methodSplitDepth = "splitDepth"
methodL2BlockNumber = "l2BlockNumber"
methodRequiredBond = "getRequiredBond"
methodClaimCredit = "claimCredit"
methodCredit = "credit"
methodWETH = "weth"
methodGameDuration = "gameDuration"
methodMaxGameDepth = "maxGameDepth"
methodAbsolutePrestate = "absolutePrestate"
methodStatus = "status"
methodRootClaim = "rootClaim"
methodClaimCount = "claimDataLen"
methodClaim = "claimData"
methodL1Head = "l1Head"
methodResolve = "resolve"
methodResolveClaim = "resolveClaim"
methodAttack = "attack"
methodDefend = "defend"
methodStep = "step"
methodAddLocalData = "addLocalData"
methodVM = "vm"
methodStartingBlockNumber = "startingBlockNumber"
methodStartingRootHash = "startingRootHash"
methodSplitDepth = "splitDepth"
methodL2BlockNumber = "l2BlockNumber"
methodRequiredBond = "getRequiredBond"
methodClaimCredit = "claimCredit"
methodCredit = "credit"
methodWETH = "weth"
)

type FaultDisputeGameContract struct {
Expand Down Expand Up @@ -83,7 +83,7 @@ func (f *FaultDisputeGameContract) GetBalance(ctx context.Context, block rpcbloc
// and the post-state block (that the proposed output root is for).
func (f *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateBlock uint64, poststateBlock uint64, retErr error) {
results, err := f.multiCaller.Call(ctx, rpcblock.Latest,
f.contract.Call(methodGenesisBlockNumber),
f.contract.Call(methodStartingBlockNumber),
f.contract.Call(methodL2BlockNumber))
if err != nil {
retErr = fmt.Errorf("failed to retrieve game block range: %w", err)
Expand Down Expand Up @@ -123,12 +123,12 @@ func (f *FaultDisputeGameContract) GetGameMetadata(ctx context.Context, block rp
return l1Head, l2BlockNumber, rootClaim, status, duration, nil
}

func (f *FaultDisputeGameContract) GetGenesisOutputRoot(ctx context.Context) (common.Hash, error) {
genesisOutputRoot, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodGenesisOutputRoot))
func (f *FaultDisputeGameContract) GetStartingRootHash(ctx context.Context) (common.Hash, error) {
startingRootHash, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodStartingRootHash))
if err != nil {
return common.Hash{}, fmt.Errorf("failed to retrieve genesis output root: %w", err)
}
return genesisOutputRoot.GetHash(0), nil
return startingRootHash.GetHash(0), nil
}

func (f *FaultDisputeGameContract) GetSplitDepth(ctx context.Context) (types.Depth, error) {
Expand Down
10 changes: 5 additions & 5 deletions op-challenger/game/fault/contracts/faultdisputegame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ func TestGetBlockRange(t *testing.T) {
stubRpc, contract := setupFaultDisputeGameTest(t)
expectedStart := uint64(65)
expectedEnd := uint64(102)
stubRpc.SetResponse(fdgAddr, methodGenesisBlockNumber, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(expectedStart)})
stubRpc.SetResponse(fdgAddr, methodStartingBlockNumber, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(expectedStart)})
stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(expectedEnd)})
start, end, err := contract.GetBlockRange(context.Background())
require.NoError(t, err)
Expand Down Expand Up @@ -354,13 +354,13 @@ func TestGetGameMetadata(t *testing.T) {
require.Equal(t, expectedGameDuration, duration)
}

func TestGetGenesisOutputRoot(t *testing.T) {
func TestGetStartingRootHash(t *testing.T) {
stubRpc, contract := setupFaultDisputeGameTest(t)
expectedOutputRoot := common.HexToHash("0x1234")
stubRpc.SetResponse(fdgAddr, methodGenesisOutputRoot, rpcblock.Latest, nil, []interface{}{expectedOutputRoot})
genesisOutputRoot, err := contract.GetGenesisOutputRoot(context.Background())
stubRpc.SetResponse(fdgAddr, methodStartingRootHash, rpcblock.Latest, nil, []interface{}{expectedOutputRoot})
startingOutputRoot, err := contract.GetStartingRootHash(context.Background())
require.NoError(t, err)
require.Equal(t, expectedOutputRoot, genesisOutputRoot)
require.Equal(t, expectedOutputRoot, startingOutputRoot)
}

func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) {
Expand Down
8 changes: 4 additions & 4 deletions op-challenger/game/fault/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ func registerAlphabet(
return accessor, nil
}
prestateValidator := NewPrestateValidator("alphabet", contract.GetAbsolutePrestateHash, alphabet.PrestateProvider)
genesisValidator := NewPrestateValidator("output root", contract.GetGenesisOutputRoot, prestateProvider)
return NewGamePlayer(ctx, cl, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, genesisValidator}, creator, l1HeaderSource, selective, claimants)
startingValidator := NewPrestateValidator("output root", contract.GetStartingRootHash, prestateProvider)
return NewGamePlayer(ctx, cl, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, startingValidator}, creator, l1HeaderSource, selective, claimants)
}
err := registerOracle(ctx, oracles, gameFactory, caller, faultTypes.AlphabetGameType)
if err != nil {
Expand Down Expand Up @@ -215,8 +215,8 @@ func registerCannon(
return accessor, nil
}
prestateValidator := NewPrestateValidator("cannon", contract.GetAbsolutePrestateHash, cannonPrestateProvider)
genesisValidator := NewPrestateValidator("output root", contract.GetGenesisOutputRoot, prestateProvider)
return NewGamePlayer(ctx, cl, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, genesisValidator}, creator, l1HeaderSource, selective, claimants)
startingValidator := NewPrestateValidator("output root", contract.GetStartingRootHash, prestateProvider)
return NewGamePlayer(ctx, cl, logger, m, dir, game.Proxy, txSender, contract, syncValidator, []Validator{prestateValidator, startingValidator}, creator, l1HeaderSource, selective, claimants)
}
err := registerOracle(ctx, oracles, gameFactory, caller, gameType)
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions op-e2e/e2eutils/disputegame/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string
h.require.NoError(err)

callOpts := &bind.CallOpts{Context: ctx}
prestateBlock, err := game.GenesisBlockNumber(callOpts)
h.require.NoError(err, "Failed to load genesis block number")
prestateBlock, err := game.StartingBlockNumber(callOpts)
h.require.NoError(err, "Failed to load starting block number")
poststateBlock, err := game.L2BlockNumber(callOpts)
h.require.NoError(err, "Failed to load l2 block number")
splitDepth, err := game.SplitDepth(callOpts)
Expand Down Expand Up @@ -251,8 +251,8 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri
h.require.NoError(err)

callOpts := &bind.CallOpts{Context: ctx}
prestateBlock, err := game.GenesisBlockNumber(callOpts)
h.require.NoError(err, "Failed to load genesis block number")
prestateBlock, err := game.StartingBlockNumber(callOpts)
h.require.NoError(err, "Failed to load starting block number")
poststateBlock, err := game.L2BlockNumber(callOpts)
h.require.NoError(err, "Failed to load l2 block number")
splitDepth, err := game.SplitDepth(callOpts)
Expand Down
6 changes: 3 additions & 3 deletions op-e2e/e2eutils/disputegame/output_game_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ func (g *OutputGameHelper) L2BlockNum(ctx context.Context) uint64 {
return blockNum.Uint64()
}

func (g *OutputGameHelper) GenesisBlockNum(ctx context.Context) uint64 {
blockNum, err := g.game.GenesisBlockNumber(&bind.CallOpts{Context: ctx})
g.require.NoError(err, "failed to load genesis block number")
func (g *OutputGameHelper) StartingBlockNum(ctx context.Context) uint64 {
blockNum, err := g.game.StartingBlockNumber(&bind.CallOpts{Context: ctx})
smartcontracts marked this conversation as resolved.
Show resolved Hide resolved
g.require.NoError(err, "failed to load starting block number")
return blockNum.Uint64()
}

Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-bedrock/.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (g
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92930)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68360)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 69013)
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155556)
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155551)
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"faultGameMaxDepth": 50,
"faultGameMaxDuration": 2400,
"faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
"faultGameSplitDepth": 14,
"faultGameWithdrawalDelay": 604800,
"preimageOracleMinProposalSize": 10000,
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-bedrock/deploy-config/hardhat.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"faultGameMaxDepth": 8,
"faultGameMaxDuration": 2400,
"faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
smartcontracts marked this conversation as resolved.
Show resolved Hide resolved
"faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
"faultGameSplitDepth": 4,
"faultGameWithdrawalDelay": 604800,
"preimageOracleMinProposalSize": 10000,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `FaultDisputeGame` Invariants

## FaultDisputeGame always returns all ETH on total resolution
**Test:** [`FaultDisputeGame.t.sol#L39`](../test/invariants/FaultDisputeGame.t.sol#L39)
**Test:** [`FaultDisputeGame.t.sol#L33`](../test/invariants/FaultDisputeGame.t.sol#L33)

The FaultDisputeGame contract should always return all ETH in the contract to the correct recipients upon resolution of all outstanding claims. There may never be any ETH left in the contract after a full resolution.
65 changes: 61 additions & 4 deletions packages/contracts-bedrock/scripts/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol";
import { PermissionedDisputeGame } from "src/dispute/PermissionedDisputeGame.sol";
import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol";
import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
import { MIPS } from "src/cannon/MIPS.sol";
import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
Expand Down Expand Up @@ -69,6 +70,7 @@ contract Deploy is Deployer {
/// to finally adopt PUSHN and get rid of stack too deep once and for all.
/// Someday we will look back and laugh about stack too deep, today is not that day.
struct FaultDisputeGameParams {
AnchorStateRegistry anchorStateRegistry;
DelayedWETH weth;
GameType gameType;
Claim absolutePrestate;
Expand Down Expand Up @@ -144,6 +146,7 @@ contract Deploy is Deployer {
L2OutputOracle: mustGetAddress("L2OutputOracleProxy"),
DisputeGameFactory: mustGetAddress("DisputeGameFactoryProxy"),
DelayedWETH: mustGetAddress("DelayedWETHProxy"),
AnchorStateRegistry: mustGetAddress("AnchorStateRegistryProxy"),
OptimismMintableERC20Factory: mustGetAddress("OptimismMintableERC20FactoryProxy"),
OptimismPortal: mustGetAddress("OptimismPortalProxy"),
OptimismPortal2: mustGetAddress("OptimismPortalProxy"),
Expand All @@ -162,6 +165,7 @@ contract Deploy is Deployer {
L2OutputOracle: getAddress("L2OutputOracleProxy"),
DisputeGameFactory: getAddress("DisputeGameFactoryProxy"),
DelayedWETH: getAddress("DelayedWETHProxy"),
AnchorStateRegistry: getAddress("AnchorStateRegistryProxy"),
OptimismMintableERC20Factory: getAddress("OptimismMintableERC20FactoryProxy"),
OptimismPortal: getAddress("OptimismPortalProxy"),
OptimismPortal2: getAddress("OptimismPortalProxy"),
Expand Down Expand Up @@ -345,6 +349,7 @@ contract Deploy is Deployer {
deployERC1967Proxy("DisputeGameFactoryProxy");
deployERC1967Proxy("L2OutputOracleProxy");
deployERC1967Proxy("DelayedWETHProxy");
deployERC1967Proxy("AnchorStateRegistryProxy");

transferAddressManagerOwnership(); // to the ProxyAdmin
}
Expand All @@ -366,6 +371,7 @@ contract Deploy is Deployer {
deployDelayedWETH();
deployPreimageOracle();
deployMips();
deployAnchorStateRegistry();
}

/// @notice Initialize all of the implementations
Expand All @@ -379,6 +385,7 @@ contract Deploy is Deployer {
initializeL2OutputOracle();
initializeDisputeGameFactory();
initializeDelayedWETH();
initializeAnchorStateRegistry();

// Selectively initialize either the original OptimismPortal or the new OptimismPortal2. Since this will upgrade
// the proxy, we cannot initialize both. FPAC warning can be removed once we're done with the old OptimismPortal
Expand Down Expand Up @@ -731,6 +738,17 @@ contract Deploy is Deployer {
addr_ = address(mips);
}

/// @notice Deploy the AnchorStateRegistry
function deployAnchorStateRegistry() public broadcast returns (address addr_) {
console.log("Deploying AnchorStateRegistry implementation");
AnchorStateRegistry anchorStateRegistry =
new AnchorStateRegistry{ salt: _implSalt() }(DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy")));
save("AnchorStateRegistry", address(anchorStateRegistry));
console.log("AnchorStateRegistry deployed at %s", address(anchorStateRegistry));

addr_ = address(anchorStateRegistry);
}

/// @notice Deploy the SystemConfig
function deploySystemConfig() public broadcast returns (address addr_) {
console.log("Deploying SystemConfig implementation");
Expand Down Expand Up @@ -869,6 +887,44 @@ contract Deploy is Deployer {
});
}

function initializeAnchorStateRegistry() public broadcast {
console.log("Upgrading and initializing AnchorStateRegistry proxy");
address anchorStateRegistryProxy = mustGetAddress("AnchorStateRegistryProxy");
address anchorStateRegistry = mustGetAddress("AnchorStateRegistry");

AnchorStateRegistry.StartingAnchorRoot[] memory roots = new AnchorStateRegistry.StartingAnchorRoot[](3);
roots[0] = AnchorStateRegistry.StartingAnchorRoot({
gameType: GameTypes.CANNON,
outputRoot: OutputRoot({
root: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
l2BlockNumber: cfg.faultGameGenesisBlock()
})
});
roots[1] = AnchorStateRegistry.StartingAnchorRoot({
gameType: GameTypes.PERMISSIONED_CANNON,
outputRoot: OutputRoot({
root: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
l2BlockNumber: cfg.faultGameGenesisBlock()
})
});
roots[2] = AnchorStateRegistry.StartingAnchorRoot({
gameType: GameTypes.ALPHABET,
outputRoot: OutputRoot({
root: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
l2BlockNumber: cfg.faultGameGenesisBlock()
})
});

_upgradeAndCallViaSafe({
_proxy: payable(anchorStateRegistryProxy),
_implementation: anchorStateRegistry,
_innerCallData: abi.encodeCall(AnchorStateRegistry.initialize, (roots))
});

string memory version = AnchorStateRegistry(payable(anchorStateRegistryProxy)).version();
console.log("AnchorStateRegistry version: %s", version);
}

/// @notice Initialize the SystemConfig
function initializeSystemConfig() public broadcast {
console.log("Upgrading and initializing SystemConfig proxy");
Expand Down Expand Up @@ -1222,6 +1278,7 @@ contract Deploy is Deployer {
_factory: factory,
_allowUpgrade: _allowUpgrade,
_params: FaultDisputeGameParams({
anchorStateRegistry: AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
weth: weth,
gameType: GameTypes.CANNON,
absolutePrestate: loadMipsAbsolutePrestate(),
Expand All @@ -1242,6 +1299,7 @@ contract Deploy is Deployer {
_factory: factory,
_allowUpgrade: _allowUpgrade,
_params: FaultDisputeGameParams({
anchorStateRegistry: AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
weth: weth,
gameType: GameTypes.PERMISSIONED_CANNON,
absolutePrestate: loadMipsAbsolutePrestate(),
Expand All @@ -1262,6 +1320,7 @@ contract Deploy is Deployer {
_factory: factory,
_allowUpgrade: _allowUpgrade,
_params: FaultDisputeGameParams({
anchorStateRegistry: AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
weth: weth,
gameType: GameTypes.ALPHABET,
absolutePrestate: outputAbsolutePrestate,
Expand Down Expand Up @@ -1295,13 +1354,12 @@ contract Deploy is Deployer {
new FaultDisputeGame({
_gameType: _params.gameType,
_absolutePrestate: _params.absolutePrestate,
_genesisBlockNumber: cfg.faultGameGenesisBlock(),
_genesisOutputRoot: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
_maxGameDepth: _params.maxGameDepth,
_splitDepth: cfg.faultGameSplitDepth(),
_gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())),
_vm: _params.faultVm,
_weth: _params.weth,
_anchorStateRegistry: _params.anchorStateRegistry,
_l2ChainId: cfg.l2ChainID()
})
);
Expand All @@ -1311,13 +1369,12 @@ contract Deploy is Deployer {
new PermissionedDisputeGame({
_gameType: _params.gameType,
_absolutePrestate: _params.absolutePrestate,
_genesisBlockNumber: cfg.faultGameGenesisBlock(),
_genesisOutputRoot: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
_maxGameDepth: _params.maxGameDepth,
_splitDepth: cfg.faultGameSplitDepth(),
_gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())),
_vm: _params.faultVm,
_weth: _params.weth,
_anchorStateRegistry: _params.anchorStateRegistry,
_l2ChainId: cfg.l2ChainID(),
_proposer: cfg.l2OutputOracleProposer(),
_challenger: cfg.l2OutputOracleChallenger()
Expand Down
8 changes: 1 addition & 7 deletions packages/contracts-bedrock/scripts/FaultDisputeGameViz.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,7 @@ contract FaultDisputeGameViz is Script, FaultDisputeGame_Init {

function setUp() public override {
super.setUp();
super.init({
rootClaim: ROOT_CLAIM,
absolutePrestate: ABSOLUTE_PRESTATE,
l2BlockNumber: 0x10,
genesisBlockNumber: 0,
genesisOutputRoot: Hash.wrap(bytes32(0))
});
super.init({ rootClaim: ROOT_CLAIM, absolutePrestate: ABSOLUTE_PRESTATE, l2BlockNumber: 0x10 });
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/contracts-bedrock/scripts/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ library Types {
address L2OutputOracle;
address DisputeGameFactory;
address DelayedWETH;
address AnchorStateRegistry;
address OptimismMintableERC20Factory;
address OptimismPortal;
address OptimismPortal2;
Expand Down
Loading