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 Dec 14, 2023
1 parent 387d992 commit 63c78f5
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 2 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 @@ -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

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

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

type bindGenGeneratorRemote struct {
bindGenGeneratorBase
contractDataClients map[string]contractDataClient
rpcClients map[string]*ethclient.Client
tempArtifactsDir string
}

Expand Down
19 changes: 19 additions & 0 deletions op-bindings/bindgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -171,6 +172,14 @@ func parseConfigRemote(logger log.Logger, c *cli.Context) (bindGenGeneratorRemot
generator.contractDataClients = make(map[string]contractDataClient)
generator.contractDataClients["eth"] = etherscan.NewEthereumClient(c.String(EtherscanApiKeyEthFlagName))
generator.contractDataClients["op"] = etherscan.NewOptimismClient(c.String(EtherscanApiKeyOpFlagName))

generator.rpcClients = make(map[string]*ethclient.Client)
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
}

Expand Down Expand Up @@ -222,5 +231,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,
},
}
}
50 changes: 50 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,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 == "" {
Expand Down Expand Up @@ -61,6 +69,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
}
Expand All @@ -74,6 +88,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
}

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 @@ -195,6 +215,36 @@ func (generator *bindGenGeneratorRemote) compareBytecodeWithOp(contractMetadataE
return nil
}

func (generator *bindGenGeneratorRemote) compareDeployedBytecodeWithRpc(contractMetadata *remoteContractMetadata, chain string) error {
client, ok := generator.rpcClients[chain]
if !ok {
generator.logger.Crit("unknown chain, unable to retrieve a RPC client", "chain", chain)
}

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

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 63c78f5

Please sign in to comment.