diff --git a/README.md b/README.md index 406a6420..d45135aa 100644 --- a/README.md +++ b/README.md @@ -210,13 +210,13 @@ The relayer is configured via a JSON file, the path to which is passed in via th - The VM type of the source blockchain. - `"rpc-endpoint": string` + `"rpc-endpoint": APIConfig` - - The RPC endpoint of the source blockchain's API node. + - The RPC endpoint configuration of the source blockchain's API node. - `"ws-endpoint": string` + `"ws-endpoint": APIConfig` - - The WebSocket endpoint of the source blockchain's API node. + - The WebSocket endpoint configuration of the source blockchain's API node. `"message-contracts": map[string]MessageProtocolConfig` @@ -250,9 +250,9 @@ The relayer is configured via a JSON file, the path to which is passed in via th - The VM type of the source blockchain. - `"rpc-endpoint": string` + `"rpc-endpoint": APIConfig` - - The RPC endpoint of the destination blockchains's API node. + - The RPC endpoint configuration of the destination blockchains's API node. `"account-private-key": string` diff --git a/config/config.go b/config/config.go index dcf07ae8..addd3fd1 100644 --- a/config/config.go +++ b/config/config.go @@ -17,7 +17,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/awm-relayer/utils" - "github.com/ava-labs/subnet-evm/ethclient" + "github.com/ava-labs/awm-relayer/ethclient" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" // Force-load precompiles to trigger registration @@ -85,8 +85,8 @@ type SourceBlockchain struct { SubnetID string `mapstructure:"subnet-id" json:"subnet-id"` BlockchainID string `mapstructure:"blockchain-id" json:"blockchain-id"` VM string `mapstructure:"vm" json:"vm"` - RPCEndpoint string `mapstructure:"rpc-endpoint" json:"rpc-endpoint"` - WSEndpoint string `mapstructure:"ws-endpoint" json:"ws-endpoint"` + RPCEndpoint APIConfig `mapstructure:"rpc-endpoint" json:"rpc-endpoint"` + WSEndpoint APIConfig `mapstructure:"ws-endpoint" json:"ws-endpoint"` MessageContracts map[string]MessageProtocolConfig `mapstructure:"message-contracts" json:"message-contracts"` SupportedDestinations []*SupportedDestination `mapstructure:"supported-destinations" json:"supported-destinations"` ProcessHistoricalBlocksFromHeight uint64 `mapstructure:"process-historical-blocks-from-height" json:"process-historical-blocks-from-height"` @@ -100,13 +100,13 @@ type SourceBlockchain struct { // Destination blockchain configuration. Specifies how to connect to and issue transactions on the desination blockchain. type DestinationBlockchain struct { - SubnetID string `mapstructure:"subnet-id" json:"subnet-id"` - BlockchainID string `mapstructure:"blockchain-id" json:"blockchain-id"` - VM string `mapstructure:"vm" json:"vm"` - RPCEndpoint string `mapstructure:"rpc-endpoint" json:"rpc-endpoint"` - KMSKeyID string `mapstructure:"kms-key-id" json:"kms-key-id"` - KMSAWSRegion string `mapstructure:"kms-aws-region" json:"kms-aws-region"` - AccountPrivateKey string `mapstructure:"account-private-key" json:"account-private-key"` + SubnetID string `mapstructure:"subnet-id" json:"subnet-id"` + BlockchainID string `mapstructure:"blockchain-id" json:"blockchain-id"` + VM string `mapstructure:"vm" json:"vm"` + RPCEndpoint APIConfig `mapstructure:"rpc-endpoint" json:"rpc-endpoint"` + KMSKeyID string `mapstructure:"kms-key-id" json:"kms-key-id"` + KMSAWSRegion string `mapstructure:"kms-aws-region" json:"kms-aws-region"` + AccountPrivateKey string `mapstructure:"account-private-key" json:"account-private-key"` // Fetched from the chain after startup warpQuorum WarpQuorum @@ -436,11 +436,11 @@ func (s *SourceBlockchain) Validate(destinationBlockchainIDs *set.Set[string]) e if _, err := ids.FromString(s.BlockchainID); err != nil { return fmt.Errorf("invalid blockchainID in source subnet configuration. Provided ID: %s", s.BlockchainID) } - if _, err := url.ParseRequestURI(s.WSEndpoint); err != nil { - return fmt.Errorf("invalid relayer subscribe URL in source subnet configuration: %w", err) + if err := s.RPCEndpoint.Validate(); err != nil { + return fmt.Errorf("invalid rpc-endpoint in source subnet configuration: %w", err) } - if _, err := url.ParseRequestURI(s.RPCEndpoint); err != nil { - return fmt.Errorf("invalid relayer RPC URL in source subnet configuration: %w", err) + if err := s.WSEndpoint.Validate(); err != nil { + return fmt.Errorf("invalid ws-endpoint in source subnet configuration: %w", err) } // Validate the VM specific settings @@ -543,8 +543,8 @@ func (s *DestinationBlockchain) Validate() error { if _, err := ids.FromString(s.BlockchainID); err != nil { return fmt.Errorf("invalid blockchainID in source subnet configuration. Provided ID: %s", s.BlockchainID) } - if _, err := url.ParseRequestURI(s.RPCEndpoint); err != nil { - return fmt.Errorf("invalid relayer broadcast URL: %w", err) + if err := s.RPCEndpoint.Validate(); err != nil { + return fmt.Errorf("invalid rpc-endpoint in destination subnet configuration: %w", err) } if s.KMSKeyID != "" { if s.KMSAWSRegion == "" { @@ -598,7 +598,7 @@ func (s *DestinationBlockchain) initializeWarpQuorum() error { return fmt.Errorf("invalid subnetID in configuration. error: %w", err) } - client, err := ethclient.Dial(s.RPCEndpoint) + client, err := ethclient.DialWithConfig(context.Background(), s.RPCEndpoint.BaseURL, s.RPCEndpoint.HTTPHeaders, s.RPCEndpoint.QueryParams) if err != nil { return fmt.Errorf("failed to dial destination blockchain %s: %w", blockchainID, err) } diff --git a/config/config_test.go b/config/config_test.go index e65984c9..ba889fbf 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -118,6 +118,7 @@ func TestGetRelayerAccountPrivateKey_set_pk_with_subnet_env(t *testing.T) { } runConfigModifierEnvVarTest(t, testCase) } + func TestGetRelayerAccountPrivateKey_set_pk_with_global_env(t *testing.T) { testCase := configMondifierEnvVarTestCase{ baseConfig: TestValidConfig, @@ -218,6 +219,7 @@ func TestEitherKMSOrAccountPrivateKey(t *testing.T) { } } } + func TestGetWarpQuorum(t *testing.T) { blockchainID, err := ids.FromString("p433wpuXyJiDhyazPYyZMJeaoPSW76CBZ2x7wrVPLgvokotXz") require.NoError(t, err) @@ -347,10 +349,14 @@ func TestGetWarpQuorum(t *testing.T) { func TestValidateSourceBlockchain(t *testing.T) { validSourceCfg := SourceBlockchain{ BlockchainID: testBlockchainID, - RPCEndpoint: fmt.Sprintf("http://test.avax.network/ext/bc/%s/rpc", testBlockchainID), - WSEndpoint: fmt.Sprintf("ws://test.avax.network/ext/bc/%s/ws", testBlockchainID), - SubnetID: testSubnetID, - VM: "evm", + RPCEndpoint: APIConfig{ + BaseURL: fmt.Sprintf("http://test.avax.network/ext/bc/%s/rpc", testBlockchainID), + }, + WSEndpoint: APIConfig{ + BaseURL: fmt.Sprintf("ws://test.avax.network/ext/bc/%s/ws", testBlockchainID), + }, + SubnetID: testSubnetID, + VM: "evm", SupportedDestinations: []*SupportedDestination{ { BlockchainID: testBlockchainID, diff --git a/config/test_utils.go b/config/test_utils.go index 603d8909..17e0e9b9 100644 --- a/config/test_utils.go +++ b/config/test_utils.go @@ -35,8 +35,12 @@ var ( }, SourceBlockchains: []*SourceBlockchain{ { - RPCEndpoint: fmt.Sprintf("http://test.avax.network/ext/bc/%s/rpc", testBlockchainID), - WSEndpoint: fmt.Sprintf("ws://test.avax.network/ext/bc/%s/ws", testBlockchainID), + RPCEndpoint: APIConfig{ + BaseURL: fmt.Sprintf("http://test.avax.network/ext/bc/%s/rpc", testBlockchainID), + }, + WSEndpoint: APIConfig{ + BaseURL: fmt.Sprintf("ws://test.avax.network/ext/bc/%s/ws", testBlockchainID), + }, BlockchainID: testBlockchainID, SubnetID: testSubnetID, VM: "evm", @@ -49,7 +53,9 @@ var ( }, DestinationBlockchains: []*DestinationBlockchain{ { - RPCEndpoint: fmt.Sprintf("http://test.avax.network/ext/bc/%s/rpc", testBlockchainID), + RPCEndpoint: APIConfig{ + BaseURL: fmt.Sprintf("http://test.avax.network/ext/bc/%s/rpc", testBlockchainID), + }, BlockchainID: testBlockchainID, SubnetID: testSubnetID, VM: "evm", @@ -58,8 +64,12 @@ var ( }, } TestValidSourceBlockchainConfig = SourceBlockchain{ - RPCEndpoint: "http://test.avax.network/ext/bc/C/rpc", - WSEndpoint: "ws://test.avax.network/ext/bc/C/ws", + RPCEndpoint: APIConfig{ + BaseURL: "http://test.avax.network/ext/bc/C/rpc", + }, + WSEndpoint: APIConfig{ + BaseURL: "ws://test.avax.network/ext/bc/C/ws", + }, BlockchainID: "S4mMqUXe7vHsGiRAma6bv3CKnyaLssyAxmQ2KvFpX1KEvfFCD", SubnetID: "2TGBXcnwx5PqiXWiqxAKUaNSqDguXNh1mxnp82jui68hxJSZAx", VM: "evm", @@ -70,10 +80,12 @@ var ( }, } TestValidDestinationBlockchainConfig = DestinationBlockchain{ - SubnetID: "2TGBXcnwx5PqiXWiqxAKUaNSqDguXNh1mxnp82jui68hxJSZAx", - BlockchainID: "S4mMqUXe7vHsGiRAma6bv3CKnyaLssyAxmQ2KvFpX1KEvfFCD", - VM: "evm", - RPCEndpoint: "http://test.avax.network/ext/bc/C/rpc", + SubnetID: "2TGBXcnwx5PqiXWiqxAKUaNSqDguXNh1mxnp82jui68hxJSZAx", + BlockchainID: "S4mMqUXe7vHsGiRAma6bv3CKnyaLssyAxmQ2KvFpX1KEvfFCD", + VM: "evm", + RPCEndpoint: APIConfig{ + BaseURL: "http://test.avax.network/ext/bc/C/rpc", + }, AccountPrivateKey: "1234567890123456789012345678901234567890123456789012345678901234", } ) diff --git a/ethclient/client.go b/ethclient/client.go new file mode 100644 index 00000000..807f2d1f --- /dev/null +++ b/ethclient/client.go @@ -0,0 +1,54 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package ethclient + +import ( + "context" + "errors" + "fmt" + "net/url" + + "github.com/ava-labs/subnet-evm/ethclient" + "github.com/ava-labs/subnet-evm/rpc" +) + +var ErrInvalidEndpoint = errors.New("invalid rpc endpoint") + +type Client ethclient.Client + +// DialWithContext returns an ethclient.Client with the internal RPC client configured with the provided options. +func DialWithConfig(ctx context.Context, baseURL string, httpHeaders, queryParams map[string]string) (Client, error) { + url, err := addQueryParams(baseURL, queryParams) + if err != nil { + return nil, err + } + client, err := rpc.DialOptions(ctx, url, newClientHeaderOptions(httpHeaders)...) + if err != nil { + return nil, err + } + return ethclient.NewClient(client), nil +} + +// addQueryParams adds the query parameters to the url +func addQueryParams(endpoint string, queryParams map[string]string) (string, error) { + uri, err := url.ParseRequestURI(endpoint) + if err != nil { + return "", fmt.Errorf("%w: %v", ErrInvalidEndpoint, err) + } + values := uri.Query() + for key, value := range queryParams { + values.Add(key, value) + } + uri.RawQuery = values.Encode() + return uri.String(), nil +} + +// newClientOptions creates a ClientOption slice from httpHeaders +func newClientHeaderOptions(httpHeaders map[string]string) []rpc.ClientOption { + opts := make([]rpc.ClientOption, 0, len(httpHeaders)) + for key, value := range httpHeaders { + opts = append(opts, rpc.WithHeader(key, value)) + } + return opts +} diff --git a/ethclient/client_test.go b/ethclient/client_test.go new file mode 100644 index 00000000..f31c16a6 --- /dev/null +++ b/ethclient/client_test.go @@ -0,0 +1,45 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package ethclient + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAddQueryParams(t *testing.T) { + t.Run("NoQueryParams", func(t *testing.T) { + newurl, err := addQueryParams("https://avalabs.com", nil) + require.NoError(t, err) + require.Equal(t, "https://avalabs.com", newurl) + }) + t.Run("TwoQueryParams", func(t *testing.T) { + newurl, err := addQueryParams("https://avalabs.com", map[string]string{ + "first": "value1", + "second": "value2", + }) + require.NoError(t, err) + require.Equal(t, "https://avalabs.com?first=value1&second=value2", newurl) + }) + t.Run("InvalidEndpoint", func(t *testing.T) { + _, err := addQueryParams("invalid-endpoint", nil) + require.True(t, errors.Is(err, ErrInvalidEndpoint)) + }) +} + +func TestNewClientOptions(t *testing.T) { + t.Run("NoHttpHeaders", func(t *testing.T) { + opts := newClientHeaderOptions(nil) + require.Len(t, opts, 0) + }) + t.Run("TwoHttpHeaders", func(t *testing.T) { + opts := newClientHeaderOptions(map[string]string{ + "first": "value1", + "second": "value2", + }) + require.Len(t, opts, 2) + }) +} diff --git a/messages/off-chain-registry/message_manager.go b/messages/off-chain-registry/message_manager.go index 8fbc2000..4204d6e2 100644 --- a/messages/off-chain-registry/message_manager.go +++ b/messages/off-chain-registry/message_manager.go @@ -13,17 +13,15 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/warp" warpPayload "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/ethclient" "github.com/ava-labs/awm-relayer/vms" "github.com/ava-labs/subnet-evm/accounts/abi/bind" - "github.com/ava-labs/subnet-evm/ethclient" teleporterregistry "github.com/ava-labs/teleporter/abi-bindings/go/Teleporter/upgrades/TeleporterRegistry" "github.com/ethereum/go-ethereum/common" "go.uber.org/zap" ) -var ( - OffChainRegistrySourceAddress = common.HexToAddress("0x0000000000000000000000000000000000000000") -) +var OffChainRegistrySourceAddress = common.HexToAddress("0x0000000000000000000000000000000000000000") const ( addProtocolVersionGasLimit uint64 = 500_000 diff --git a/messages/teleporter/message_manager.go b/messages/teleporter/message_manager.go index c4dc36fa..ef7323e4 100644 --- a/messages/teleporter/message_manager.go +++ b/messages/teleporter/message_manager.go @@ -13,9 +13,9 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/warp" warpPayload "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/ethclient" "github.com/ava-labs/awm-relayer/vms" "github.com/ava-labs/subnet-evm/accounts/abi/bind" - "github.com/ava-labs/subnet-evm/ethclient" teleportermessenger "github.com/ava-labs/teleporter/abi-bindings/go/Teleporter/TeleporterMessenger" gasUtils "github.com/ava-labs/teleporter/utils/gas-utils" teleporterUtils "github.com/ava-labs/teleporter/utils/teleporter-utils" diff --git a/relayer/application_relayer.go b/relayer/application_relayer.go index 29f8326e..5d689e9f 100644 --- a/relayer/application_relayer.go +++ b/relayer/application_relayer.go @@ -23,11 +23,11 @@ import ( avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/awm-relayer/config" "github.com/ava-labs/awm-relayer/database" + "github.com/ava-labs/awm-relayer/ethclient" "github.com/ava-labs/awm-relayer/messages" "github.com/ava-labs/awm-relayer/peers" "github.com/ava-labs/awm-relayer/utils" coreEthMsg "github.com/ava-labs/coreth/plugin/evm/message" - "github.com/ava-labs/subnet-evm/ethclient" msg "github.com/ava-labs/subnet-evm/plugin/evm/message" warpBackend "github.com/ava-labs/subnet-evm/warp" "go.uber.org/zap" @@ -191,7 +191,7 @@ func (r *applicationRelayer) relayMessage( func (r *applicationRelayer) createSignedMessage(unsignedMessage *avalancheWarp.UnsignedMessage) (*avalancheWarp.Message, error) { r.logger.Info("Fetching aggregate signature from the source chain validators via API") // TODO: To properly support this, we should provide a dedicated Warp API endpoint in the config - uri := utils.StripFromString(r.sourceBlockchain.RPCEndpoint, "/ext") + uri := utils.StripFromString(r.sourceBlockchain.RPCEndpoint.BaseURL, "/ext") warpClient, err := warpBackend.NewClient(uri, r.sourceBlockchain.GetBlockchainID().String()) if err != nil { r.logger.Error( @@ -639,7 +639,12 @@ func (r *applicationRelayer) calculateStartingBlockHeight(processHistoricalBlock // Gets the height of the chain head, writes it to the database, then returns it. func (r *applicationRelayer) setProcessedBlockHeightToLatest() (uint64, error) { - ethClient, err := ethclient.Dial(r.sourceBlockchain.RPCEndpoint) + ethClient, err := ethclient.DialWithConfig( + context.Background(), + r.sourceBlockchain.RPCEndpoint.BaseURL, + r.sourceBlockchain.RPCEndpoint.HTTPHeaders, + r.sourceBlockchain.RPCEndpoint.QueryParams, + ) if err != nil { r.logger.Error( "Failed to dial node", diff --git a/sample-relayer-config.json b/sample-relayer-config.json index 9f2d0254..129c81a4 100644 --- a/sample-relayer-config.json +++ b/sample-relayer-config.json @@ -10,8 +10,12 @@ "subnet-id": "11111111111111111111111111111111LpoYY", "blockchain-id": "yH8D7ThNJkxmtkuv2jgBa4P1Rn3Qpr4pPr7QYNfcdoS6k6HWp", "vm": "evm", - "rpc-endpoint": "https://api.avax-test.network/ext/bc/C/rpc", - "ws-endpoint": "wss://api.avax-test.network/ext/bc/C/ws", + "rpc-endpoint": { + "base-url": "https://api.avax-test.network/ext/bc/C/rpc" + }, + "ws-endpoint": { + "base-url": "wss://api.avax-test.network/ext/bc/C/ws" + }, "message-contracts": { "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf": { "message-format": "teleporter", @@ -27,7 +31,9 @@ "subnet-id": "7WtoAMPhrmh5KosDUsFL9yTcvw7YSxiKHPpdfs4JsgW47oZT5", "blockchain-id": "2D8RG4UpSXbPbvPCAWppNJyqTG2i2CAXSkTgmTBBvs7GKNZjsY", "vm": "evm", - "rpc-endpoint": "https://subnets.avax.network/dispatch/testnet/rpc", + "rpc-endpoint": { + "base-url": "https://subnets.avax.network/dispatch/testnet/rpc" + }, "account-private-key": "0x7493..." } ] diff --git a/tests/utils/utils.go b/tests/utils/utils.go index 1ee442ad..809159de 100644 --- a/tests/utils/utils.go +++ b/tests/utils/utils.go @@ -116,8 +116,12 @@ func CreateDefaultRelayerConfig( SubnetID: subnetInfo.SubnetID.String(), BlockchainID: subnetInfo.BlockchainID.String(), VM: config.EVM.String(), - RPCEndpoint: fmt.Sprintf("http://%s:%d/ext/bc/%s/rpc", host, port, subnetInfo.BlockchainID.String()), - WSEndpoint: fmt.Sprintf("ws://%s:%d/ext/bc/%s/ws", host, port, subnetInfo.BlockchainID.String()), + RPCEndpoint: config.APIConfig{ + BaseURL: fmt.Sprintf("http://%s:%d/ext/bc/%s/rpc", host, port, subnetInfo.BlockchainID.String()), + }, + WSEndpoint: config.APIConfig{ + BaseURL: fmt.Sprintf("ws://%s:%d/ext/bc/%s/ws", host, port, subnetInfo.BlockchainID.String()), + }, MessageContracts: map[string]config.MessageProtocolConfig{ teleporterContractAddress.Hex(): { @@ -149,10 +153,12 @@ func CreateDefaultRelayerConfig( Expect(err).Should(BeNil()) destinations[i] = &config.DestinationBlockchain{ - SubnetID: subnetInfo.SubnetID.String(), - BlockchainID: subnetInfo.BlockchainID.String(), - VM: config.EVM.String(), - RPCEndpoint: fmt.Sprintf("http://%s:%d/ext/bc/%s/rpc", host, port, subnetInfo.BlockchainID.String()), + SubnetID: subnetInfo.SubnetID.String(), + BlockchainID: subnetInfo.BlockchainID.String(), + VM: config.EVM.String(), + RPCEndpoint: config.APIConfig{ + BaseURL: fmt.Sprintf("http://%s:%d/ext/bc/%s/rpc", host, port, subnetInfo.BlockchainID.String()), + }, AccountPrivateKey: hex.EncodeToString(relayerKey.D.Bytes()), } diff --git a/vms/evm/destination_client.go b/vms/evm/destination_client.go index cfed5ef6..9878f9dc 100644 --- a/vms/evm/destination_client.go +++ b/vms/evm/destination_client.go @@ -14,9 +14,9 @@ import ( "github.com/ava-labs/avalanchego/utils/logging" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/ethclient" "github.com/ava-labs/awm-relayer/vms/evm/signer" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" predicateutils "github.com/ava-labs/subnet-evm/predicate" "github.com/ethereum/go-ethereum/common" @@ -48,7 +48,12 @@ type destinationClient struct { func NewDestinationClient(logger logging.Logger, destinationBlockchain *config.DestinationBlockchain) (*destinationClient, error) { // Dial the destination RPC endpoint - client, err := ethclient.Dial(destinationBlockchain.RPCEndpoint) + client, err := ethclient.DialWithConfig( + context.Background(), + destinationBlockchain.RPCEndpoint.BaseURL, + destinationBlockchain.RPCEndpoint.HTTPHeaders, + destinationBlockchain.RPCEndpoint.QueryParams, + ) if err != nil { logger.Error( "Failed to dial rpc endpoint", @@ -107,7 +112,8 @@ func NewDestinationClient(logger logging.Logger, destinationBlockchain *config.D func (c *destinationClient) SendTx(signedMessage *avalancheWarp.Message, toAddress string, gasLimit uint64, - callData []byte) error { + callData []byte, +) error { // Synchronize teleporter message requests to the same destination chain so that message ordering is preserved c.lock.Lock() defer c.lock.Unlock() diff --git a/vms/evm/destination_client_test.go b/vms/evm/destination_client_test.go index 4ac9aa1d..4608fe5d 100644 --- a/vms/evm/destination_client_test.go +++ b/vms/evm/destination_client_test.go @@ -19,10 +19,12 @@ import ( ) var destinationSubnet = config.DestinationBlockchain{ - SubnetID: "2TGBXcnwx5PqiXWiqxAKUaNSqDguXNh1mxnp82jui68hxJSZAx", - BlockchainID: "S4mMqUXe7vHsGiRAma6bv3CKnyaLssyAxmQ2KvFpX1KEvfFCD", - VM: config.EVM.String(), - RPCEndpoint: "https://subnets.avax.network/mysubnet/rpc", + SubnetID: "2TGBXcnwx5PqiXWiqxAKUaNSqDguXNh1mxnp82jui68hxJSZAx", + BlockchainID: "S4mMqUXe7vHsGiRAma6bv3CKnyaLssyAxmQ2KvFpX1KEvfFCD", + VM: config.EVM.String(), + RPCEndpoint: config.APIConfig{ + BaseURL: "https://subnets.avax.network/mysubnet/rpc", + }, AccountPrivateKey: "56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027", } diff --git a/vms/evm/subscriber.go b/vms/evm/subscriber.go index 432c8df9..33a355b4 100644 --- a/vms/evm/subscriber.go +++ b/vms/evm/subscriber.go @@ -14,9 +14,9 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/ethclient" "github.com/ava-labs/awm-relayer/vms/vmtypes" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/interfaces" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" "github.com/ethereum/go-ethereum/common" @@ -47,17 +47,17 @@ var warpFilterQuery = interfaces.FilterQuery{ // subscriber implements Subscriber type subscriber struct { - nodeWSURL string - nodeRPCURL string - blockchainID ids.ID - logsChan chan vmtypes.WarpLogInfo - evmLog <-chan types.Log - sub interfaces.Subscription + nodeWSEndpoint config.APIConfig + nodeRPCEndpoint config.APIConfig + blockchainID ids.ID + logsChan chan vmtypes.WarpLogInfo + evmLog <-chan types.Log + sub interfaces.Subscription logger logging.Logger // seams for mock injection: - dial func(url string) (ethclient.Client, error) + dial func(ctx context.Context, url string, httpHeaders, queryParams map[string]string) (ethclient.Client, error) } // NewSubscriber returns a subscriber @@ -74,12 +74,12 @@ func NewSubscriber(logger logging.Logger, subnetInfo config.SourceBlockchain) *s logs := make(chan vmtypes.WarpLogInfo, maxClientSubscriptionBuffer) return &subscriber{ - nodeWSURL: subnetInfo.WSEndpoint, - nodeRPCURL: subnetInfo.RPCEndpoint, - blockchainID: blockchainID, - logger: logger, - logsChan: logs, - dial: ethclient.Dial, + nodeWSEndpoint: subnetInfo.WSEndpoint, + nodeRPCEndpoint: subnetInfo.RPCEndpoint, + blockchainID: blockchainID, + logger: logger, + logsChan: logs, + dial: ethclient.DialWithConfig, } } @@ -140,7 +140,7 @@ func (s *subscriber) ProcessFromHeight(height *big.Int, done chan bool) { s.logger.Error("cannot process logs from nil height") done <- false } - ethClient, err := s.dial(s.nodeWSURL) + ethClient, err := s.dial(context.Background(), s.nodeWSEndpoint.BaseURL, s.nodeWSEndpoint.HTTPHeaders, s.nodeWSEndpoint.QueryParams) if err != nil { s.logger.Error("failed to dial eth client", zap.Error(err)) done <- false @@ -272,7 +272,7 @@ func (s *subscriber) Subscribe(maxResubscribeAttempts int) error { func (s *subscriber) dialAndSubscribe() error { // Dial the configured source chain endpoint // This needs to be a websocket - ethClient, err := s.dial(s.nodeWSURL) + ethClient, err := s.dial(context.Background(), s.nodeWSEndpoint.BaseURL, s.nodeWSEndpoint.HTTPHeaders, s.nodeWSEndpoint.QueryParams) if err != nil { return err } diff --git a/vms/evm/subscriber_test.go b/vms/evm/subscriber_test.go index cbbbe880..da1d2fc1 100644 --- a/vms/evm/subscriber_test.go +++ b/vms/evm/subscriber_test.go @@ -4,14 +4,15 @@ package evm import ( + "context" "math/big" "testing" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/ethclient" mock_ethclient "github.com/ava-labs/awm-relayer/vms/evm/mocks" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/interfaces" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -22,14 +23,18 @@ func makeSubscriberWithMockEthClient(t *testing.T) (*subscriber, *mock_ethclient SubnetID: "2TGBXcnwx5PqiXWiqxAKUaNSqDguXNh1mxnp82jui68hxJSZAx", BlockchainID: "S4mMqUXe7vHsGiRAma6bv3CKnyaLssyAxmQ2KvFpX1KEvfFCD", VM: config.EVM.String(), - RPCEndpoint: "https://subnets.avax.network/mysubnet/rpc", + RPCEndpoint: config.APIConfig{ + BaseURL: "https://subnets.avax.network/mysubnet/rpc", + }, } logger := logging.NoLog{} mockEthClient := mock_ethclient.NewMockClient(gomock.NewController(t)) subscriber := NewSubscriber(logger, sourceSubnet) - subscriber.dial = func(_url string) (ethclient.Client, error) { return mockEthClient, nil } + subscriber.dial = func(_ctx context.Context, _url string, _httpHeaders, _queryParams map[string]string) (ethclient.Client, error) { + return mockEthClient, nil + } return subscriber, mockEthClient }