Skip to content

contracts-bedrock: cleanup predeploys solidity test #8933

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

Merged
merged 3 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
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