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

contracts-bedrock: cleanup predeploys solidity test (#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
https://github.com/ethereum-optimism/optimism/pull/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
parent 67e8b982
......@@ -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"
......@@ -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 {
......@@ -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]
......@@ -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 {
......@@ -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.
......
......@@ -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 {
......@@ -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");
}
}
......
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