diff --git a/README.md b/README.md index 2eb011a9..7828260c 100644 --- a/README.md +++ b/README.md @@ -111,23 +111,39 @@ The relayer is configured via a JSON file, the path to which is passed in via th - The log level for the relayer. Defaults to `info`. -`"p-chain-api-url": string` +`"p-chain-api": APIConfig` -- The URL of the Avalanche P-Chain API node to which the relayer will connect. This API node needs to have the following methods enabled: - - platform.getHeight - - platform.validatedBy - - platform.getValidatorsAt OR platform.getCurrentValidators +- The configuration for the Avalanche P-Chain API node. The `PChainAPI` object has the following configuration: -`"info-api-url": string` + `"base-url": string` -- The URL of the Avalanche Info API node to which the relayer will connect. This API node needs to have the following methods enabled: + - The URL of the Avalanche P-Chain API node to which the relayer will connect. This API node needs to have the following methods enabled: + - platform.getHeight + - platform.validatedBy + - platform.getValidatorsAt OR platform.getCurrentValidators + + `"query-parameters": map[string]string` + + - Additional query parameters to include in the API requests. + +`"info-api": APIConfig` + +- The configuration for the Avalanche Info API node. The `InfoAPI` object has the following configuration: + + `"base-url": string` - - info.peers - - info.getNetworkID + - The URL of the Avalanche Info API node to which the relayer will connect. This API node needs to have the following methods enabled: -- Additionally, if the Info API node is also a validator, it must have enabled: - - info.getNodeID - - info.getNodeIP + - info.peers + - info.getNetworkID + + - Additionally, if the Info API node is also a validator, it must have enabled: + - info.getNodeID + - info.getNodeIP + + `"query-parameters": map[string]string` + + - Additional query parameters to include in the API requests. `"storage-location": string` @@ -236,7 +252,7 @@ The relayer is configured via a JSON file, the path to which is passed in via th `"kms-aws-region": string` - The AWS region in which the KMS key is located. Required if `kms-key-id` is provided. - + ## Architecture ### Components diff --git a/config/config.go b/config/config.go index 6007fc24..c9c76659 100644 --- a/config/config.go +++ b/config/config.go @@ -122,16 +122,22 @@ type WarpQuorum struct { QuorumDenominator uint64 } +// API configuration containing the base URL and query parameters +type APIConfig struct { + BaseURL string `mapstructure:"base-url" json:"base-url"` + QueryParams map[string]string `mapstructure:"query-parameters" json:"query-parameters"` +} + // Top-level configuration type Config struct { LogLevel string `mapstructure:"log-level" json:"log-level"` - PChainAPIURL string `mapstructure:"p-chain-api-url" json:"p-chain-api-url"` - InfoAPIURL string `mapstructure:"info-api-url" json:"info-api-url"` StorageLocation string `mapstructure:"storage-location" json:"storage-location"` RedisURL string `mapstructure:"redis-url" json:"redis-url"` APIPort uint16 `mapstructure:"api-port" json:"api-port"` MetricsPort uint16 `mapstructure:"metrics-port" json:"metrics-port"` + PChainAPI *APIConfig `mapstructure:"p-chain-api" json:"p-chain-api"` + InfoAPI *APIConfig `mapstructure:"info-api" json:"info-api"` SourceBlockchains []*SourceBlockchain `mapstructure:"source-blockchains" json:"source-blockchains"` DestinationBlockchains []*DestinationBlockchain `mapstructure:"destination-blockchains" json:"destination-blockchains"` ProcessMissedBlocks bool `mapstructure:"process-missed-blocks" json:"process-missed-blocks"` @@ -172,13 +178,17 @@ func BuildConfig(v *viper.Viper) (Config, bool, error) { ) cfg.LogLevel = v.GetString(LogLevelKey) - cfg.PChainAPIURL = v.GetString(PChainAPIURLKey) - cfg.InfoAPIURL = v.GetString(InfoAPIURLKey) cfg.StorageLocation = v.GetString(StorageLocationKey) cfg.RedisURL = v.GetString(RedisURLKey) cfg.ProcessMissedBlocks = v.GetBool(ProcessMissedBlocksKey) cfg.APIPort = v.GetUint16(APIPortKey) cfg.MetricsPort = v.GetUint16(MetricsPortKey) + if err := v.UnmarshalKey(PChainAPIKey, &cfg.PChainAPI); err != nil { + return Config{}, false, fmt.Errorf("failed to unmarshal P-Chain API: %w", err) + } + if err := v.UnmarshalKey(InfoAPIKey, &cfg.InfoAPI); err != nil { + return Config{}, false, fmt.Errorf("failed to unmarshal Info API: %w", err) + } if err := v.UnmarshalKey(ManualWarpMessagesKey, &cfg.ManualWarpMessages); err != nil { return Config{}, false, fmt.Errorf("failed to unmarshal manual warp messages: %w", err) } @@ -230,10 +240,10 @@ func (c *Config) Validate() error { if len(c.DestinationBlockchains) == 0 { return errors.New("relayer not configured to relay to any subnets. A list of destination subnets must be provided in the configuration file") } - if _, err := url.ParseRequestURI(c.PChainAPIURL); err != nil { + if err := c.PChainAPI.Validate(); err != nil { return err } - if _, err := url.ParseRequestURI(c.InfoAPIURL); err != nil { + if err := c.InfoAPI.Validate(); err != nil { return err } @@ -408,6 +418,13 @@ func (c *Config) InitializeWarpQuorums() error { return nil } +func (c *APIConfig) Validate() error { + if _, err := url.ParseRequestURI(c.BaseURL); err != nil { + return fmt.Errorf("invalid base URL: %w", err) + } + return nil +} + // Validates the source subnet configuration, including verifying that the supported destinations are present in destinationBlockchainIDs // Does not modify the public fields as derived from the configuration passed to the application, // but does initialize private fields available through getters diff --git a/config/keys.go b/config/keys.go index ca5808b6..316445d0 100644 --- a/config/keys.go +++ b/config/keys.go @@ -7,8 +7,8 @@ package config const ( ConfigFileKey = "config-file" LogLevelKey = "log-level" - PChainAPIURLKey = "p-chain-api-url" - InfoAPIURLKey = "info-api-url" + PChainAPIKey = "p-chain-api" + InfoAPIKey = "info-api" APIPortKey = "api-port" MetricsPortKey = "metrics-port" SourceBlockchainsKey = "source-blockchains" diff --git a/config/test_utils.go b/config/test_utils.go index 40fe0ec4..e95f794d 100644 --- a/config/test_utils.go +++ b/config/test_utils.go @@ -11,14 +11,23 @@ var ( testAddress string = "0xd81545385803bCD83bd59f58Ba2d2c0562387F83" testPk1 string = "0xabc89e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8abc" testPk2 string = "0x12389e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8123" + queryParamKey1 string = "key1" + queryParamVal1 string = "val1" ) // Valid configuration objects to be used by tests in external packages var ( TestValidConfig = Config{ - LogLevel: "info", - PChainAPIURL: "http://test.avax.network", - InfoAPIURL: "http://test.avax.network", + LogLevel: "info", + PChainAPI: &APIConfig{ + BaseURL: "http://test.avax.network", + QueryParams: map[string]string{ + queryParamKey1: queryParamVal1, + }, + }, + InfoAPI: &APIConfig{ + BaseURL: "http://test.avax.network", + }, SourceBlockchains: []*SourceBlockchain{ { RPCEndpoint: fmt.Sprintf("http://test.avax.network/ext/bc/%s/rpc", testBlockchainID), diff --git a/main/main.go b/main/main.go index fa4759f2..8f045339 100644 --- a/main/main.go +++ b/main/main.go @@ -12,13 +12,11 @@ import ( "os" "github.com/alexliesenfeld/health" - "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/api/metrics" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/message" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/awm-relayer/config" "github.com/ava-labs/awm-relayer/database" "github.com/ava-labs/awm-relayer/peers" @@ -70,10 +68,6 @@ func main() { } logger.Info(fmt.Sprintf("Set config options.%s", overwrittenLog)) - // Global P-Chain and Info clients used to get subnet validator sets - pChainClient := platformvm.NewClient(cfg.PChainAPIURL) - infoClient := info.NewClient(cfg.InfoAPIURL) - // Initialize all destination clients logger.Info("Initializing destination clients") destinationClients, err := vms.CreateDestinationClients(logger, cfg) @@ -106,8 +100,6 @@ func main() { networkLogLevel, registerer, &cfg, - infoClient, - pChainClient, ) if err != nil { logger.Error( @@ -214,7 +206,6 @@ func main() { metrics, db, *subnetInfo, - pChainClient, network, responseChans[blockchainID], destinationClients, @@ -239,7 +230,6 @@ func runRelayer( metrics *relayer.ApplicationRelayerMetrics, db database.RelayerDatabase, sourceSubnetInfo config.SourceBlockchain, - pChainClient platformvm.Client, network *peers.AppRequestNetwork, responseChan chan message.InboundMessage, destinationClients map[ids.ID]vms.DestinationClient, @@ -258,7 +248,6 @@ func runRelayer( metrics, db, sourceSubnetInfo, - pChainClient, network, responseChan, destinationClients, diff --git a/peers/app_request_network.go b/peers/app_request_network.go index cee48d09..8fe1b803 100644 --- a/peers/app_request_network.go +++ b/peers/app_request_network.go @@ -10,7 +10,6 @@ import ( "sync" "time" - "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/message" "github.com/ava-labs/avalanchego/network" @@ -19,11 +18,10 @@ import ( "github.com/ava-labs/avalanchego/utils/ips" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/peers/validators" "github.com/ava-labs/awm-relayer/utils" - "github.com/ava-labs/awm-relayer/validators" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" ) @@ -36,7 +34,7 @@ const ( type AppRequestNetwork struct { Network network.Network Handler *RelayerExternalHandler - infoClient info.Client + infoAPI *InfoAPI logger logging.Logger lock *sync.Mutex validatorClient *validators.CanonicalValidatorClient @@ -47,8 +45,6 @@ func NewNetwork( logLevel logging.Level, registerer prometheus.Registerer, cfg *config.Config, - infoClient info.Client, - pChainClient platformvm.Client, ) (*AppRequestNetwork, map[ids.ID]chan message.InboundMessage, error) { logger := logging.NewLogger( "awm-relayer-p2p", @@ -59,15 +55,6 @@ func NewNetwork( ), ) - networkID, err := infoClient.GetNetworkID(context.Background()) - if err != nil { - logger.Error( - "Failed to get network ID", - zap.Error(err), - ) - return nil, nil, err - } - // Create the test network for AppRequests var trackedSubnets set.Set[ids.ID] for _, sourceBlockchain := range cfg.SourceBlockchains { @@ -91,6 +78,23 @@ func NewNetwork( return nil, nil, err } + infoAPI, err := NewInfoAPI(cfg.InfoAPI) + if err != nil { + logger.Error( + "Failed to create info API", + zap.Error(err), + ) + return nil, nil, err + } + networkID, err := infoAPI.GetNetworkID(context.Background()) + if err != nil { + logger.Error( + "Failed to get network ID", + zap.Error(err), + ) + return nil, nil, err + } + testNetwork, err := network.NewTestNetwork(logger, networkID, snowVdrs.NewManager(), trackedSubnets, handler) if err != nil { logger.Error( @@ -100,12 +104,12 @@ func NewNetwork( return nil, nil, err } - validatorClient := validators.NewCanonicalValidatorClient(logger, pChainClient) + validatorClient := validators.NewCanonicalValidatorClient(logger, cfg.PChainAPI) arNetwork := &AppRequestNetwork{ Network: testNetwork, Handler: handler, - infoClient: infoClient, + infoAPI: infoAPI, logger: logger, lock: new(sync.Mutex), validatorClient: validatorClient, @@ -152,7 +156,7 @@ func (n *AppRequestNetwork) ConnectPeers(nodeIDs set.Set[ids.NodeID]) set.Set[id // re-adding connections to already tracked peers. // Get the list of peers - peers, err := n.infoClient.Peers(context.Background()) + peers, err := n.infoAPI.Peers(context.Background()) if err != nil { n.logger.Error( "Failed to get peers", @@ -184,13 +188,13 @@ func (n *AppRequestNetwork) ConnectPeers(nodeIDs set.Set[ids.NodeID]) set.Set[id // If the Info API node is in nodeIDs, it will not be reflected in the call to info.Peers. // In this case, we need to manually track the API node. - if apiNodeID, _, err := n.infoClient.GetNodeID(context.Background()); err != nil { + if apiNodeID, _, err := n.infoAPI.GetNodeID(context.Background()); err != nil { n.logger.Error( "Failed to get API Node ID", zap.Error(err), ) } else if nodeIDs.Contains(apiNodeID) { - if apiNodeIP, err := n.infoClient.GetNodeIP(context.Background()); err != nil { + if apiNodeIP, err := n.infoAPI.GetNodeIP(context.Background()); err != nil { n.logger.Error( "Failed to get API Node IP", zap.Error(err), diff --git a/peers/info_client.go b/peers/info_client.go new file mode 100644 index 00000000..2d6358c4 --- /dev/null +++ b/peers/info_client.go @@ -0,0 +1,76 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package peers + +import ( + "context" + + "github.com/ava-labs/avalanchego/api/info" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/rpc" + "github.com/ava-labs/avalanchego/vms/platformvm/signer" + "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/peers/utils" +) + +// InfoAPI is a wrapper around the info.Client, +// and provides additional options for the API +// passed in the config. +type InfoAPI struct { + client info.Client + options []rpc.Option +} + +func NewInfoAPI(apiConfig *config.APIConfig) (*InfoAPI, error) { + client := info.NewClient(apiConfig.BaseURL) + options := utils.InitializeOptions(apiConfig) + return &InfoAPI{ + client: client, + options: options, + }, nil +} + +func (i *InfoAPI) GetBlockchainID(ctx context.Context, alias string) (ids.ID, error) { + return i.client.GetBlockchainID(ctx, alias, i.options...) +} + +func (i *InfoAPI) GetNetworkID(ctx context.Context) (uint32, error) { + return i.client.GetNetworkID(ctx, i.options...) +} + +func (i *InfoAPI) GetNetworkName(ctx context.Context) (string, error) { + return i.client.GetNetworkName(ctx, i.options...) +} + +func (i *InfoAPI) GetNodeID(ctx context.Context) (ids.NodeID, *signer.ProofOfPossession, error) { + return i.client.GetNodeID(ctx, i.options...) +} + +func (i *InfoAPI) GetNodeIP(ctx context.Context) (string, error) { + return i.client.GetNodeIP(ctx, i.options...) +} + +func (i *InfoAPI) GetNodeVersion(ctx context.Context) (*info.GetNodeVersionReply, error) { + return i.client.GetNodeVersion(ctx, i.options...) +} + +func (i *InfoAPI) GetTxFee(ctx context.Context) (*info.GetTxFeeResponse, error) { + return i.client.GetTxFee(ctx, i.options...) +} + +func (i *InfoAPI) GetVMs(ctx context.Context) (map[ids.ID][]string, error) { + return i.client.GetVMs(ctx, i.options...) +} + +func (i *InfoAPI) IsBootstrapped(ctx context.Context, chainID string) (bool, error) { + return i.client.IsBootstrapped(ctx, chainID, i.options...) +} + +func (i *InfoAPI) Peers(ctx context.Context) ([]info.Peer, error) { + return i.client.Peers(ctx, i.options...) +} + +func (i *InfoAPI) Uptime(ctx context.Context, subnetID ids.ID) (*info.UptimeResponse, error) { + return i.client.Uptime(ctx, subnetID, i.options...) +} diff --git a/peers/utils/utils.go b/peers/utils/utils.go new file mode 100644 index 00000000..ed713f9c --- /dev/null +++ b/peers/utils/utils.go @@ -0,0 +1,18 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package utils + +import ( + "github.com/ava-labs/avalanchego/utils/rpc" + "github.com/ava-labs/awm-relayer/config" +) + +// InitializeOptions initializes the rpc options for an API +func InitializeOptions(apiConfig *config.APIConfig) []rpc.Option { + options := make([]rpc.Option, 0, len(apiConfig.QueryParams)) + for key, value := range apiConfig.QueryParams { + options = append(options, rpc.WithQueryParam(key, value)) + } + return options +} diff --git a/validators/canonical_validator_client.go b/peers/validators/canonical_validator_client.go similarity index 87% rename from validators/canonical_validator_client.go rename to peers/validators/canonical_validator_client.go index ccf44b03..225638bc 100644 --- a/validators/canonical_validator_client.go +++ b/peers/validators/canonical_validator_client.go @@ -9,8 +9,11 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/utils/rpc" "github.com/ava-labs/avalanchego/vms/platformvm" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/awm-relayer/config" + "github.com/ava-labs/awm-relayer/peers/utils" "go.uber.org/zap" ) @@ -18,14 +21,18 @@ var _ validators.State = &CanonicalValidatorClient{} // CanonicalValidatorClient wraps platformvm.Client and implements validators.State type CanonicalValidatorClient struct { - client platformvm.Client - logger logging.Logger + logger logging.Logger + client platformvm.Client + options []rpc.Option } -func NewCanonicalValidatorClient(logger logging.Logger, client platformvm.Client) *CanonicalValidatorClient { +func NewCanonicalValidatorClient(logger logging.Logger, apiConfig *config.APIConfig) *CanonicalValidatorClient { + client := platformvm.NewClient(apiConfig.BaseURL) + options := utils.InitializeOptions(apiConfig) return &CanonicalValidatorClient{ - client: client, - logger: logger, + logger: logger, + client: client, + options: options, } } @@ -59,15 +66,37 @@ func (v *CanonicalValidatorClient) GetCurrentCanonicalValidatorSet(subnetID ids. } func (v *CanonicalValidatorClient) GetMinimumHeight(ctx context.Context) (uint64, error) { - return v.client.GetHeight(ctx) + return v.client.GetHeight(ctx, v.options...) } func (v *CanonicalValidatorClient) GetCurrentHeight(ctx context.Context) (uint64, error) { - return v.client.GetHeight(ctx) + return v.client.GetHeight(ctx, v.options...) } func (v *CanonicalValidatorClient) GetSubnetID(ctx context.Context, blockchainID ids.ID) (ids.ID, error) { - return v.client.ValidatedBy(ctx, blockchainID) + return v.client.ValidatedBy(ctx, blockchainID, v.options...) +} + +// Gets the validator set of the given subnet at the given P-chain block height. +// Attempts to use the "getValidatorsAt" API first. If not available, falls back +// to use "getCurrentValidators", ignoring the specified P-chain block height. +func (v *CanonicalValidatorClient) GetValidatorSet( + ctx context.Context, + height uint64, + subnetID ids.ID, +) (map[ids.NodeID]*validators.GetValidatorOutput, error) { + // First, attempt to use the "getValidatorsAt" RPC method. This method may not be available on + // all API nodes, in which case we can fall back to using "getCurrentValidators" if needed. + res, err := v.client.GetValidatorsAt(ctx, subnetID, height, v.options...) + if err != nil { + v.logger.Debug( + "P-chain RPC to getValidatorAt returned error. Falling back to getCurrentValidators", + zap.String("subnetID", subnetID.String()), + zap.Uint64("pChainHeight", height), + zap.Error(err)) + return v.getCurrentValidatorSet(ctx, subnetID) + } + return res, nil } // Gets the current validator set of the given subnet ID, including the validators' BLS public @@ -84,7 +113,7 @@ func (v *CanonicalValidatorClient) getCurrentValidatorSet( // Get the current subnet validators. These validators are not expected to include // BLS signing information given that addPermissionlessValidatorTx is only used to // add primary network validators. - subnetVdrs, err := v.client.GetCurrentValidators(ctx, subnetID, nil) + subnetVdrs, err := v.client.GetCurrentValidators(ctx, subnetID, nil, v.options...) if err != nil { return nil, err } @@ -100,7 +129,7 @@ func (v *CanonicalValidatorClient) getCurrentValidatorSet( Weight: subnetVdr.Weight, } } - primaryVdrs, err := v.client.GetCurrentValidators(ctx, ids.Empty, subnetNodeIDs) + primaryVdrs, err := v.client.GetCurrentValidators(ctx, ids.Empty, subnetNodeIDs, v.options...) if err != nil { return nil, err } @@ -131,25 +160,3 @@ func (v *CanonicalValidatorClient) getCurrentValidatorSet( return res, nil } - -// Gets the validator set of the given subnet at the given P-chain block height. -// Attempts to use the "getValidatorsAt" API first. If not available, falls back -// to use "getCurrentValidators", ignoring the specified P-chain block height. -func (v *CanonicalValidatorClient) GetValidatorSet( - ctx context.Context, - height uint64, - subnetID ids.ID, -) (map[ids.NodeID]*validators.GetValidatorOutput, error) { - // First, attempt to use the "getValidatorsAt" RPC method. This method may not be available on - // all API nodes, in which case we can fall back to using "getCurrentValidators" if needed. - res, err := v.client.GetValidatorsAt(ctx, subnetID, height) - if err != nil { - v.logger.Debug( - "P-chain RPC to getValidatorAt returned error. Falling back to getCurrentValidators", - zap.String("subnetID", subnetID.String()), - zap.Uint64("pChainHeight", height), - zap.Error(err)) - return v.getCurrentValidatorSet(ctx, subnetID) - } - return res, nil -} diff --git a/relayer/listener.go b/relayer/listener.go index edecb0e8..b03a04cc 100644 --- a/relayer/listener.go +++ b/relayer/listener.go @@ -13,7 +13,6 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/message" "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/awm-relayer/config" "github.com/ava-labs/awm-relayer/database" "github.com/ava-labs/awm-relayer/messages" @@ -35,7 +34,6 @@ const ( // Listener handles all messages sent from a given source chain type Listener struct { Subscriber vms.Subscriber - pChainClient platformvm.Client currentRequestID uint32 responseChan chan message.InboundMessage contractMessage vms.ContractMessage @@ -53,7 +51,6 @@ func NewListener( metrics *ApplicationRelayerMetrics, db database.RelayerDatabase, sourceBlockchain config.SourceBlockchain, - pChainClient platformvm.Client, network *peers.AppRequestNetwork, responseChan chan message.InboundMessage, destinationClients map[ids.ID]vms.DestinationClient, @@ -120,7 +117,6 @@ func NewListener( ) lstnr := Listener{ Subscriber: sub, - pChainClient: pChainClient, currentRequestID: rand.Uint32(), // Initialize to a random value to mitigate requestID collision responseChan: responseChan, contractMessage: vms.NewContractMessage(logger, sourceBlockchain), diff --git a/sample-relayer-config.json b/sample-relayer-config.json index 0880457c..9f2d0254 100644 --- a/sample-relayer-config.json +++ b/sample-relayer-config.json @@ -1,6 +1,10 @@ { - "info-api-url": "https://api.avax-test.network", - "p-chain-api-url": "https://api.avax-test.network", + "info-api": { + "base-url": "https://api.avax-test.network" + }, + "p-chain-api": { + "base-url": "https://api.avax-test.network" + }, "source-blockchains": [ { "subnet-id": "11111111111111111111111111111111LpoYY", @@ -22,9 +26,9 @@ { "subnet-id": "7WtoAMPhrmh5KosDUsFL9yTcvw7YSxiKHPpdfs4JsgW47oZT5", "blockchain-id": "2D8RG4UpSXbPbvPCAWppNJyqTG2i2CAXSkTgmTBBvs7GKNZjsY", - "vm":"evm", + "vm": "evm", "rpc-endpoint": "https://subnets.avax.network/dispatch/testnet/rpc", "account-private-key": "0x7493..." } ] -} \ No newline at end of file +} diff --git a/tests/utils/utils.go b/tests/utils/utils.go index 27cc7b62..1ee442ad 100644 --- a/tests/utils/utils.go +++ b/tests/utils/utils.go @@ -166,9 +166,13 @@ func CreateDefaultRelayerConfig( } return config.Config{ - LogLevel: logging.Info.LowerString(), - PChainAPIURL: sourceSubnetsInfo[0].NodeURIs[0], - InfoAPIURL: sourceSubnetsInfo[0].NodeURIs[0], + LogLevel: logging.Info.LowerString(), + PChainAPI: &config.APIConfig{ + BaseURL: sourceSubnetsInfo[0].NodeURIs[0], + }, + InfoAPI: &config.APIConfig{ + BaseURL: sourceSubnetsInfo[0].NodeURIs[0], + }, StorageLocation: StorageLocation, ProcessMissedBlocks: false, SourceBlockchains: sources,