Commit 4abef208 authored by Wyatt Barnes's avatar Wyatt Barnes Committed by GitHub

Add deployed bytecode retrieval mitigation (#8282)

parent 6d78aa09
......@@ -7,6 +7,8 @@ contracts-list := ./artifacts.json
log-level := info
ETHERSCAN_APIKEY_ETH ?=
ETHERSCAN_APIKEY_OP ?=
RPC_URL_ETH ?=
RPC_URL_OP ?=
all: version mkdir bindings
......@@ -36,7 +38,9 @@ bindgen-generate-all:
--source-maps-list MIPS,PreimageOracle \
--forge-artifacts $(contracts-dir)/forge-artifacts \
--etherscan.apikey.eth $(ETHERSCAN_APIKEY_ETH) \
--etherscan.apikey.op $(ETHERSCAN_APIKEY_OP)
--etherscan.apikey.op $(ETHERSCAN_APIKEY_OP) \
--rpc.url.eth $(RPC_URL_ETH) \
--rpc.url.op $(RPC_URL_OP)
bindgen-local: compile bindgen-generate-local
......@@ -60,7 +64,9 @@ bindgen-remote:
--log.level $(log-level) \
remote \
--etherscan.apikey.eth $(ETHERSCAN_APIKEY_ETH) \
--etherscan.apikey.op $(ETHERSCAN_APIKEY_OP)
--etherscan.apikey.op $(ETHERSCAN_APIKEY_OP) \
--rpc.url.eth $(RPC_URL_ETH) \
--rpc.url.op $(RPC_URL_OP)
mkdir:
mkdir -p $(pkg)
......
......@@ -7,6 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
type bindGenGeneratorRemote struct {
......@@ -15,6 +16,10 @@ type bindGenGeneratorRemote struct {
eth contractDataClient
op contractDataClient
}
rpcClients struct {
eth *ethclient.Client
op *ethclient.Client
}
tempArtifactsDir string
}
......
......@@ -7,6 +7,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum-optimism/optimism/op-e2e/config"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)
......@@ -170,6 +171,13 @@ func parseConfigRemote(logger log.Logger, c *cli.Context) (bindGenGeneratorRemot
generator.contractDataClients.eth = etherscan.NewEthereumClient(c.String(EtherscanApiKeyEthFlagName))
generator.contractDataClients.op = etherscan.NewOptimismClient(c.String(EtherscanApiKeyOpFlagName))
if generator.rpcClients.eth, err = ethclient.Dial(c.String(RpcUrlEthFlagName)); err != nil {
return bindGenGeneratorRemote{}, fmt.Errorf("error initializing Ethereum client: %w", err)
}
if generator.rpcClients.op, err = ethclient.Dial(c.String(RpcUrlOpFlagName)); err != nil {
return bindGenGeneratorRemote{}, fmt.Errorf("error initializing Optimism client: %w", err)
}
return generator, nil
}
......@@ -221,5 +229,15 @@ func remoteFlags() []cli.Flag {
Usage: "API key to make queries to Etherscan for Optimism",
Required: true,
},
&cli.StringFlag{
Name: RpcUrlEthFlagName,
Usage: "RPC URL (with API key if required) to query Ethereum",
Required: true,
},
&cli.StringFlag{
Name: RpcUrlOpFlagName,
Usage: "RPC URL (with API key if required) to query Optimism",
Required: true,
},
}
}
......@@ -10,6 +10,8 @@ import (
"text/template"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
type contractData struct {
......@@ -25,6 +27,12 @@ func (generator *bindGenGeneratorRemote) standardHandler(contractMetadata *remot
}
contractMetadata.DeployedBin = fetchedData.deployedBin
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "eth"); err != nil {
return err
}
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil {
return err
}
// If ABI was explicitly provided by config, don't overwrite
if contractMetadata.ABI == "" {
......@@ -76,6 +84,12 @@ func (generator *bindGenGeneratorRemote) multiSendHandler(contractMetadata *remo
contractMetadata.ABI = fetchedData.abi
contractMetadata.DeployedBin = fetchedData.deployedBin
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "eth"); err != nil {
return err
}
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil {
return err
}
if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.deploymentTx.Input, contractMetadata.DeploymentSalt); err != nil {
return err
}
......@@ -89,6 +103,12 @@ func (generator *bindGenGeneratorRemote) senderCreatorHandler(contractMetadata *
if err != nil {
return fmt.Errorf("error fetching deployed bytecode: %w", err)
}
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "eth"); err != nil {
return err
}
if err = generator.compareDeployedBytecodeWithRpc(contractMetadata, "op"); err != nil {
return err
}
// The SenderCreator contract is deployed by EntryPoint, so the transaction data
// from the deployment transaction is for the entire EntryPoint deployment.
......@@ -221,6 +241,41 @@ func (generator *bindGenGeneratorRemote) compareBytecodeWithOp(contractMetadataE
return nil
}
func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithRpc(contractMetadata *remoteContractMetadata, chain string) error {
var client *ethclient.Client
switch chain {
case "eth":
client = generator.rpcClients.eth
case "op":
client = generator.rpcClients.op
default:
return fmt.Errorf("unknown chain: %s, unable to retrieve a RPC client", chain)
}
var deployment common.Address
switch chain {
case "eth":
deployment = contractMetadata.Deployments.Eth
case "op":
deployment = contractMetadata.Deployments.Op
default:
generator.logger.Warn("Unable to compare bytecode from Etherscan against RPC client, no deployment address provided for chain", "chain", chain)
}
if deployment != (common.Address{}) {
bytecode, err := client.CodeAt(context.Background(), common.HexToAddress(deployment.Hex()), nil)
if err != nil {
return fmt.Errorf("error getting deployed bytecode from RPC on chain: %s err: %w", chain, err)
}
bytecodeHex := common.Bytes2Hex(bytecode)
if !strings.EqualFold(strings.TrimPrefix(contractMetadata.DeployedBin, "0x"), bytecodeHex) {
return fmt.Errorf("%s deployment bytecode from RPC doesn't match bytecode from Etherscan. rpcBytecode: %s etherscanBytecode: %s", contractMetadata.Name, bytecodeHex, contractMetadata.DeployedBin)
}
}
return nil
}
func (generator *bindGenGeneratorRemote) writeAllOutputs(contractMetadata *remoteContractMetadata, fileTemplate string) error {
abiFilePath, bytecodeFilePath, err := writeContractArtifacts(
generator.logger, generator.tempArtifactsDir, contractMetadata.Name,
......
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