Skip to content

Commit

Permalink
Add deployed bytecode retrieval mitigation
Browse files Browse the repository at this point in the history
  • Loading branch information
spacesailor24 committed Nov 27, 2023
1 parent 5441f06 commit 6e9ff00
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 6 deletions.
10 changes: 8 additions & 2 deletions op-bindings/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -37,7 +39,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

Expand All @@ -63,7 +67,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)
Expand Down
3 changes: 3 additions & 0 deletions op-bindings/bindgen/generator_remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import (
"os"

"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/ethclient"
)

type bindGenGeneratorRemote struct {
bindGenGeneratorBase
etherscanApiKeyEth string
etherscanApiKeyOp string
contractDataClient
rpcClientEth *ethclient.Client
rpcClientOp *ethclient.Client
tempArtifactsDir string
}

Expand Down
34 changes: 30 additions & 4 deletions op-bindings/bindgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum/go-ethereum/ethclient"
gethLog "github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)
Expand Down Expand Up @@ -86,14 +87,18 @@ func setupLogger(c *cli.Context) (gethLog.Logger, error) {
func generateBindings(c *cli.Context) error {
logger, _ := setupLogger(c)

var err error
switch c.Command.Name {
case "all":
localBindingsGenerator := parseConfigLocal(logger, c)
if err := localBindingsGenerator.generateBindings(); err != nil {
gethLog.Crit("Error generating local bindings", "error", err.Error())
}

remoteBindingsGenerator := parseConfigRemote(logger, c)
var remoteBindingsGenerator bindGenGeneratorRemote
if remoteBindingsGenerator, err = parseConfigRemote(logger, c); err != nil {
gethLog.Crit("Error parsing remote config", "error", err.Error())
}
if err := remoteBindingsGenerator.generateBindings(); err != nil {
gethLog.Crit("Error generating remote bindings", "error", err.Error())
}
Expand All @@ -106,7 +111,10 @@ func generateBindings(c *cli.Context) error {
}
return nil
case "remote":
remoteBindingsGenerator := parseConfigRemote(logger, c)
var remoteBindingsGenerator bindGenGeneratorRemote
if remoteBindingsGenerator, err = parseConfigRemote(logger, c); err != nil {
gethLog.Crit("Error parsing remote config", "error", err.Error())
}
if err := remoteBindingsGenerator.generateBindings(); err != nil {
gethLog.Crit("Error generating remote bindings", "error", err.Error())
}
Expand Down Expand Up @@ -135,15 +143,23 @@ func parseConfigLocal(logger gethLog.Logger, c *cli.Context) bindGenGeneratorLoc
}
}

func parseConfigRemote(logger gethLog.Logger, c *cli.Context) bindGenGeneratorRemote {
func parseConfigRemote(logger gethLog.Logger, c *cli.Context) (bindGenGeneratorRemote, error) {
baseConfig := parseConfigBase(logger, c)
generator := bindGenGeneratorRemote{
bindGenGeneratorBase: baseConfig,
etherscanApiKeyEth: c.String(EtherscanApiKeyEthFlagName),
etherscanApiKeyOp: c.String(EtherscanApiKeyOpFlagName),
}
generator.contractDataClient = etherscan.NewClient(generator.etherscanApiKeyEth, generator.etherscanApiKeyOp)
return generator

var err error
if generator.rpcClientEth, err = ethclient.Dial(c.String(RpcUrlEthFlagName)); err != nil {
return bindGenGeneratorRemote{}, fmt.Errorf("error initializing Ethereum client: %w", err)
}
if generator.rpcClientOp, err = ethclient.Dial(c.String(RpcUrlOpFlagName)); err != nil {
return bindGenGeneratorRemote{}, fmt.Errorf("error initializing Optimism client: %w", err)
}
return generator, nil
}

func baseFlags() []cli.Flag {
Expand Down Expand Up @@ -199,5 +215,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,
},
}
}
55 changes: 55 additions & 0 deletions op-bindings/bindgen/remote_handlers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"
"os"
"path/filepath"
Expand All @@ -9,6 +10,7 @@ import (
"text/template"

"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/common"
)

