Commit 9d13ae01 authored by Wyatt Barnes's avatar Wyatt Barnes Committed by GitHub

Refactor BindGen E2E tests (#8741)

parent 6c23fbee
...@@ -524,16 +524,16 @@ jobs: ...@@ -524,16 +524,16 @@ jobs:
working_directory: op-bindings working_directory: op-bindings
- notify-failures-on-develop - notify-failures-on-develop
bindgen-test: bindgen-test-e2e:
docker: docker:
- image: <<pipeline.parameters.ci_builder_image>> - image: <<pipeline.parameters.ci_builder_image>>
resource_class: xlarge resource_class: xlarge
steps: steps:
- checkout - checkout
- run: - run:
name: bindgen test name: bindgen test E2E
command: make test-bindgen-e2e command: make test-bindgen-e2e
working_directory: op-bindings working_directory: op-bindings-e2e
- notify-failures-on-develop - notify-failures-on-develop
js-lint-test: js-lint-test:
...@@ -2012,7 +2012,7 @@ workflows: ...@@ -2012,7 +2012,7 @@ workflows:
context: context:
- slack - slack
- oplabs-etherscan - oplabs-etherscan
- bindgen-test: - bindgen-test-e2e:
context: context:
- slack - slack
- oplabs-etherscan - oplabs-etherscan
test-bindgen-e2e:
go test ./... -count=1
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
package bindgen
import (
"fmt"
"os"
"reflect"
"strings"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindgen"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/ethclient"
)
var generator bindgen.BindGenGeneratorRemote = bindgen.BindGenGeneratorRemote{}
func configureGenerator(t *testing.T) error {
generator.ContractDataClients.Eth = etherscan.NewEthereumClient(os.Getenv("ETHERSCAN_APIKEY_ETH"))
generator.ContractDataClients.Op = etherscan.NewOptimismClient(os.Getenv("ETHERSCAN_APIKEY_OP"))
var err error
if generator.RpcClients.Eth, err = ethclient.Dial(os.Getenv("RPC_URL_ETH")); err != nil {
return fmt.Errorf("error initializing Ethereum client: %w", err)
}
if generator.RpcClients.Op, err = ethclient.Dial(os.Getenv("RPC_URL_OP")); err != nil {
return fmt.Errorf("error initializing Optimism client: %w", err)
}
return nil
}
func TestFetchContractData(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range fetchContractDataTests {
t.Run(tt.name, func(t *testing.T) {
contractData, err := generator.FetchContractData(tt.contractVerified, tt.chain, tt.deploymentAddress)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(contractData, tt.expectedContractData) {
t.Errorf("Retrieved contract data doesn't match expected. Expected: %s Retrieved: %s", tt.expectedContractData, contractData)
}
})
}
}
func TestFetchContractDataFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range fetchContractDataTestsFailures {
t.Run(tt.name, func(t *testing.T) {
_, err := generator.FetchContractData(tt.contractVerified, tt.chain, tt.deploymentAddress)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareInitBytecodeWithOp(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareInitBytecodeWithOpTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareInitBytecodeWithOp(&tt.contractMetadataEth, tt.initCodeShouldMatch)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareInitBytecodeWithOpFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareInitBytecodeWithOpTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareInitBytecodeWithOp(&tt.contractMetadataEth, tt.initCodeShouldMatch)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareDeployedBytecodeWithOp(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithOpTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareDeployedBytecodeWithOp(&tt.contractMetadataEth, tt.deployedCodeShouldMatch)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareDeployedBytecodeWithOpFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithOpTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareDeployedBytecodeWithOp(&tt.contractMetadataEth, tt.deployedCodeShouldMatch)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareDeployedBytecodeWithRpc(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithRpcTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareDeployedBytecodeWithRpc(&tt.contractMetadataEth, tt.chain)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareDeployedBytecodeWithRpcFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithRpcTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.CompareDeployedBytecodeWithRpc(&tt.contractMetadataEth, tt.chain)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
...@@ -28,7 +28,7 @@ bindings-build: bindgen-generate-local ...@@ -28,7 +28,7 @@ bindings-build: bindgen-generate-local
bindgen: compile bindgen-generate-all bindgen: compile bindgen-generate-all
bindgen-generate-all: bindgen-generate-all:
go run ./bindgen/ \ go run ./cmd/ \
generate \ generate \
--metadata-out ./$(pkg) \ --metadata-out ./$(pkg) \
--bindings-package $(pkg) \ --bindings-package $(pkg) \
...@@ -45,7 +45,7 @@ bindgen-generate-all: ...@@ -45,7 +45,7 @@ bindgen-generate-all:
bindgen-local: compile bindgen-generate-local bindgen-local: compile bindgen-generate-local
bindgen-generate-local: bindgen-generate-local:
go run ./bindgen/ \ go run ./cmd/ \
generate \ generate \
--metadata-out ./$(pkg) \ --metadata-out ./$(pkg) \
--bindings-package $(pkg) \ --bindings-package $(pkg) \
...@@ -56,7 +56,7 @@ bindgen-generate-local: ...@@ -56,7 +56,7 @@ bindgen-generate-local:
--forge-artifacts $(contracts-dir)/forge-artifacts --forge-artifacts $(contracts-dir)/forge-artifacts
bindgen-remote: bindgen-remote:
go run ./bindgen/ \ go run ./cmd/ \
generate \ generate \
--metadata-out ./$(pkg) \ --metadata-out ./$(pkg) \
--bindings-package $(pkg) \ --bindings-package $(pkg) \
...@@ -80,6 +80,3 @@ clean: ...@@ -80,6 +80,3 @@ clean:
test: test:
go test ./... go test ./...
test-bindgen-e2e:
RUN_E2E=true go test -count=1 ./bindgen/...
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
package main package bindgen
import ( import (
"encoding/json" "encoding/json"
...@@ -15,10 +15,10 @@ import ( ...@@ -15,10 +15,10 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/foundry" "github.com/ethereum-optimism/optimism/op-bindings/foundry"
) )
type bindGenGeneratorLocal struct { type BindGenGeneratorLocal struct {
bindGenGeneratorBase BindGenGeneratorBase
sourceMapsList string SourceMapsList string
forgeArtifactsPath string ForgeArtifactsPath string
} }
type localContractMetadata struct { type localContractMetadata struct {
...@@ -30,33 +30,33 @@ type localContractMetadata struct { ...@@ -30,33 +30,33 @@ type localContractMetadata struct {
HasImmutableReferences bool HasImmutableReferences bool
} }
func (generator *bindGenGeneratorLocal) generateBindings() error { func (generator *BindGenGeneratorLocal) GenerateBindings() error {
contracts, err := readContractList(generator.logger, generator.contractsListPath) contracts, err := readContractList(generator.Logger, generator.ContractsListPath)
if err != nil { if err != nil {
return fmt.Errorf("error reading contract list %s: %w", generator.contractsListPath, err) return fmt.Errorf("error reading contract list %s: %w", generator.ContractsListPath, err)
} }
if len(contracts.Local) == 0 { if len(contracts.Local) == 0 {
return fmt.Errorf("no contracts parsed from given contract list: %s", generator.contractsListPath) return fmt.Errorf("no contracts parsed from given contract list: %s", generator.ContractsListPath)
} }
return generator.processContracts(contracts.Local) return generator.processContracts(contracts.Local)
} }
func (generator *bindGenGeneratorLocal) processContracts(contracts []string) error { func (generator *BindGenGeneratorLocal) processContracts(contracts []string) error {
tempArtifactsDir, err := mkTempArtifactsDir(generator.logger) tempArtifactsDir, err := mkTempArtifactsDir(generator.Logger)
if err != nil { if err != nil {
return err return err
} }
defer func() { defer func() {
err := os.RemoveAll(tempArtifactsDir) err := os.RemoveAll(tempArtifactsDir)
if err != nil { if err != nil {
generator.logger.Error("Error removing temporary artifact directory", "path", tempArtifactsDir, "err", err.Error()) generator.Logger.Error("Error removing temporary artifact directory", "path", tempArtifactsDir, "err", err.Error())
} else { } else {
generator.logger.Debug("Successfully removed temporary artifact directory") generator.Logger.Debug("Successfully removed temporary artifact directory")
} }
}() }()
sourceMapsList := strings.Split(generator.sourceMapsList, ",") sourceMapsList := strings.Split(generator.SourceMapsList, ",")
sourceMapsSet := make(map[string]struct{}) sourceMapsSet := make(map[string]struct{})
for _, k := range sourceMapsList { for _, k := range sourceMapsList {
sourceMapsSet[k] = struct{}{} sourceMapsSet[k] = struct{}{}
...@@ -70,19 +70,19 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err ...@@ -70,19 +70,19 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err
contractMetadataFileTemplate := template.Must(template.New("localContractMetadata").Parse(localContractMetadataTemplate)) contractMetadataFileTemplate := template.Must(template.New("localContractMetadata").Parse(localContractMetadataTemplate))
for _, contractName := range contracts { for _, contractName := range contracts {
generator.logger.Info("Generating bindings and metadata for local contract", "contract", contractName) generator.Logger.Info("Generating bindings and metadata for local contract", "contract", contractName)
forgeArtifact, err := generator.readForgeArtifact(contractName, contractArtifactPaths) forgeArtifact, err := generator.readForgeArtifact(contractName, contractArtifactPaths)
if err != nil { if err != nil {
return err return err
} }
abiFilePath, bytecodeFilePath, err := writeContractArtifacts(generator.logger, tempArtifactsDir, contractName, forgeArtifact.Abi, []byte(forgeArtifact.Bytecode.Object.String())) abiFilePath, bytecodeFilePath, err := writeContractArtifacts(generator.Logger, tempArtifactsDir, contractName, forgeArtifact.Abi, []byte(forgeArtifact.Bytecode.Object.String()))
if err != nil { if err != nil {
return err return err
} }
err = genContractBindings(generator.logger, generator.monorepoBasePath, abiFilePath, bytecodeFilePath, generator.bindingsPackageName, contractName) err = genContractBindings(generator.Logger, generator.MonorepoBasePath, abiFilePath, bytecodeFilePath, generator.BindingsPackageName, contractName)
if err != nil { if err != nil {
return err return err
} }
...@@ -104,7 +104,7 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err ...@@ -104,7 +104,7 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err
Name: contractName, Name: contractName,
StorageLayout: canonicalStorageStr, StorageLayout: canonicalStorageStr,
DeployedBin: forgeArtifact.DeployedBytecode.Object.String(), DeployedBin: forgeArtifact.DeployedBytecode.Object.String(),
Package: generator.bindingsPackageName, Package: generator.BindingsPackageName,
DeployedSourceMap: deployedSourceMap, DeployedSourceMap: deployedSourceMap,
HasImmutableReferences: hasImmutables, HasImmutableReferences: hasImmutables,
} }
...@@ -117,14 +117,14 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err ...@@ -117,14 +117,14 @@ func (generator *bindGenGeneratorLocal) processContracts(contracts []string) err
return nil return nil
} }
func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]string, error) { func (generator *BindGenGeneratorLocal) getContractArtifactPaths() (map[string]string, error) {
// If some contracts have the same name then the path to their // If some contracts have the same name then the path to their
// artifact depends on their full import path. Scan over all artifacts // artifact depends on their full import path. Scan over all artifacts
// and hold a mapping from the contract name to the contract path. // and hold a mapping from the contract name to the contract path.
// Walk walks the directory deterministically, so the earliest instance // Walk walks the directory deterministically, so the earliest instance
// of the contract with the same name will be used // of the contract with the same name will be used
artifactPaths := make(map[string]string) artifactPaths := make(map[string]string)
if err := filepath.Walk(generator.forgeArtifactsPath, if err := filepath.Walk(generator.ForgeArtifactsPath,
func(path string, info os.FileInfo, err error) error { func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
...@@ -141,7 +141,7 @@ func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]s ...@@ -141,7 +141,7 @@ func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]s
if !ok { if !ok {
artifactPaths[sanitized] = path artifactPaths[sanitized] = path
} else { } else {
generator.logger.Warn("Multiple versions of forge artifacts exist, using lesser version", "contract", sanitized) generator.Logger.Warn("Multiple versions of forge artifacts exist, using lesser version", "contract", sanitized)
} }
} }
return nil return nil
...@@ -152,13 +152,13 @@ func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]s ...@@ -152,13 +152,13 @@ func (generator *bindGenGeneratorLocal) getContractArtifactPaths() (map[string]s
return artifactPaths, nil return artifactPaths, nil
} }
func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, contractArtifactPaths map[string]string) (foundry.Artifact, error) { func (generator *BindGenGeneratorLocal) readForgeArtifact(contractName string, contractArtifactPaths map[string]string) (foundry.Artifact, error) {
var forgeArtifact foundry.Artifact var forgeArtifact foundry.Artifact
contractArtifactPath := path.Join(generator.forgeArtifactsPath, contractName+".sol", contractName+".json") contractArtifactPath := path.Join(generator.ForgeArtifactsPath, contractName+".sol", contractName+".json")
forgeArtifactRaw, err := os.ReadFile(contractArtifactPath) forgeArtifactRaw, err := os.ReadFile(contractArtifactPath)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
generator.logger.Debug("Cannot find forge-artifact at standard path, trying provided path", "contract", contractName, "standardPath", contractArtifactPath, "providedPath", contractArtifactPaths[contractName]) generator.Logger.Debug("Cannot find forge-artifact at standard path, trying provided path", "contract", contractName, "standardPath", contractArtifactPath, "providedPath", contractArtifactPaths[contractName])
contractArtifactPath = contractArtifactPaths[contractName] contractArtifactPath = contractArtifactPaths[contractName]
forgeArtifactRaw, err = os.ReadFile(contractArtifactPath) forgeArtifactRaw, err = os.ReadFile(contractArtifactPath)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
...@@ -166,7 +166,7 @@ func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, c ...@@ -166,7 +166,7 @@ func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, c
} }
} }
generator.logger.Debug("Using forge-artifact", "path", contractArtifactPath) generator.Logger.Debug("Using forge-artifact", "path", contractArtifactPath)
if err := json.Unmarshal(forgeArtifactRaw, &forgeArtifact); err != nil { if err := json.Unmarshal(forgeArtifactRaw, &forgeArtifact); err != nil {
return forgeArtifact, fmt.Errorf("failed to parse forge artifact of %q: %w", contractName, err) return forgeArtifact, fmt.Errorf("failed to parse forge artifact of %q: %w", contractName, err)
} }
...@@ -174,9 +174,9 @@ func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, c ...@@ -174,9 +174,9 @@ func (generator *bindGenGeneratorLocal) readForgeArtifact(contractName string, c
return forgeArtifact, nil return forgeArtifact, nil
} }
func (generator *bindGenGeneratorLocal) canonicalizeStorageLayout(forgeArtifact foundry.Artifact, sourceMapsSet map[string]struct{}, contractName string) (string, string, error) { func (generator *BindGenGeneratorLocal) canonicalizeStorageLayout(forgeArtifact foundry.Artifact, sourceMapsSet map[string]struct{}, contractName string) (string, string, error) {
artifactStorageStruct := forgeArtifact.StorageLayout artifactStorageStruct := forgeArtifact.StorageLayout
canonicalStorageStruct := ast.CanonicalizeASTIDs(&artifactStorageStruct, generator.monorepoBasePath) canonicalStorageStruct := ast.CanonicalizeASTIDs(&artifactStorageStruct, generator.MonorepoBasePath)
canonicalStorageJson, err := json.Marshal(canonicalStorageStruct) canonicalStorageJson, err := json.Marshal(canonicalStorageStruct)
if err != nil { if err != nil {
return "", "", fmt.Errorf("error marshaling canonical storage: %w", err) return "", "", fmt.Errorf("error marshaling canonical storage: %w", err)
...@@ -191,8 +191,8 @@ func (generator *bindGenGeneratorLocal) canonicalizeStorageLayout(forgeArtifact ...@@ -191,8 +191,8 @@ func (generator *bindGenGeneratorLocal) canonicalizeStorageLayout(forgeArtifact
return deployedSourceMap, canonicalStorageStr, nil return deployedSourceMap, canonicalStorageStr, nil
} }
func (generator *bindGenGeneratorLocal) writeContractMetadata(contractMetaData localContractMetadata, contractName string, fileTemplate *template.Template) error { func (generator *BindGenGeneratorLocal) writeContractMetadata(contractMetaData localContractMetadata, contractName string, fileTemplate *template.Template) error {
metadataFilePath := filepath.Join(generator.metadataOut, strings.ToLower(contractName)+"_more.go") metadataFilePath := filepath.Join(generator.MetadataOut, strings.ToLower(contractName)+"_more.go")
metadataFile, err := os.OpenFile( metadataFile, err := os.OpenFile(
metadataFilePath, metadataFilePath,
os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.O_RDWR|os.O_CREATE|os.O_TRUNC,
...@@ -207,7 +207,7 @@ func (generator *bindGenGeneratorLocal) writeContractMetadata(contractMetaData l ...@@ -207,7 +207,7 @@ func (generator *bindGenGeneratorLocal) writeContractMetadata(contractMetaData l
return fmt.Errorf("error writing %s's contract metadata at %s: %w", contractName, metadataFilePath, err) return fmt.Errorf("error writing %s's contract metadata at %s: %w", contractName, metadataFilePath, err)
} }
generator.logger.Debug("Successfully wrote contract metadata", "contract", contractName, "path", metadataFilePath) generator.Logger.Debug("Successfully wrote contract metadata", "contract", contractName, "path", metadataFilePath)
return nil return nil
} }
......
package main package bindgen
import ( import (
"context" "context"
...@@ -10,15 +10,15 @@ import ( ...@@ -10,15 +10,15 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
) )
type bindGenGeneratorRemote struct { type BindGenGeneratorRemote struct {
bindGenGeneratorBase BindGenGeneratorBase
contractDataClients struct { ContractDataClients struct {
eth contractDataClient Eth contractDataClient
op contractDataClient Op contractDataClient
} }
rpcClients struct { RpcClients struct {
eth *ethclient.Client Eth *ethclient.Client
op *ethclient.Client Op *ethclient.Client
} }
tempArtifactsDir string tempArtifactsDir string
} }
...@@ -30,67 +30,67 @@ type contractDataClient interface { ...@@ -30,67 +30,67 @@ type contractDataClient interface {
FetchDeploymentTx(ctx context.Context, txHash string) (etherscan.Transaction, error) FetchDeploymentTx(ctx context.Context, txHash string) (etherscan.Transaction, error)
} }
type deployments struct { type Deployments struct {
Eth common.Address `json:"eth"` Eth common.Address `json:"eth"`
Op common.Address `json:"op"` Op common.Address `json:"op"`
} }
type remoteContract struct { type RemoteContract struct {
Name string `json:"name"` Name string `json:"name"`
Verified bool `json:"verified"` Verified bool `json:"verified"`
Deployments deployments `json:"deployments"` Deployments Deployments `json:"deployments"`
DeploymentSalt string `json:"deploymentSalt"` DeploymentSalt string `json:"deploymentSalt"`
Deployer common.Address `json:"deployer"` Deployer common.Address `json:"deployer"`
ABI string `json:"abi"` ABI string `json:"abi"`
InitBytecode string `json:"initBytecode"` InitBytecode string `json:"initBytecode"`
} }
type remoteContractMetadata struct { type RemoteContractMetadata struct {
remoteContract RemoteContract
Package string Package string
InitBin string InitBin string
DeployedBin string DeployedBin string
} }
func (generator *bindGenGeneratorRemote) generateBindings() error { func (generator *BindGenGeneratorRemote) GenerateBindings() error {
contracts, err := readContractList(generator.logger, generator.contractsListPath) contracts, err := readContractList(generator.Logger, generator.ContractsListPath)
if err != nil { if err != nil {
return fmt.Errorf("error reading contract list %s: %w", generator.contractsListPath, err) return fmt.Errorf("error reading contract list %s: %w", generator.ContractsListPath, err)
} }
if len(contracts.Remote) == 0 { if len(contracts.Remote) == 0 {
return fmt.Errorf("no contracts parsed from given contract list: %s", generator.contractsListPath) return fmt.Errorf("no contracts parsed from given contract list: %s", generator.ContractsListPath)
} }
return generator.processContracts(contracts.Remote) return generator.processContracts(contracts.Remote)
} }
func (generator *bindGenGeneratorRemote) processContracts(contracts []remoteContract) error { func (generator *BindGenGeneratorRemote) processContracts(contracts []RemoteContract) error {
var err error var err error
generator.tempArtifactsDir, err = mkTempArtifactsDir(generator.logger) generator.tempArtifactsDir, err = mkTempArtifactsDir(generator.Logger)
if err != nil { if err != nil {
return err return err
} }
defer func() { defer func() {
err := os.RemoveAll(generator.tempArtifactsDir) err := os.RemoveAll(generator.tempArtifactsDir)
if err != nil { if err != nil {
generator.logger.Error("Error removing temporary artifact directory", "path", generator.tempArtifactsDir, "err", err.Error()) generator.Logger.Error("Error removing temporary artifact directory", "path", generator.tempArtifactsDir, "err", err.Error())
} else { } else {
generator.logger.Debug("Successfully removed temporary artifact directory") generator.Logger.Debug("Successfully removed temporary artifact directory")
} }
}() }()
for _, contract := range contracts { for _, contract := range contracts {
generator.logger.Info("Generating bindings and metadata for remote contract", "contract", contract.Name) generator.Logger.Info("Generating bindings and metadata for remote contract", "contract", contract.Name)
contractMetadata := remoteContractMetadata{ contractMetadata := RemoteContractMetadata{
remoteContract: remoteContract{ RemoteContract: RemoteContract{
Name: contract.Name, Name: contract.Name,
Deployments: contract.Deployments, Deployments: contract.Deployments,
DeploymentSalt: contract.DeploymentSalt, DeploymentSalt: contract.DeploymentSalt,
ABI: contract.ABI, ABI: contract.ABI,
Verified: contract.Verified, Verified: contract.Verified,
}, },
Package: generator.bindingsPackageName, Package: generator.BindingsPackageName,
} }
var err error var err error
......
This diff is collapsed.
package main package bindgen
import ( import (
"fmt"
"os"
"reflect"
"strings"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
var generator bindGenGeneratorRemote = bindGenGeneratorRemote{} var generator BindGenGeneratorRemote = BindGenGeneratorRemote{}
func configureGenerator(t *testing.T) error {
if os.Getenv("RUN_E2E") == "" {
t.Log("Not running test, RUN_E2E env not set")
t.Skip()
}
generator.contractDataClients.eth = etherscan.NewEthereumClient(os.Getenv("ETHERSCAN_APIKEY_ETH"))
generator.contractDataClients.op = etherscan.NewOptimismClient(os.Getenv("ETHERSCAN_APIKEY_OP"))
var err error
if generator.rpcClients.eth, err = ethclient.Dial(os.Getenv("RPC_URL_ETH")); err != nil {
return fmt.Errorf("error initializing Ethereum client: %w", err)
}
if generator.rpcClients.op, err = ethclient.Dial(os.Getenv("RPC_URL_OP")); err != nil {
return fmt.Errorf("error initializing Optimism client: %w", err)
}
return nil
}
func TestFetchContractData(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range fetchContractDataTests {
t.Run(tt.name, func(t *testing.T) {
contractData, err := generator.fetchContractData(tt.contractVerified, tt.chain, tt.deploymentAddress)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(contractData, tt.expectedContractData) {
t.Errorf("Retrieved contract data doesn't match expected. Expected: %s Retrieved: %s", tt.expectedContractData, contractData)
}
})
}
}
func TestFetchContractDataFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range fetchContractDataTestsFailures {
t.Run(tt.name, func(t *testing.T) {
_, err := generator.fetchContractData(tt.contractVerified, tt.chain, tt.deploymentAddress)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestRemoveDeploymentSalt(t *testing.T) { func TestRemoveDeploymentSalt(t *testing.T) {
for _, tt := range removeDeploymentSaltTests { for _, tt := range removeDeploymentSaltTests {
...@@ -90,111 +25,3 @@ func TestRemoveDeploymentSaltFailures(t *testing.T) { ...@@ -90,111 +25,3 @@ func TestRemoveDeploymentSaltFailures(t *testing.T) {
}) })
} }
} }
func TestCompareInitBytecodeWithOp(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareInitBytecodeWithOpTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareInitBytecodeWithOp(&tt.contractMetadataEth, tt.initCodeShouldMatch)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareInitBytecodeWithOpFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareInitBytecodeWithOpTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareInitBytecodeWithOp(&tt.contractMetadataEth, tt.initCodeShouldMatch)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareDeployedBytecodeWithOp(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithOpTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareDeployedBytecodeWithOp(&tt.contractMetadataEth, tt.deployedCodeShouldMatch)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareDeployedBytecodeWithOpFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithOpTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareDeployedBytecodeWithOp(&tt.contractMetadataEth, tt.deployedCodeShouldMatch)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
func TestCompareDeployedBytecodeWithRpc(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithRpcTests {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareDeployedBytecodeWithRpc(&tt.contractMetadataEth, tt.chain)
if err != nil {
t.Error(err)
}
})
}
}
func TestCompareDeployedBytecodeWithRpcFailures(t *testing.T) {
if err := configureGenerator(t); err != nil {
t.Error(err)
}
for _, tt := range compareDeployedBytecodeWithRpcTestsFailures {
t.Run(tt.name, func(t *testing.T) {
err := generator.compareDeployedBytecodeWithRpc(&tt.contractMetadataEth, tt.chain)
if err == nil {
t.Errorf("Expected error: %s but didn't receive it", tt.expectedError)
return
}
if !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("Expected error: %s Received: %s", tt.expectedError, err)
return
}
})
}
}
package main package bindgen
import ( import (
"bufio" "bufio"
...@@ -13,9 +13,17 @@ import ( ...@@ -13,9 +13,17 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
type BindGenGeneratorBase struct {
MetadataOut string
BindingsPackageName string
MonorepoBasePath string
ContractsListPath string
Logger log.Logger
}
type contractsList struct { type contractsList struct {
Local []string `json:"local"` Local []string `json:"local"`
Remote []remoteContract `json:"remote"` Remote []RemoteContract `json:"remote"`
} }
// readContractList reads a JSON file from the given `filePath` and unmarshals // readContractList reads a JSON file from the given `filePath` and unmarshals
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/ethereum-optimism/optimism/op-bindings/bindgen"
"github.com/ethereum-optimism/optimism/op-bindings/etherscan" "github.com/ethereum-optimism/optimism/op-bindings/etherscan"
op_service "github.com/ethereum-optimism/optimism/op-service" op_service "github.com/ethereum-optimism/optimism/op-service"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
...@@ -12,14 +13,6 @@ import ( ...@@ -12,14 +13,6 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
type bindGenGeneratorBase struct {
metadataOut string
bindingsPackageName string
monorepoBasePath string
contractsListPath string
logger log.Logger
}
const ( const (
// Base Flags // Base Flags
MetadataOutFlagName = "metadata-out" MetadataOutFlagName = "metadata-out"
...@@ -92,7 +85,7 @@ func generateBindings(c *cli.Context) error { ...@@ -92,7 +85,7 @@ func generateBindings(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := localBindingsGenerator.generateBindings(); err != nil { if err := localBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating local bindings: %w", err) return fmt.Errorf("error generating local bindings: %w", err)
} }
...@@ -100,7 +93,7 @@ func generateBindings(c *cli.Context) error { ...@@ -100,7 +93,7 @@ func generateBindings(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := remoteBindingsGenerator.generateBindings(); err != nil { if err := remoteBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating remote bindings: %w", err) return fmt.Errorf("error generating remote bindings: %w", err)
} }
...@@ -110,7 +103,7 @@ func generateBindings(c *cli.Context) error { ...@@ -110,7 +103,7 @@ func generateBindings(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := localBindingsGenerator.generateBindings(); err != nil { if err := localBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating local bindings: %w", err) return fmt.Errorf("error generating local bindings: %w", err)
} }
return nil return nil
...@@ -119,7 +112,7 @@ func generateBindings(c *cli.Context) error { ...@@ -119,7 +112,7 @@ func generateBindings(c *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := remoteBindingsGenerator.generateBindings(); err != nil { if err := remoteBindingsGenerator.GenerateBindings(); err != nil {
return fmt.Errorf("error generating remote bindings: %w", err) return fmt.Errorf("error generating remote bindings: %w", err)
} }
return nil return nil
...@@ -128,55 +121,55 @@ func generateBindings(c *cli.Context) error { ...@@ -128,55 +121,55 @@ func generateBindings(c *cli.Context) error {
} }
} }
func parseConfigBase(logger log.Logger, c *cli.Context) (bindGenGeneratorBase, error) { func parseConfigBase(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorBase, error) {
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
return bindGenGeneratorBase{}, err return bindgen.BindGenGeneratorBase{}, err
} }
monoRepoPath, err := op_service.FindMonorepoRoot(cwd) monoRepoPath, err := op_service.FindMonorepoRoot(cwd)
if err != nil { if err != nil {
return bindGenGeneratorBase{}, err return bindgen.BindGenGeneratorBase{}, err
} }
return bindGenGeneratorBase{ return bindgen.BindGenGeneratorBase{
metadataOut: c.String(MetadataOutFlagName), MetadataOut: c.String(MetadataOutFlagName),
bindingsPackageName: c.String(BindingsPackageNameFlagName), BindingsPackageName: c.String(BindingsPackageNameFlagName),
monorepoBasePath: monoRepoPath, MonorepoBasePath: monoRepoPath,
contractsListPath: c.String(ContractsListFlagName), ContractsListPath: c.String(ContractsListFlagName),
logger: logger, Logger: logger,
}, nil }, nil
} }
func parseConfigLocal(logger log.Logger, c *cli.Context) (bindGenGeneratorLocal, error) { func parseConfigLocal(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorLocal, error) {
baseConfig, err := parseConfigBase(logger, c) baseConfig, err := parseConfigBase(logger, c)
if err != nil { if err != nil {
return bindGenGeneratorLocal{}, err return bindgen.BindGenGeneratorLocal{}, err
} }
return bindGenGeneratorLocal{ return bindgen.BindGenGeneratorLocal{
bindGenGeneratorBase: baseConfig, BindGenGeneratorBase: baseConfig,
sourceMapsList: c.String(SourceMapsListFlagName), SourceMapsList: c.String(SourceMapsListFlagName),
forgeArtifactsPath: c.String(ForgeArtifactsFlagName), ForgeArtifactsPath: c.String(ForgeArtifactsFlagName),
}, nil }, nil
} }
func parseConfigRemote(logger log.Logger, c *cli.Context) (bindGenGeneratorRemote, error) { func parseConfigRemote(logger log.Logger, c *cli.Context) (bindgen.BindGenGeneratorRemote, error) {
baseConfig, err := parseConfigBase(logger, c) baseConfig, err := parseConfigBase(logger, c)
if err != nil { if err != nil {
return bindGenGeneratorRemote{}, err return bindgen.BindGenGeneratorRemote{}, err
} }
generator := bindGenGeneratorRemote{ generator := bindgen.BindGenGeneratorRemote{
bindGenGeneratorBase: baseConfig, BindGenGeneratorBase: baseConfig,
} }
generator.contractDataClients.eth = etherscan.NewEthereumClient(c.String(EtherscanApiKeyEthFlagName)) generator.ContractDataClients.Eth = etherscan.NewEthereumClient(c.String(EtherscanApiKeyEthFlagName))
generator.contractDataClients.op = etherscan.NewOptimismClient(c.String(EtherscanApiKeyOpFlagName)) generator.ContractDataClients.Op = etherscan.NewOptimismClient(c.String(EtherscanApiKeyOpFlagName))
if generator.rpcClients.eth, err = ethclient.Dial(c.String(RpcUrlEthFlagName)); err != nil { if generator.RpcClients.Eth, err = ethclient.Dial(c.String(RpcUrlEthFlagName)); err != nil {
return bindGenGeneratorRemote{}, fmt.Errorf("error initializing Ethereum client: %w", err) return bindgen.BindGenGeneratorRemote{}, fmt.Errorf("error initializing Ethereum client: %w", err)
} }
if generator.rpcClients.op, err = ethclient.Dial(c.String(RpcUrlOpFlagName)); err != nil { if generator.RpcClients.Op, err = ethclient.Dial(c.String(RpcUrlOpFlagName)); err != nil {
return bindGenGeneratorRemote{}, fmt.Errorf("error initializing Optimism client: %w", err) return bindgen.BindGenGeneratorRemote{}, fmt.Errorf("error initializing Optimism client: %w", err)
} }
return generator, nil return generator, nil
} }
......
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