Skip to content
This repository has been archived by the owner on Jan 7, 2025. It is now read-only.

Commit

Permalink
contracts-bedrock: cleanup predeploys solidity test (ethereum-optimis…
Browse files Browse the repository at this point in the history
…m#8933)

* contracts-bedrock: cleanup predeploys solidity test

Contributors to the smart contracts have way too many steps
to get their PR over the line. This migrates some of the `check-l2`
script to solidity. I believe that we can fully delete `check-l2`
but want to follow up in an additional PR to ensure that we have the
same functionality. Completely deleting `check-l2` was unblocked by
ethereum-optimism#8911.

The functionality that is added to the solidity here was removed from
the `check-l2` script.

* op-chain-ops: remove dead code

* op-chain-ops: fix build issue
  • Loading branch information
tynes authored Jan 11, 2024
1 parent 67e8b98 commit a1e846d
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 111 deletions.
103 changes: 0 additions & 103 deletions op-chain-ops/cmd/check-l2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"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-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
Expand Down Expand Up @@ -76,29 +75,6 @@ func entrypoint(ctx *cli.Context) error {
}

log.Info("Checking predeploy proxy config")
g := new(errgroup.Group)

// Check that all proxies are configured correctly
// Do this in parallel but not too quickly to allow for
// querying against rate limiting RPC backends
count := uint64(2048)
for i := uint64(0); i < count; i++ {
i := i
if i%4 == 0 {
log.Info("Checking proxy", "index", i, "total", count)
if err := g.Wait(); err != nil {
return err
}
}
g.Go(func() error {
return checkPredeploy(clients.L2Client, i)
})
}

if err := g.Wait(); err != nil {
return err
}
log.Info("All predeploy proxies are set correctly")

// Check that all of the defined predeploys are set up correctly
for name, pre := range predeploys.Predeploys {
Expand All @@ -110,23 +86,6 @@ func entrypoint(ctx *cli.Context) error {
return nil
}

// checkPredeploy ensures that the predeploy at index i has the correct proxy admin set
func checkPredeploy(client *ethclient.Client, i uint64) error {
bigAddr := new(big.Int).Or(genesis.BigL2PredeployNamespace, new(big.Int).SetUint64(i))
addr := common.BigToAddress(bigAddr)
if pre, ok := predeploys.PredeploysByAddress[addr]; ok && pre.ProxyDisabled {
return nil
}
admin, err := getEIP1967AdminAddress(client, addr)
if err != nil {
return err
}
if admin != predeploys.ProxyAdminAddr {
return fmt.Errorf("%s does not have correct proxy admin set", addr)
}
return nil
}

// checkPredeployConfig checks that the defined predeploys are configured correctly
func checkPredeployConfig(client *ethclient.Client, name string) error {
predeploy := predeploys.Predeploys[name]
Expand All @@ -136,50 +95,6 @@ func checkPredeployConfig(client *ethclient.Client, name string) error {
p := predeploy.Address

g := new(errgroup.Group)
if !predeploy.ProxyDisabled {
// Check that an implementation is set. If the implementation has been upgraded,
// it will be considered non-standard. Ensure that there is code set at the implementation.
g.Go(func() error {
impl, err := getEIP1967ImplementationAddress(client, p)
if err != nil {
return err
}
log.Info(name, "implementation", impl.Hex())
standardImpl, err := genesis.AddressToCodeNamespace(p)
if err != nil {
return err
}
if impl != standardImpl {
log.Warn(name + " does not have the standard implementation")
}
implCode, err := client.CodeAt(context.Background(), impl, nil)
if err != nil {
return err
}
if len(implCode) == 0 {
return fmt.Errorf("%s implementation is not deployed", name)
}
return nil
})

// 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 {
proxyCode, err := client.CodeAt(context.Background(), p, nil)
if err != nil {
return err
}
proxy, err := bindings.GetDeployedBytecode("Proxy")
if err != nil {
return err
}
if !bytes.Equal(proxyCode, proxy) {
return fmt.Errorf("%s does not have the standard proxy code", name)
}
return nil
})
}

// Check the predeploy specific config is correct
g.Go(func() error {
Expand Down Expand Up @@ -981,24 +896,6 @@ func checkPredeployBytecode(addr common.Address, client *ethclient.Client, expec
return nil
}

func getEIP1967AdminAddress(client *ethclient.Client, addr common.Address) (common.Address, error) {
slot, err := client.StorageAt(context.Background(), addr, genesis.AdminSlot, nil)
if err != nil {
return common.Address{}, err
}
admin := common.BytesToAddress(slot)
return admin, nil
}

func getEIP1967ImplementationAddress(client *ethclient.Client, addr common.Address) (common.Address, error) {
slot, err := client.StorageAt(context.Background(), addr, genesis.ImplementationSlot, nil)
if err != nil {
return common.Address{}, err
}
impl := common.BytesToAddress(slot)
return impl, 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.
Expand Down
58 changes: 50 additions & 8 deletions packages/contracts-bedrock/test/Predeploys.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,38 @@ import { CommonTest } from "test/setup/CommonTest.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";

/// @title PredeploysTest
contract PredeploysTest is CommonTest {
/// @dev Function to compute the expected address of the predeploy implementation
/// in the genesis state.
function _predeployToCodeNamespace(address _addr) internal pure returns (address) {
return address(
uint160(uint256(uint160(_addr)) & 0xffff | uint256(uint160(0xc0D3C0d3C0d3C0D3c0d3C0d3c0D3C0d3c0d30000)))
);
}

/// @dev Returns true if the address is a predeploy.
function _isPredeploy(address _addr) internal pure returns (bool) {
return _addr == Predeploys.L2_TO_L1_MESSAGE_PASSER || _addr == Predeploys.L2_CROSS_DOMAIN_MESSENGER
|| _addr == Predeploys.L2_STANDARD_BRIDGE || _addr == Predeploys.L2_ERC721_BRIDGE
|| _addr == Predeploys.SEQUENCER_FEE_WALLET || _addr == Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY
|| _addr == Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == Predeploys.L1_BLOCK_ATTRIBUTES
|| _addr == Predeploys.GAS_PRICE_ORACLE || _addr == Predeploys.DEPLOYER_WHITELIST || _addr == Predeploys.WETH9
|| _addr == Predeploys.L1_BLOCK_NUMBER || _addr == Predeploys.LEGACY_MESSAGE_PASSER
|| _addr == Predeploys.PROXY_ADMIN || _addr == Predeploys.BASE_FEE_VAULT || _addr == Predeploys.L1_FEE_VAULT
|| _addr == Predeploys.GOVERNANCE_TOKEN || _addr == Predeploys.SCHEMA_REGISTRY || _addr == Predeploys.EAS;
}

/// @dev Returns true if the adress is not proxied.
function _notProxied(address _addr) internal pure returns (bool) {
return _addr == Predeploys.LEGACY_ERC20_ETH || _addr == Predeploys.GOVERNANCE_TOKEN || _addr == Predeploys.WETH9
|| _addr == Predeploys.MultiCall3 || _addr == Predeploys.Create2Deployer || _addr == Predeploys.Safe_v130
|| _addr == Predeploys.SafeL2_v130 || _addr == Predeploys.MultiSendCallOnly_v130
|| _addr == Predeploys.SafeSingletonFactory || _addr == Predeploys.DeterministicDeploymentProxy
|| _addr == Predeploys.MultiSend_v130 || _addr == Predeploys.Permit2 || _addr == Predeploys.SenderCreator
|| _addr == Predeploys.EntryPoint;
}

/// @dev Tests that the predeploy addresses are set correctly. They have code
/// and the proxied accounts have the correct admin.
function test_predeploysSet_succeeds() external {
Expand All @@ -15,17 +46,28 @@ contract PredeploysTest is CommonTest {
address addr = address(prefix | uint160(i));
bytes memory code = addr.code;
assertTrue(code.length > 0);

bool proxied = _notProxied(addr) == false;
bool isPredeploy = _isPredeploy(addr);

// Skip the accounts that do not have a proxy
if (
addr == Predeploys.LEGACY_ERC20_ETH || addr == Predeploys.GOVERNANCE_TOKEN || addr == Predeploys.WETH9
|| addr == Predeploys.MultiCall3 || addr == Predeploys.Create2Deployer || addr == Predeploys.Safe_v130
|| addr == Predeploys.SafeL2_v130 || addr == Predeploys.MultiSendCallOnly_v130
|| addr == Predeploys.SafeSingletonFactory || addr == Predeploys.DeterministicDeploymentProxy
|| addr == Predeploys.MultiSend_v130 || addr == Predeploys.Permit2 || addr == Predeploys.SenderCreator
|| addr == Predeploys.EntryPoint
) {
if (proxied == false) {
continue;
}

// Only the defined predeploys have their implementation slot set
if (proxied && isPredeploy) {
assertEq(
EIP1967Helper.getImplementation(addr),
_predeployToCodeNamespace(addr),
string.concat("Implementation mismatch for ", vm.toString(addr))
);
}

// The code is a proxy
assertEq(code, vm.getDeployedCode("Proxy.sol"));

// All of the defined predeploys have their admin set to the proxy admin
assertEq(EIP1967Helper.getAdmin(addr), Predeploys.PROXY_ADMIN, "Admin mismatch");
}
}
Expand Down

0 comments on commit a1e846d

Please sign in to comment.