Commit cef704af authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

op-chain-ops: delete check-l2 (#8942)

As of https://github.com/ethereum-optimism/optimism/pull/8933 and https://github.com/ethereum-optimism/optimism/pull/8911
all of `check-l2` tests exist in solidity and are better. There is no
real reason to keep `check-l2` around because it just adds additional
headache.
parent 5996d0bc
...@@ -329,12 +329,6 @@ CommandPreset = namedtuple('Command', ['name', 'args', 'cwd', 'timeout']) ...@@ -329,12 +329,6 @@ CommandPreset = namedtuple('Command', ['name', 'args', 'cwd', 'timeout'])
def devnet_test(paths): def devnet_test(paths):
# Check the L2 config
run_command(
['go', 'run', 'cmd/check-l2/main.go', '--l2-rpc-url', 'http://localhost:9545', '--l1-rpc-url', 'http://localhost:8545'],
cwd=paths.ops_chain_ops,
)
# Run the two commands with different signers, so the ethereum nonce management does not conflict # Run the two commands with different signers, so the ethereum nonce management does not conflict
# And do not use devnet system addresses, to avoid breaking fee-estimation or nonce values. # And do not use devnet system addresses, to avoid breaking fee-estimation or nonce values.
run_commands([ run_commands([
......
...@@ -332,8 +332,7 @@ Not every contract can be added as a predeploy, and some contracts have nuances ...@@ -332,8 +332,7 @@ Not every contract can be added as a predeploy, and some contracts have nuances
Once you've configured the `contracts-list` to include the contracts you'd like to add as predeploys, the next step is utilizing the BindGen outputs to configure the L2 genesis. Once you've configured the `contracts-list` to include the contracts you'd like to add as predeploys, the next step is utilizing the BindGen outputs to configure the L2 genesis.
1. First we must update the [addresses.go](../predeploys/addresses.go) file to include the address we're predeploying our contracts to 1. First we must update the [addresses.go](../predeploys/addresses.go) file to include the address we're predeploying our contracts to
2. Update the `switch` case found in [layer_two.go](../../op-chain-ops/genesis/layer_two.go) to include the `name` of your contracts 1. Update the `switch` case found in [layer_two.go](../../op-chain-ops/genesis/layer_two.go) to include the `name` of your contracts
3. Update [immutables.go](../../op-chain-ops/immutables/immutables.go) to include your added contracts 1. Update [immutables.go](../../op-chain-ops/immutables/immutables.go) to include your added contracts
4. Update [check-l2/main.go](../../op-chain-ops/cmd/check-l2/main.go) to include a check to verify your contract was added correctly 1. Update [Predeploys.sol](../../packages/contracts-bedrock/src/libraries/Predeploys.sol) to include your added contracts at their expected addresses
5. Update [Predeploys.sol](../../packages/contracts-bedrock/src/libraries/Predeploys.sol) to include your added contracts at their expected addresses 1. Update [Predeploys.t.sol](../../packages/contracts-bedrock/test/Predeploys.t.sol) to include the `name` of your contracts to avoid being tested for `Predeploys.PROXY_ADMIN`
6. Update [Predeploys.t.sol](../../packages/contracts-bedrock/test/Predeploys.t.sol) to include the `name` of your contracts to avoid being tested for `Predeploys.PROXY_ADMIN`
all: check-l2
check-l2:
go build -o ./bin/check-l2 ./cmd/check-l2/main.go
test: test:
go test ./... go test ./...
...@@ -12,4 +7,4 @@ fuzz: ...@@ -12,4 +7,4 @@ fuzz:
go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzAliasing ./crossdomain go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzAliasing ./crossdomain
go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzVersionedNonce ./crossdomain go test -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzVersionedNonce ./crossdomain
.PHONY: check-l2 test fuzz .PHONY: test fuzz
# op-chain-ops # op-chain-ops
This package contains utilities for working with chain state. This package contains utilities for working with chain state.
## check-l2
The `check-l2` binary is used for verifying that an OP Stack L2
has been configured correctly. It iterates over all 2048 predeployed
proxies to make sure they are configured correctly with the correct
proxy admin address. After that, it checks that all [predeploys](../op-bindings/predeploys/addresses.go)
are configured and aliased correctly. Additional contract-specific
checks ensure configuration like ownership, version, and storage
is set correctly for the predeploys.
#### Usage
It can be built and run using the [Makefile](./Makefile) `check-l2` target.
Run `make check-l2` to create a binary in [./bin/check-l2](./bin/check-l2)
that can be executed by providing the `--l1-rpc-url` and `--l2-rpc-url` flags.
```sh
./bin/check-l2 \
--l2-rpc-url http://localhost:9545 \
--l1-rpc-url http://localhost:8545
```
package main
import (
"bytes"
"context"
"errors"
"fmt"
"math/big"
"os"
"strings"
"golang.org/x/sync/errgroup"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/clients"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
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("Initializable: contract is already initialized")
)
// 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.
func main() {
log.Root().SetHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(isatty.IsTerminal(os.Stderr.Fd()))))
app := &cli.App{
Name: "check-l2",
Usage: "Check that an OP Stack L2 has been configured correctly",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "l1-rpc-url",
Value: "http://127.0.0.1:8545",
Usage: "L1 RPC URL",
EnvVars: []string{"L1_RPC_URL"},
},
&cli.StringFlag{
Name: "l2-rpc-url",
Value: "http://127.0.0.1:9545",
Usage: "L2 RPC URL",
EnvVars: []string{"L2_RPC_URL"},
},
},
Action: entrypoint,
}
if err := app.Run(os.Args); err != nil {
log.Crit("error checking l2", "err", err)
}
}
// entrypoint is the entrypoint for the check-l2 script
func entrypoint(ctx *cli.Context) error {
clients, err := clients.NewClientsFromContext(ctx)
if err != nil {
return err
}
log.Info("Checking predeploy proxy config")
// Check that all of the defined predeploys are set up correctly
for name, pre := range predeploys.Predeploys {
log.Info("Checking predeploy", "name", name, "address", pre.Address.Hex())
if err := checkPredeployConfig(clients.L2Client, name); err != nil {
return err
}
}
return nil
}
// checkPredeployConfig checks that the defined predeploys are configured correctly
func checkPredeployConfig(client *ethclient.Client, name string) error {
predeploy := predeploys.Predeploys[name]
if predeploy == nil {
return fmt.Errorf("unknown predeploy %s", name)
}
p := predeploy.Address
g := new(errgroup.Group)
// Check the predeploy specific config is correct
g.Go(func() error {
switch p {
case predeploys.LegacyMessagePasserAddr:
if err := checkLegacyMessagePasser(p, client); err != nil {
return fmt.Errorf("LegacyMessagePasser: %w", err)
}
case predeploys.DeployerWhitelistAddr:
if err := checkDeployerWhitelist(p, client); err != nil {
return fmt.Errorf("DeployerWhiteList: %w", err)
}
case predeploys.L2CrossDomainMessengerAddr:
if err := checkL2CrossDomainMessenger(p, client); err != nil {
return fmt.Errorf("L2CrossDomainMessenger: %w", err)
}
case predeploys.GasPriceOracleAddr:
if err := checkGasPriceOracle(p, client); err != nil {
return fmt.Errorf("GasPriceOracle: %w", err)
}
case predeploys.L2StandardBridgeAddr:
if err := checkL2StandardBridge(p, client); err != nil {
return fmt.Errorf("L2StandardBridge: %w", err)
}
case predeploys.SequencerFeeVaultAddr:
if err := checkSequencerFeeVault(p, client); err != nil {
return fmt.Errorf("SequencerFeeVault: %w", err)
}
case predeploys.OptimismMintableERC20FactoryAddr:
if err := checkOptimismMintableERC20Factory(p, client); err != nil {
return fmt.Errorf("OptimismMintableERC20Factory: %w", err)
}
case predeploys.L1BlockNumberAddr:
if err := checkL1BlockNumber(p, client); err != nil {
return fmt.Errorf("L1BlockNumber: %w", err)
}
case predeploys.L1BlockAddr:
if err := checkL1Block(p, client); err != nil {
return fmt.Errorf("L1Block: %w", err)
}
case predeploys.WETH9Addr:
if err := checkWETH9(p, client); err != nil {
return fmt.Errorf("WETH9: %w", err)
}
case predeploys.GovernanceTokenAddr:
if err := checkGovernanceToken(p, client); err != nil {
return fmt.Errorf("GovernanceToken: %w", err)
}
case predeploys.L2ERC721BridgeAddr:
if err := checkL2ERC721Bridge(p, client); err != nil {
return fmt.Errorf("L2ERC721Bridge: %w", err)
}
case predeploys.OptimismMintableERC721FactoryAddr:
if err := checkOptimismMintableERC721Factory(p, client); err != nil {
return fmt.Errorf("OptimismMintableERC721Factory: %w", err)
}
case predeploys.ProxyAdminAddr:
if err := checkProxyAdmin(p, client); err != nil {
return fmt.Errorf("ProxyAdmin: %w", err)
}
case predeploys.BaseFeeVaultAddr:
if err := checkBaseFeeVault(p, client); err != nil {
return fmt.Errorf("BaseFeeVault: %w", err)
}
case predeploys.L1FeeVaultAddr:
if err := checkL1FeeVault(p, client); err != nil {
return fmt.Errorf("L1FeeVault: %w", err)
}
case predeploys.L2ToL1MessagePasserAddr:
if err := checkL2ToL1MessagePasser(p, client); err != nil {
return fmt.Errorf("L2ToL1MessagePasser: %w", err)
}
case predeploys.SchemaRegistryAddr:
if err := checkSchemaRegistry(p, client); err != nil {
return fmt.Errorf("SchemaRegistry: %w", err)
}
case predeploys.EASAddr:
if err := checkEAS(p, client); err != nil {
return fmt.Errorf("EAS: %w", err)
}
case predeploys.Create2DeployerAddr:
bytecode, err := bindings.GetDeployedBytecode("Create2Deployer")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("Create2Deployer :%w", err)
}
case predeploys.MultiCall3Addr:
bytecode, err := bindings.GetDeployedBytecode("MultiCall3")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("MultiCall3 :%w", err)
}
case predeploys.Safe_v130Addr:
bytecode, err := bindings.GetDeployedBytecode("Safe_v130")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("Safe_v130 :%w", err)
}
case predeploys.SafeL2_v130Addr:
bytecode, err := bindings.GetDeployedBytecode("SafeL2_v130")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("SafeL2_v130 :%w", err)
}
case predeploys.MultiSendCallOnly_v130Addr:
bytecode, err := bindings.GetDeployedBytecode("MultiSendCallOnly_v130")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("MultiSendCallOnly_v130 :%w", err)
}
case predeploys.SafeSingletonFactoryAddr:
bytecode, err := bindings.GetDeployedBytecode("SafeSingletonFactory")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("SafeSingletonFactory :%w", err)
}
case predeploys.DeterministicDeploymentProxyAddr:
bytecode, err := bindings.GetDeployedBytecode("DeterministicDeploymentProxy")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("DeterministicDeploymentProxy :%w", err)
}
case predeploys.MultiSend_v130Addr:
bytecode, err := bindings.GetDeployedBytecode("MultiSend_v130")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("MultiSend_v130 :%w", err)
}
case predeploys.Permit2Addr:
const domainABI = `[{"inputs":[{"name":"typeHash","type":"bytes32"},{"name":"nameHash","type":"bytes32"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"name":"EIP712Domain","outputs":[],"stateMutability":"nonpayable","type":"constructor"}]`
parsedABI, err := abi.JSON(strings.NewReader(domainABI))
if err != nil {
return fmt.Errorf("Permit2 failed to parse ABI: %w", err)
}
typeHash := crypto.Keccak256Hash([]byte("EIP712Domain(string name,uint256 chainId,address verifyingContract)"))
nameHash := crypto.Keccak256Hash([]byte("Permit2"))
chainId, err := client.ChainID(context.Background())
if err != nil {
return fmt.Errorf("Permit2: %w", err)
}
data, err := parsedABI.Constructor.Inputs.Pack(typeHash, nameHash, chainId, predeploys.Predeploys["Permit2"].Address)
if err != nil {
return fmt.Errorf("Permit2: %w", err)
}
calculatedDomainSeparator := crypto.Keccak256Hash(data)
permit2Caller, err := bindings.NewPermit2Caller(predeploys.Predeploys["Permit2"].Address, client)
if err != nil {
return fmt.Errorf("Permit2: %w", err)
}
retrievedDomainSeparator, err := permit2Caller.DOMAINSEPARATOR(&bind.CallOpts{})
if err != nil {
return fmt.Errorf("Permit2: %w", err)
}
if [32]byte(calculatedDomainSeparator.Bytes()) != retrievedDomainSeparator {
return fmt.Errorf("Permit2: EIP-712 domain separators don't match")
}
case predeploys.SenderCreatorAddr:
bytecode, err := bindings.GetDeployedBytecode("SenderCreator")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("SenderCreator :%w", err)
}
case predeploys.EntryPointAddr:
bytecode, err := bindings.GetDeployedBytecode("EntryPoint")
if err != nil {
return err
}
if err := checkPredeployBytecode(p, client, bytecode); err != nil {
return fmt.Errorf("EntryPoint :%w", err)
}
}
return nil
})
if err := g.Wait(); err != nil {
return err
}
return nil
}
func checkL2ToL1MessagePasser(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewL2ToL1MessagePasser(addr, client)
if err != nil {
return err
}
messageVersion, err := contract.MESSAGEVERSION(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ToL1MessagePasser", "MESSAGE_VERSION", messageVersion)
messageNonce, err := contract.MessageNonce(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ToL1MessagePasser", "MESSAGE_NONCE", messageNonce)
return nil
}
func checkL1FeeVault(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewL1FeeVault(addr, client)
if err != nil {
return err
}
recipient, err := contract.RECIPIENT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1FeeVault", "RECIPIENT", recipient.Hex())
if recipient == (common.Address{}) {
return errors.New("RECIPIENT should not be address(0)")
}
minWithdrawalAmount, err := contract.MINWITHDRAWALAMOUNT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1FeeVault", "MIN_WITHDRAWAL_AMOUNT", minWithdrawalAmount)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1FeeVault version", "version", version)
return nil
}
func checkBaseFeeVault(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewBaseFeeVault(addr, client)
if err != nil {
return err
}
recipient, err := contract.RECIPIENT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("BaseFeeVault", "RECIPIENT", recipient.Hex())
if recipient == (common.Address{}) {
return errors.New("RECIPIENT should not be address(0)")
}
minWithdrawalAmount, err := contract.MINWITHDRAWALAMOUNT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("BaseFeeVault", "MIN_WITHDRAWAL_AMOUNT", minWithdrawalAmount)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("BaseFeeVault version", "version", version)
return nil
}
func checkProxyAdmin(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewProxyAdmin(addr, client)
if err != nil {
return err
}
owner, err := contract.Owner(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("ProxyAdmin", "owner", owner.Hex())
if owner == (common.Address{}) {
return errors.New("ProxyAdmin.owner is zero address")
}
addressManager, err := contract.AddressManager(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("ProxyAdmin", "addressManager", addressManager.Hex())
return nil
}
func checkOptimismMintableERC721Factory(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewOptimismMintableERC721Factory(addr, client)
if err != nil {
return err
}
bridge, err := contract.BRIDGE(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC721Factory", "BRIDGE", bridge.Hex())
if bridge == (common.Address{}) {
return errors.New("OptimismMintableERC721Factory.BRIDGE is zero address")
}
remoteChainID, err := contract.REMOTECHAINID(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC721Factory", "REMOTE_CHAIN_ID", remoteChainID)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC721Factory version", "version", version)
return nil
}
func checkL2ERC721Bridge(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewL2ERC721Bridge(addr, client)
if err != nil {
return err
}
messenger, err := contract.MESSENGER(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ERC721Bridge", "MESSENGER", messenger.Hex())
if messenger == (common.Address{}) {
return errors.New("L2ERC721Bridge.MESSENGER is zero address")
}
otherBridge, err := contract.OTHERBRIDGE(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ERC721Bridge", "OTHERBRIDGE", otherBridge.Hex())
if otherBridge == (common.Address{}) {
return errors.New("L2ERC721Bridge.OTHERBRIDGE is zero address")
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ERC721Bridge version", "version", version)
return nil
}
func checkGovernanceToken(addr common.Address, client *ethclient.Client) error {
code, err := client.CodeAt(context.Background(), addr, nil)
if err != nil {
return err
}
if len(code) > 0 {
// This should also check the owner
contract, err := bindings.NewERC20(addr, client)
if err != nil {
return err
}
name, err := contract.Name(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GovernanceToken", "name", name)
symbol, err := contract.Symbol(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GovernanceToken", "symbol", symbol)
totalSupply, err := contract.TotalSupply(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GovernanceToken", "totalSupply", totalSupply)
} else {
log.Info("No code at GovernanceToken")
}
return nil
}
func checkWETH9(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewWETH9(addr, client)
if err != nil {
return err
}
name, err := contract.Name(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("WETH9", "name", name)
if name != "Wrapped Ether" {
return fmt.Errorf("WETH9 name should be 'Wrapped Ether', got %s", name)
}
symbol, err := contract.Symbol(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("WETH9", "symbol", symbol)
if symbol != "WETH" {
return fmt.Errorf("WETH9 symbol should be 'WETH', got %s", symbol)
}
decimals, err := contract.Decimals(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("WETH9", "decimals", decimals)
if decimals != 18 {
return fmt.Errorf("WETH9 decimals should be 18, got %d", decimals)
}
return nil
}
func checkL1Block(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewL1Block(addr, client)
if err != nil {
return err
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1Block version", "version", version)
return nil
}
func checkL1BlockNumber(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewL1BlockNumber(addr, client)
if err != nil {
return err
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1BlockNumber version", "version", version)
return nil
}
func checkOptimismMintableERC20Factory(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewOptimismMintableERC20Factory(addr, client)
if err != nil {
return err
}
bridgeLegacy, err := contract.BRIDGE(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC20Factory", "BRIDGE", bridgeLegacy.Hex())
if bridgeLegacy == (common.Address{}) {
return errors.New("OptimismMintableERC20Factory.BRIDGE is zero address")
}
bridge, err := contract.Bridge(&bind.CallOpts{})
if err != nil {
return err
}
if bridge == (common.Address{}) {
return errors.New("OptimismMintableERC20Factory.bridge is zero address")
}
log.Info("OptimismMintableERC20Factory", "bridge", bridge.Hex())
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC20Factory version", "version", version)
return nil
}
func checkSequencerFeeVault(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewSequencerFeeVault(addr, client)
if err != nil {
return err
}
recipient, err := contract.RECIPIENT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SequencerFeeVault", "RECIPIENT", recipient.Hex())
if recipient == (common.Address{}) {
return errors.New("RECIPIENT should not be address(0)")
}
l1FeeWallet, err := contract.L1FeeWallet(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SequencerFeeVault", "l1FeeWallet", l1FeeWallet.Hex())
minWithdrawalAmount, err := contract.MINWITHDRAWALAMOUNT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SequencerFeeVault", "MIN_WITHDRAWAL_AMOUNT", minWithdrawalAmount)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SequencerFeeVault version", "version", version)
return nil
}
func checkL2StandardBridge(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewL2StandardBridge(addr, client)
if err != nil {
return err
}
otherBridge, err := contract.OTHERBRIDGE(&bind.CallOpts{})
if err != nil {
return err
}
if otherBridge == (common.Address{}) {
return errors.New("OTHERBRIDGE should not be address(0)")
}
log.Info("L2StandardBridge", "OTHERBRIDGE", otherBridge.Hex())
messenger, err := contract.MESSENGER(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2StandardBridge", "MESSENGER", messenger.Hex())
if messenger != predeploys.L2CrossDomainMessengerAddr {
return fmt.Errorf("L2StandardBridge MESSENGER should be %s, got %s", predeploys.L2CrossDomainMessengerAddr, messenger)
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2StandardBridge version", "version", version)
return nil
}
func checkGasPriceOracle(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewGasPriceOracle(addr, client)
if err != nil {
return err
}
decimals, err := contract.DECIMALS(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GasPriceOracle", "DECIMALS", decimals)
if decimals.Cmp(big.NewInt(6)) != 0 {
return fmt.Errorf("GasPriceOracle decimals should be 6, got %v", decimals)
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GasPriceOracle version", "version", version)
return nil
}
func checkL2CrossDomainMessenger(addr common.Address, client *ethclient.Client) error {
slot, err := client.StorageAt(context.Background(), addr, common.Hash{31: 0xcc}, nil)
if err != nil {
return err
}
if common.BytesToAddress(slot) != defaultCrossDomainMessageSender {
return fmt.Errorf("Expected xDomainMsgSender to be %s, got %s", defaultCrossDomainMessageSender, addr)
}
contract, err := bindings.NewL2CrossDomainMessenger(addr, client)
if err != nil {
return err
}
otherMessenger, err := contract.OTHERMESSENGER(&bind.CallOpts{})
if err != nil {
return err
}
if otherMessenger == (common.Address{}) {
return errors.New("OTHERMESSENGER should not be address(0)")
}
log.Info("L2CrossDomainMessenger", "OTHERMESSENGER", otherMessenger.Hex())
l1CrossDomainMessenger, err := contract.L1CrossDomainMessenger(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "l1CrossDomainMessenger", l1CrossDomainMessenger.Hex())
messageVersion, err := contract.MESSAGEVERSION(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "MESSAGE_VERSION", messageVersion)
minGasCallDataOverhead, err := contract.MINGASCALLDATAOVERHEAD(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "MIN_GAS_CALLDATA_OVERHEAD", minGasCallDataOverhead)
relayConstantOverhead, err := contract.RELAYCONSTANTOVERHEAD(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "RELAY_CONSTANT_OVERHEAD", relayConstantOverhead)
minGasDynamicsOverheadDenominator, err := contract.MINGASDYNAMICOVERHEADDENOMINATOR(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR", minGasDynamicsOverheadDenominator)
minGasDynamicsOverheadNumerator, err := contract.MINGASDYNAMICOVERHEADNUMERATOR(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR", minGasDynamicsOverheadNumerator)
relayCallOverhead, err := contract.RELAYCALLOVERHEAD(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "RELAY_CALL_OVERHEAD", relayCallOverhead)
relayReservedGas, err := contract.RELAYRESERVEDGAS(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "RELAY_RESERVED_GAS", relayReservedGas)
relayGasCheckBuffer, err := contract.RELAYGASCHECKBUFFER(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "RELAY_GAS_CHECK_BUFFER", relayGasCheckBuffer)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
initialized, err := getInitialized("L2CrossDomainMessenger", addr, client)
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "_initialized", initialized)
if initialized.Uint64() != 1 {
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
}
if err := checkAlreadyInitialized(addr, calldata, client); err != nil {
return err
}
initializing, err := getInitializing("L2CrossDomainMessenger", addr, client)
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "_initializing", initializing)
log.Info("L2CrossDomainMessenger version", "version", version)
return nil
}
func checkLegacyMessagePasser(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewLegacyMessagePasser(addr, client)
if err != nil {
return err
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("LegacyMessagePasser version", "version", version)
return nil
}
func checkDeployerWhitelist(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewDeployerWhitelist(addr, client)
if err != nil {
return err
}
owner, err := contract.Owner(&bind.CallOpts{})
if err != nil {
return err
}
if owner != (common.Address{}) {
return fmt.Errorf("DeployerWhitelist owner should be set to address(0)")
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("DeployerWhitelist version", "version", version)
return nil
}
func checkSchemaRegistry(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewSchemaRegistry(addr, client)
if err != nil {
return err
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SchemaRegistry version", "version", version)
return nil
}
func checkEAS(addr common.Address, client *ethclient.Client) error {
contract, err := bindings.NewEAS(addr, client)
if err != nil {
return err
}
registry, err := contract.GetSchemaRegistry(&bind.CallOpts{})
if err != nil {
return err
}
if registry != predeploys.SchemaRegistryAddr {
return fmt.Errorf("Incorrect registry address %s", registry)
}
log.Info("EAS", "registry", registry)
name, err := contract.GetName(&bind.CallOpts{})
if err != nil {
return err
}
if name != "EAS" {
return fmt.Errorf("Incorrect name %s", name)
}
log.Info("EAS", "name", name)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("EAS version", "version", version)
return nil
}
func checkPredeployBytecode(addr common.Address, client *ethclient.Client, expectedBytecode []byte) error {
code, err := client.CodeAt(context.Background(), addr, nil)
if err != nil {
return err
}
if !bytes.Equal(code, expectedBytecode) {
return fmt.Errorf("deployed bytecode at %s, doesn't match expected", addr)
}
return nil
}
// getInitialized will get the initialized value in storage of a contract.
// This is an incrementing number that starts at 1 and increments each time that
// the contract is upgraded.
func getInitialized(name string, addr common.Address, client *ethclient.Client) (*big.Int, error) {
value, err := getStorageValue(name, "_initialized", addr, client)
if err != nil {
return nil, err
}
return new(big.Int).SetBytes(value), nil
}
// getInitializing will get the _initializing value in storage of a contract.
func getInitializing(name string, addr common.Address, client *ethclient.Client) (bool, error) {
value, err := getStorageValue(name, "_initializing", addr, client)
if err != nil {
return false, err
}
if len(value) != 1 {
return false, fmt.Errorf("Unexpected length for _initializing: %d", len(value))
}
return value[0] == 1, nil
}
// getStorageValue will get the value of a named storage slot in a contract. It isn't smart about
// automatically converting from a byte slice to a type, it is the caller's responsibility to do that.
func getStorageValue(name, entryName string, addr common.Address, client *ethclient.Client) ([]byte, error) {
layout, err := bindings.GetStorageLayout(name)
if err != nil {
return nil, err
}
entry, err := layout.GetStorageLayoutEntry(entryName)
if err != nil {
return nil, err
}
typ, err := layout.GetStorageLayoutType(entry.Type)
if err != nil {
return nil, err
}
slot := common.BigToHash(big.NewInt(int64(entry.Slot)))
value, err := client.StorageAt(context.Background(), addr, slot, nil)
if err != nil {
return nil, err
}
if entry.Offset+typ.NumberOfBytes > uint(len(value)) {
return nil, fmt.Errorf("value length is too short")
}
// Swap the endianness
slice := common.CopyBytes(value)
for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
slice[i], slice[j] = slice[j], slice[i]
}
return slice[entry.Offset : entry.Offset+typ.NumberOfBytes], nil
}
// checkAlreadyInitialized will check if a contract has already been initialized
// based on error message string matching.
func checkAlreadyInitialized(addr common.Address, calldata []byte, client *ethclient.Client) error {
msg := ethereum.CallMsg{
To: &addr,
Data: calldata,
}
if _, err := client.CallContract(context.Background(), msg, nil); err != nil && !strings.Contains(err.Error(), errAlreadyInitialized.Error()) {
return err
}
return 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