Skip to content

Commit

Permalink
Pull seth client into multiclient
Browse files Browse the repository at this point in the history
  • Loading branch information
ogtownsend committed Sep 18, 2024
1 parent e89847b commit 2381add
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package kms
package deployment

import (
"bytes"
Expand All @@ -9,6 +9,8 @@ import (
"fmt"
"math/big"

"github.com/aws/aws-sdk-go/aws/session"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand Down Expand Up @@ -184,3 +186,25 @@ func padTo32Bytes(buffer []byte) []byte {
}
return buffer
}

type AwsSessionFn func(config Config) *session.Session

var awsSessionFromEnvVarsFn = func(config Config) *session.Session {
return session.Must(
session.NewSession(&aws.Config{
Region: aws.String(config.EnvConfig.KmsDeployerKeyRegion),
CredentialsChainVerboseErrors: aws.Bool(true),
}))
}

var awsSessionFromProfileFn = func(config Config) *session.Session {
return session.Must(
session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
Profile: config.EnvConfig.AwsProfileName,
Config: aws.Config{
Region: aws.String(config.EnvConfig.KmsDeployerKeyRegion),
CredentialsChainVerboseErrors: aws.Bool(true),
},
}))
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package kms
package deployment

import (
"encoding/hex"
Expand Down
134 changes: 129 additions & 5 deletions integration-tests/deployment/multiclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,35 @@ import (
"context"
"fmt"
"math/big"
"os"
"time"

"github.com/avast/retry-go/v4"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/pelletier/go-toml/v2"
"github.com/smartcontractkit/chainlink-testing-framework/seth"
)

const (
RPC_RETRY_ATTEMPTS = 10
RPC_RETRY_DELAY = 1000 * time.Millisecond
)

// MultiClient should comply with the coreenv.OnchainClient interface
// MultiClient should comply with the OnchainClient interface
var _ OnchainClient = &MultiClient{}

type MultiClient struct {
*ethclient.Client
backup []*ethclient.Client
// we will use Seth only for gas estimations, confirming and tracing the transactions, but for sending transactions we will use pure ethclient
// so that MultiClient conforms to the OnchainClient interface
SethClient *seth.Client
EvmKMSClient *evmKMSClient
chainId uint64
}

type RPC struct {
Expand All @@ -31,22 +41,136 @@ type RPC struct {
WSURL string `toml:"ws_url"`
}

func NewMultiClient(rpcs []RPC) *MultiClient {
type Config struct {
EnvConfig EnvConfig `toml:"env_config"`
}

type EnvConfig struct {
TestWalletKey string `toml:"test_wallet_key"`
KmsDeployerKeyId string `toml:"kms_deployer_key_id"`
KmsDeployerKeyRegion string `toml:"kms_deployer_key_region"`
AwsProfileName string `toml:"aws_profile_name"`
EvmNetworks []EvmNetwork `toml:"evm_networks"`
// Seth-related
GethWrappersDirs []string `toml:"geth_wrappers_dirs"`
SethConfigFile string `toml:"seth_config_file"`
}

type EvmNetwork struct {
ChainID uint64 `toml:"chain_id"`
EtherscanAPIKey string `toml:"etherscan_api_key"`
EtherscanUrl string `toml:"etherscan_url"`
RPCs []RPC `toml:"rpcs"`
}

func initRpcClients(rpcs []RPC) (*ethclient.Client, []*ethclient.Client) {
if len(rpcs) == 0 {
panic("No RPCs provided")
}
clients := make([]*ethclient.Client, 0, len(rpcs))

for _, rpc := range rpcs {
client, err := ethclient.Dial(rpc.HTTPURL)
if err != nil {
panic(err)
}
clients = append(clients, client)
}
return &MultiClient{
Client: clients[0],
backup: clients[1:],
return clients[0], clients[1:]
}

func NewMultiClientWithSeth(rpcs []RPC, chainId uint64, config Config) *MultiClient {
mainClient, backupClients := initRpcClients(rpcs)
mc := &MultiClient{
Client: mainClient,
backup: backupClients,
chainId: chainId,
}

sethClient, err := buildSethClient(rpcs[0].HTTPURL, chainId, config)
if err != nil {
panic(err)
}

mc.SethClient = sethClient
mc.EvmKMSClient = initialiseKMSClient(config)

return mc
}

func buildSethClient(rpc string, chainId uint64, config Config) (*seth.Client, error) {
var sethClient *seth.Client
var err error

// if config path is provided use the TOML file to configure Seth to provide maximum flexibility
if config.EnvConfig.SethConfigFile != "" {
sethConfig, readErr := readSethConfigFromFile(config.EnvConfig.SethConfigFile)
if readErr != nil {
return nil, readErr
}

sethClient, err = seth.NewClientBuilderWithConfig(sethConfig).
UseNetworkWithChainId(chainId).
WithRpcUrl(rpc).
WithPrivateKeys([]string{config.EnvConfig.TestWalletKey}).
Build()
} else {
// if full flexibility is not needed we create a client with reasonable defaults
// if you need to further tweak them, please refer to https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/seth/README.md
sethClient, err = seth.NewClientBuilder().
WithRpcUrl(rpc).
WithPrivateKeys([]string{config.EnvConfig.TestWalletKey}).
WithProtections(true, true, seth.MustMakeDuration(1*time.Minute)).
WithGethWrappersFolders(config.EnvConfig.GethWrappersDirs).
// Fast priority will add a 20% buffer on top of what the node suggests
// we will use last 20 block to estimate block congestion and further bump gas price suggested by the node
WithGasPriceEstimations(true, 20, seth.Priority_Fast).
Build()
}

return sethClient, err
}

func readSethConfigFromFile(configPath string) (*seth.Config, error) {
d, err := os.ReadFile(configPath)
if err != nil {
return nil, err
}

var sethConfig seth.Config
err = toml.Unmarshal(d, &sethConfig)
if err != nil {
return nil, err
}

return &sethConfig, nil
}

func initialiseKMSClient(config Config) *evmKMSClient {
if config.EnvConfig.KmsDeployerKeyId != "" && config.EnvConfig.KmsDeployerKeyRegion != "" {
var awsSessionFn AwsSessionFn
if config.EnvConfig.AwsProfileName != "" {
awsSessionFn = awsSessionFromProfileFn
} else {
awsSessionFn = awsSessionFromEnvVarsFn
}
return NewEVMKMSClient(kms.New(awsSessionFn(config)), config.EnvConfig.KmsDeployerKeyId)
}
return nil
}

func (mc *MultiClient) GetKMSKey() *bind.TransactOpts {
kmsTxOpts, err := mc.EvmKMSClient.GetKMSTransactOpts(context.Background(), big.NewInt(int64(mc.chainId)))
if err != nil {
panic(err)
}
// nonce needs to be `nil` so that RPC node sets it, otherwise Seth would set it to whatever it was, when we requested the key
return mc.SethClient.NewTXOpts(seth.WithNonce(nil), seth.WithFrom(kmsTxOpts.From), seth.WithSignerFn(kmsTxOpts.Signer))
}

func (mc *MultiClient) GetTestWalletKey() *bind.TransactOpts {
// nonce needs to be `nil` so that RPC node sets it, otherwise Seth would set it to whatever it was, when we requested the key
return mc.SethClient.NewTXOpts(seth.WithNonce(nil))
}

func (mc *MultiClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ require (
github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0
github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5
github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0
github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1
github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.4-0.20240912161944-13ade8436072
github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0
github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7
Expand Down
1 change: 1 addition & 0 deletions integration-tests/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1445,6 +1445,7 @@ github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 h1:V
github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0/go.mod h1:lyAu+oMXdNUzEDScj2DXB2IueY+SDXPPfyl/kb63tMM=
github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 h1:2OxnPfvjC+zs0ZokSsRTRnJrEGJ4NVJwZgfroS1lPHs=
github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1/go.mod h1:afY3QmNgeR/VI1pRbGH8g3YXGy7C2RrFOwUzEFvL3L8=
github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.4-0.20240912161944-13ade8436072/go.mod h1:afY3QmNgeR/VI1pRbGH8g3YXGy7C2RrFOwUzEFvL3L8=
github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0 h1:gfhfTn7HkbUHNooSF3c9vzQyN8meWJVGt6G/pNUbpYk=
github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0/go.mod h1:tqajhpUJA/9OaMCLitghBXjAgqYO4i27St0F4TUO3+M=
github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs=
Expand Down

0 comments on commit 2381add

Please sign in to comment.