Skip to content

Commit

Permalink
Merge pull request #268 from ava-labs/query-params
Browse files Browse the repository at this point in the history
Pchain/Info API query params
  • Loading branch information
cam-schultz authored Apr 29, 2024
2 parents cfacbb6 + 9caceb5 commit 366a137
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 98 deletions.
42 changes: 29 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down Expand Up @@ -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
Expand Down
29 changes: 23 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions config/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
15 changes: 12 additions & 3 deletions config/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
11 changes: 0 additions & 11 deletions main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -106,8 +100,6 @@ func main() {
networkLogLevel,
registerer,
&cfg,
infoClient,
pChainClient,
)
if err != nil {
logger.Error(
Expand Down Expand Up @@ -214,7 +206,6 @@ func main() {
metrics,
db,
*subnetInfo,
pChainClient,
network,
responseChans[blockchainID],
destinationClients,
Expand All @@ -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,
Expand All @@ -258,7 +248,6 @@ func runRelayer(
metrics,
db,
sourceSubnetInfo,
pChainClient,
network,
responseChan,
destinationClients,
Expand Down
44 changes: 24 additions & 20 deletions peers/app_request_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
)
Expand All @@ -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
Expand All @@ -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",
Expand All @@ -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 {
Expand All @@ -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(
Expand All @@ -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,
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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),
Expand Down
Loading

0 comments on commit 366a137

Please sign in to comment.