type contractData struct {
Expand All @@ -24,6 +26,9 @@ func (generator *bindGenGeneratorRemote) standardHandler(contractMetadata *remot
}

contractMetadata.DeployedBin = fetchedData.deployedBin
if err = generator.compareDeployedBytecodeWithRpcs(contractMetadata); err != nil {
return err
}

// If ABI was explicitly provided by config, don't overwrite
if contractMetadata.Abi == "" {
Expand Down Expand Up @@ -57,6 +62,9 @@ func (generator *bindGenGeneratorRemote) multiSendHandler(contractMetadata *remo

contractMetadata.Abi = fetchedData.abi
contractMetadata.DeployedBin = fetchedData.deployedBin
if err = generator.compareDeployedBytecodeWithRpcs(contractMetadata); err != nil {
return err
}
if contractMetadata.InitBin, err = generator.removeDeploymentSalt(fetchedData.deploymentTx.Input, contractMetadata.DeploymentSalt); err != nil {
return err
}
Expand All @@ -70,6 +78,9 @@ func (generator *bindGenGeneratorRemote) senderCreatorHandler(contractMetadata *
if err != nil {
return fmt.Errorf("error fetching deployed bytecode: %w", err)
}
if err = generator.compareDeployedBytecodeWithRpcs(contractMetadata); err != nil {
return err
}

if err := generator.compareBytecodeWithOp(contractMetadata, false, true); err != nil {
return fmt.Errorf("error comparing contract bytecode for %s: %w", contractMetadata.Name, err)
Expand Down Expand Up @@ -185,6 +196,50 @@ func (generator *bindGenGeneratorRemote) compareBytecodeWithOp(contractMetadataE
return nil
}

func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithRpcs(contractMetadata *remoteContractMetadata) error {
if contractMetadata.Deployments["eth"] != "" {
bytecodeEth, err := generator.rpcClientEth.CodeAt(context.Background(), common.HexToAddress(contractMetadata.Deployments["eth"]), nil)
if err != nil {
generator.logger.Crit(
"Error getting deployed bytecode from Ethereum RPC",
"err", err,
)
}
bytecodeEthHex := common.Bytes2Hex(bytecodeEth)
if !strings.EqualFold(strings.TrimPrefix(contractMetadata.DeployedBin, "0x"), bytecodeEthHex) {
generator.logger.Crit(
"Deployment bytecode from Ethereum RPC doesn't match bytecode from Etherscan",
"rpcBytecode", bytecodeEthHex,
"etherscanBytecode", contractMetadata.DeployedBin,
)
}
} else {
generator.logger.Warn("Unable to compare bytecode from Etherscan against Ethereum RPC client, no deployment address provided")
}

if contractMetadata.Deployments["op"] != "" {
bytecodeOp, err := generator.rpcClientOp.CodeAt(context.Background(), common.HexToAddress(contractMetadata.Deployments["op"]), nil)
if err != nil {
generator.logger.Crit(
"Error getting deployed bytecode from Optimism RPC",
"err", err,
)
}
bytecodeOpHex := common.Bytes2Hex(bytecodeOp)
if !strings.EqualFold(strings.TrimPrefix(contractMetadata.DeployedBin, "0x"), bytecodeOpHex) {
generator.logger.Crit(
"Deployment bytecode from Optimism RPC doesn't match bytecode from Etherscan",
"rpcBytecode", bytecodeOpHex,
"etherscanBytecode", contractMetadata.DeployedBin,
)
}
} else {
generator.logger.Warn("Unable to compare bytecode from Etherscan against Optimism RPC client, no deployment address provided")
}

return nil
}

func (generator *bindGenGeneratorRemote) writeAllOutputs(contractMetadata *remoteContractMetadata, fileTemplate string) error {
abiFilePath, bytecodeFilePath, err := writeContractArtifacts(
generator.logger, generator.tempArtifactsDir, contractMetadata.Name,
Expand Down

0 comments on commit 6e9ff00

Please sign in to comment.