Commit 5fc066de authored by Mark Tyneway's avatar Mark Tyneway

op-chain-ops: add additional assertions the `check-l2`

The `check-l2` script works against new networks but not legacy
networks. We need a solution that can work against both new networks
and legacy networks. This adds test coverage for new networks
as `check-l2` runs in CI against the local devnet.

Add test coverage for reinitialize on L2 contracts.
Also ensures that the `_initialized` value is set as
expected.
parent 111f3f3a
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
...@@ -24,7 +25,15 @@ import ( ...@@ -24,7 +25,15 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
var defaultCrossDomainMessageSender = common.HexToAddress("0x000000000000000000000000000000000000dead") var (
defaultCrossDomainMessageSender = common.HexToAddress("0x000000000000000000000000000000000000dead")
// errInvalidInitialized represents when the initialized value is not set to the expected value.
// This is an assertion on `_initialized`. We do not care about the value of `_initializing`.
errInvalidInitialized = errors.New("invalid initialized value")
// errAlreadyInitialized represents a revert from when a contract is already initialized.
// This error is used to assert with `eth_call` on contracts that are `Initializable`
errAlreadyInitialized = errors.New("execution reverted: Initializable: contract is already initialized")
)
// Default script for checking that L2 has been configured correctly. This should be extended in the future // Default script for checking that L2 has been configured correctly. This should be extended in the future
// to pull in L1 deploy artifacts and assert that the L2 state is consistent with the L1 state. // to pull in L1 deploy artifacts and assert that the L2 state is consistent with the L1 state.
...@@ -138,7 +147,7 @@ func checkPredeployConfig(client *ethclient.Client, name string) error { ...@@ -138,7 +147,7 @@ func checkPredeployConfig(client *ethclient.Client, name string) error {
return err return err
} }
if impl != standardImpl { if impl != standardImpl {
log.Warn("%s does not have the standard implementation", name) log.Warn(name + " does not have the standard implementation")
} }
implCode, err := client.CodeAt(context.Background(), impl, nil) implCode, err := client.CodeAt(context.Background(), impl, nil)
if err != nil { if err != nil {
...@@ -151,6 +160,8 @@ func checkPredeployConfig(client *ethclient.Client, name string) error { ...@@ -151,6 +160,8 @@ func checkPredeployConfig(client *ethclient.Client, name string) error {
}) })
// Ensure that the code is set to the proxy bytecode as expected // Ensure that the code is set to the proxy bytecode as expected
// This will not work against production networks where the bytecode
// has deviated from the current bytecode. We need a more reliable way to check for this.
g.Go(func() error { g.Go(func() error {
proxyCode, err := client.CodeAt(context.Background(), p, nil) proxyCode, err := client.CodeAt(context.Background(), p, nil)
if err != nil { if err != nil {
...@@ -172,97 +183,97 @@ func checkPredeployConfig(client *ethclient.Client, name string) error { ...@@ -172,97 +183,97 @@ func checkPredeployConfig(client *ethclient.Client, name string) error {
switch p { switch p {
case predeploys.LegacyMessagePasserAddr: case predeploys.LegacyMessagePasserAddr:
if err := checkLegacyMessagePasser(p, client); err != nil { if err := checkLegacyMessagePasser(p, client); err != nil {
return err return fmt.Errorf("LegacyMessagePasser: %w", err)
} }
case predeploys.DeployerWhitelistAddr: case predeploys.DeployerWhitelistAddr:
if err := checkDeployerWhitelist(p, client); err != nil { if err := checkDeployerWhitelist(p, client); err != nil {
return err return fmt.Errorf("DeployerWhiteList: %w", err)
} }
case predeploys.L2CrossDomainMessengerAddr: case predeploys.L2CrossDomainMessengerAddr:
if err := checkL2CrossDomainMessenger(p, client); err != nil { if err := checkL2CrossDomainMessenger(p, client); err != nil {
return err return fmt.Errorf("L2CrossDomainMessenger: %w", err)
} }
case predeploys.GasPriceOracleAddr: case predeploys.GasPriceOracleAddr:
if err := checkGasPriceOracle(p, client); err != nil { if err := checkGasPriceOracle(p, client); err != nil {
return err return fmt.Errorf("GasPriceOracle: %w", err)
} }
case predeploys.L2StandardBridgeAddr: case predeploys.L2StandardBridgeAddr:
if err := checkL2StandardBridge(p, client); err != nil { if err := checkL2StandardBridge(p, client); err != nil {
return err return fmt.Errorf("L2StandardBridge: %w", err)
} }
case predeploys.SequencerFeeVaultAddr: case predeploys.SequencerFeeVaultAddr:
if err := checkSequencerFeeVault(p, client); err != nil { if err := checkSequencerFeeVault(p, client); err != nil {
return err return fmt.Errorf("SequencerFeeVault: %w", err)
} }
case predeploys.OptimismMintableERC20FactoryAddr: case predeploys.OptimismMintableERC20FactoryAddr:
if err := checkOptimismMintableERC20Factory(p, client); err != nil { if err := checkOptimismMintableERC20Factory(p, client); err != nil {
return err return fmt.Errorf("OptimismMintableERC20Factory: %w", err)
} }
case predeploys.L1BlockNumberAddr: case predeploys.L1BlockNumberAddr:
if err := checkL1BlockNumber(p, client); err != nil { if err := checkL1BlockNumber(p, client); err != nil {
return err return fmt.Errorf("L1BlockNumber: %w", err)
} }
case predeploys.L1BlockAddr: case predeploys.L1BlockAddr:
if err := checkL1Block(p, client); err != nil { if err := checkL1Block(p, client); err != nil {
return err return fmt.Errorf("L1Block: %w", err)
} }
case predeploys.WETH9Addr: case predeploys.WETH9Addr:
if err := checkWETH9(p, client); err != nil { if err := checkWETH9(p, client); err != nil {
return err return fmt.Errorf("WETH9: %w", err)
} }
case predeploys.GovernanceTokenAddr: case predeploys.GovernanceTokenAddr:
if err := checkGovernanceToken(p, client); err != nil { if err := checkGovernanceToken(p, client); err != nil {
return err return fmt.Errorf("GovernanceToken: %w", err)
} }
case predeploys.L2ERC721BridgeAddr: case predeploys.L2ERC721BridgeAddr:
if err := checkL2ERC721Bridge(p, client); err != nil { if err := checkL2ERC721Bridge(p, client); err != nil {
return err return fmt.Errorf("L2ERC721Bridge: %w", err)
} }
case predeploys.OptimismMintableERC721FactoryAddr: case predeploys.OptimismMintableERC721FactoryAddr:
if err := checkOptimismMintableERC721Factory(p, client); err != nil { if err := checkOptimismMintableERC721Factory(p, client); err != nil {
return err return fmt.Errorf("OptimismMintableERC721Factory: %w", err)
} }
case predeploys.ProxyAdminAddr: case predeploys.ProxyAdminAddr:
if err := checkProxyAdmin(p, client); err != nil { if err := checkProxyAdmin(p, client); err != nil {
return err return fmt.Errorf("ProxyAdmin: %w", err)
} }
case predeploys.BaseFeeVaultAddr: case predeploys.BaseFeeVaultAddr:
if err := checkBaseFeeVault(p, client); err != nil { if err := checkBaseFeeVault(p, client); err != nil {
return err return fmt.Errorf("BaseFeeVault: %w", err)
} }
case predeploys.L1FeeVaultAddr: case predeploys.L1FeeVaultAddr:
if err := checkL1FeeVault(p, client); err != nil { if err := checkL1FeeVault(p, client); err != nil {
return err return fmt.Errorf("L1FeeVault: %w", err)
} }
case predeploys.L2ToL1MessagePasserAddr: case predeploys.L2ToL1MessagePasserAddr:
if err := checkL2ToL1MessagePasser(p, client); err != nil { if err := checkL2ToL1MessagePasser(p, client); err != nil {
return err return fmt.Errorf("L2ToL1MessagePasser: %w", err)
} }
case predeploys.SchemaRegistryAddr: case predeploys.SchemaRegistryAddr:
if err := checkSchemaRegistry(p, client); err != nil { if err := checkSchemaRegistry(p, client); err != nil {
return err return fmt.Errorf("SchemaRegistry: %w", err)
} }
case predeploys.EASAddr: case predeploys.EASAddr:
if err := checkEAS(p, client); err != nil { if err := checkEAS(p, client); err != nil {
return err return fmt.Errorf("EAS: %w", err)
} }
} }
return nil return nil
...@@ -429,6 +440,25 @@ func checkL2ERC721Bridge(addr common.Address, client *ethclient.Client) error { ...@@ -429,6 +440,25 @@ func checkL2ERC721Bridge(addr common.Address, client *ethclient.Client) error {
return err return err
} }
log.Info("L2ERC721Bridge", "_initialized", initialized) log.Info("L2ERC721Bridge", "_initialized", initialized)
if initialized.Uint64() != genesis.InitializedValue {
return fmt.Errorf("%w: %s", errInvalidInitialized, initialized)
}
abi, err := bindings.L2ERC721BridgeMetaData.GetAbi()
if err != nil {
return err
}
calldata, err := abi.Pack("initialize")
if err != nil {
return err
}
msg := ethereum.CallMsg{
To: &addr,
Data: calldata,
}
if _, err := client.CallContract(context.Background(), msg, nil); err.Error() != errAlreadyInitialized.Error() {
return err
}
initializing, err := getInitializing("L2ERC721Bridge", addr, client) initializing, err := getInitializing("L2ERC721Bridge", addr, client)
if err != nil { if err != nil {
...@@ -566,6 +596,25 @@ func checkOptimismMintableERC20Factory(addr common.Address, client *ethclient.Cl ...@@ -566,6 +596,25 @@ func checkOptimismMintableERC20Factory(addr common.Address, client *ethclient.Cl
return err return err
} }
log.Info("OptimismMintableERC20Factory", "_initialized", initialized) log.Info("OptimismMintableERC20Factory", "_initialized", initialized)
if initialized.Uint64() != genesis.InitializedValue {
return fmt.Errorf("%w: %s", errInvalidInitialized, initialized)
}
abi, err := bindings.OptimismMintableERC20FactoryMetaData.GetAbi()
if err != nil {
return err
}
calldata, err := abi.Pack("initialize", common.Address{})
if err != nil {
return err
}
msg := ethereum.CallMsg{
To: &addr,
Data: calldata,
}
if _, err := client.CallContract(context.Background(), msg, nil); err.Error() != errAlreadyInitialized.Error() {
return err
}
initializing, err := getInitializing("OptimismMintableERC20Factory", addr, client) initializing, err := getInitializing("OptimismMintableERC20Factory", addr, client)
if err != nil { if err != nil {
...@@ -647,6 +696,25 @@ func checkL2StandardBridge(addr common.Address, client *ethclient.Client) error ...@@ -647,6 +696,25 @@ func checkL2StandardBridge(addr common.Address, client *ethclient.Client) error
return err return err
} }
log.Info("L2StandardBridge", "_initialized", initialized) log.Info("L2StandardBridge", "_initialized", initialized)
if initialized.Uint64() != genesis.InitializedValue {
return fmt.Errorf("%w: %s", errInvalidInitialized, initialized)
}
abi, err := bindings.L2StandardBridgeMetaData.GetAbi()
if err != nil {
return err
}
calldata, err := abi.Pack("initialize")
if err != nil {
return err
}
msg := ethereum.CallMsg{
To: &addr,
Data: calldata,
}
if _, err := client.CallContract(context.Background(), msg, nil); err.Error() != errAlreadyInitialized.Error() {
return err
}
initializing, err := getInitializing("L2StandardBridge", addr, client) initializing, err := getInitializing("L2StandardBridge", addr, client)
if err != nil { if err != nil {
...@@ -766,6 +834,25 @@ func checkL2CrossDomainMessenger(addr common.Address, client *ethclient.Client) ...@@ -766,6 +834,25 @@ func checkL2CrossDomainMessenger(addr common.Address, client *ethclient.Client)
return err return err
} }
log.Info("L2CrossDomainMessenger", "_initialized", initialized) log.Info("L2CrossDomainMessenger", "_initialized", initialized)
if initialized.Uint64() != genesis.InitializedValue {
return fmt.Errorf("%w: %s", errInvalidInitialized, initialized)
}
abi, err := bindings.L2CrossDomainMessengerMetaData.GetAbi()
if err != nil {
return err
}
calldata, err := abi.Pack("initialize")
if err != nil {
return err
}
msg := ethereum.CallMsg{
To: &addr,
Data: calldata,
}
if _, err := client.CallContract(context.Background(), msg, nil); err.Error() != errAlreadyInitialized.Error() {
return err
}
initializing, err := getInitializing("L2CrossDomainMessenger", addr, client) initializing, err := getInitializing("L2CrossDomainMessenger", addr, client)
if err != nil { if err != nil {
......
...@@ -29,7 +29,7 @@ import ( ...@@ -29,7 +29,7 @@ import (
// initialzedValue represents the `Initializable` contract value. It should be kept in // initialzedValue represents the `Initializable` contract value. It should be kept in
// sync with the constant in `Constants.sol`. // sync with the constant in `Constants.sol`.
// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/libraries/Constants.sol // https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/libraries/Constants.sol
const initializedValue = 3 const InitializedValue = 3
var ( var (
ErrInvalidDeployConfig = errors.New("invalid deploy config") ErrInvalidDeployConfig = errors.New("invalid deploy config")
...@@ -726,13 +726,13 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage ...@@ -726,13 +726,13 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage
"msgNonce": 0, "msgNonce": 0,
} }
storage["L2CrossDomainMessenger"] = state.StorageValues{ storage["L2CrossDomainMessenger"] = state.StorageValues{
"_initialized": initializedValue, "_initialized": InitializedValue,
"_initializing": false, "_initializing": false,
"xDomainMsgSender": "0x000000000000000000000000000000000000dEaD", "xDomainMsgSender": "0x000000000000000000000000000000000000dEaD",
"msgNonce": 0, "msgNonce": 0,
} }
storage["L2StandardBridge"] = state.StorageValues{ storage["L2StandardBridge"] = state.StorageValues{
"_initialized": initializedValue, "_initialized": InitializedValue,
"_initializing": false, "_initializing": false,
"messenger": predeploys.L2CrossDomainMessengerAddr, "messenger": predeploys.L2CrossDomainMessengerAddr,
} }
...@@ -767,12 +767,12 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage ...@@ -767,12 +767,12 @@ func NewL2StorageConfig(config *DeployConfig, block *types.Block) (state.Storage
} }
storage["L2ERC721Bridge"] = state.StorageValues{ storage["L2ERC721Bridge"] = state.StorageValues{
"messenger": predeploys.L2CrossDomainMessengerAddr, "messenger": predeploys.L2CrossDomainMessengerAddr,
"_initialized": initializedValue, "_initialized": InitializedValue,
"_initializing": false, "_initializing": false,
} }
storage["OptimismMintableERC20Factory"] = state.StorageValues{ storage["OptimismMintableERC20Factory"] = state.StorageValues{
"bridge": predeploys.L2StandardBridgeAddr, "bridge": predeploys.L2StandardBridgeAddr,
"_initialized": initializedValue, "_initialized": InitializedValue,
"_initializing": false, "_initializing": false,
} }
return storage, nil return storage, nil
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment