Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

use warpRequirePrimaryNetworkSigners config #537

Merged
merged 8 commits into from
Nov 22, 2024
17 changes: 14 additions & 3 deletions relayer/application_relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,21 @@ func NewApplicationRelayer(
)
return nil, err
}
requirePrimaryNetworkSigners, err := cfg.GetWarpRequirePrimaryNetworkSigners(relayerID.DestinationBlockchainID)
// this shouldn't be reachable since if we found a quorum, we should also find the requirePrimaryNetworkSigners
// but leaving the check for completeness
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's probably an indication we should be able to fetch them from the config together?

I also agree with your comment that the current WarpQuorum object is unnecessary. We can just use a uint for QuorumPercentage, or have WarpQuorum contain the percentage and requirePrimaryNetworkSigners

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with the latter route and renamed it to WarpConfig. It's basically identical to the source WarpConfig defined in subnet-evm but doesn't implement the Upgrade interface and when converting it we populate it with warpDefaultQuorumNumerator value if it's 0

if err != nil {
logger.Error(
"Failed to get warp primary network configuration from config.",
zap.String("destinationBlockchainID", relayerID.DestinationBlockchainID.String()),
zap.Error(err),
)
return nil, err
}
var signingSubnet ids.ID
if sourceBlockchain.GetSubnetID() == constants.PrimaryNetworkID {
// If the message originates from the primary subnet, then we instead "self sign"
// the message using the validators of the destination subnet.
if sourceBlockchain.GetSubnetID() == constants.PrimaryNetworkID && !requirePrimaryNetworkSigners {
// If the message originates from the primary subnet, and the primary network is validated by
// the destination change we can "self-sign" the message using the validators of the destination subnet.
iansuvak marked this conversation as resolved.
Show resolved Hide resolved
signingSubnet = cfg.GetSubnetID(relayerID.DestinationBlockchainID)
} else {
// Otherwise, the source subnet signs the message.
Expand Down
56 changes: 26 additions & 30 deletions relayer/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/ava-labs/awm-relayer/peers"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/set"

Expand Down Expand Up @@ -156,31 +155,25 @@ func (c *Config) GetSubnetID(blockchainID ids.ID) ids.ID {
}

// If the numerator in the Warp config is 0, use the default value
func calculateQuorumNumerator(cfgNumerator uint64) uint64 {
func calculateQuorum(cfgNumerator uint64) WarpQuorum {
if cfgNumerator == 0 {
return warp.WarpDefaultQuorumNumerator
}
return cfgNumerator
}

// Helper to retrieve the Warp Quorum from the chain config.
// Differentiates between subnet-evm and coreth RPC internally
func getWarpQuorum(
subnetID ids.ID,
blockchainID ids.ID,
client ethclient.Client,
) (WarpQuorum, error) {
if subnetID == constants.PrimaryNetworkID {
return WarpQuorum{
QuorumNumerator: warp.WarpDefaultQuorumNumerator,
QuorumDenominator: warp.WarpQuorumDenominator,
}, nil
}
} else {
return WarpQuorum{
QuorumNumerator: cfgNumerator,
QuorumDenominator: warp.WarpQuorumDenominator,
}
}
iansuvak marked this conversation as resolved.
Show resolved Hide resolved
}

func getWarpConfig(client ethclient.Client) (*warp.Config, error) {
// Fetch the subnet's chain config
chainConfig, err := client.ChainConfig(context.Background())
if err != nil {
return WarpQuorum{}, fmt.Errorf("failed to fetch chain config for blockchain %s: %w", blockchainID, err)
return nil, fmt.Errorf("failed to fetch chain config")
}

// First, check the list of precompile upgrades to get the most up to date Warp config
Expand All @@ -202,27 +195,21 @@ func getWarpQuorum(
}
}
if warpConfig != nil {
return WarpQuorum{
QuorumNumerator: calculateQuorumNumerator(warpConfig.QuorumNumerator),
QuorumDenominator: warp.WarpQuorumDenominator,
}, nil
return warpConfig, nil
}

// If we didn't find the Warp config in the upgrade precompile list, check the genesis config
warpConfig, ok := chainConfig.GenesisPrecompiles[warpConfigKey].(*warp.Config)
if ok {
return WarpQuorum{
QuorumNumerator: calculateQuorumNumerator(warpConfig.QuorumNumerator),
QuorumDenominator: warp.WarpQuorumDenominator,
}, nil
if !ok {
return nil, fmt.Errorf("no Warp config found in chain config")
}
return WarpQuorum{}, fmt.Errorf("failed to find warp config for blockchain %s", blockchainID)
return warpConfig, nil
}

func (c *Config) InitializeWarpQuorums() error {
// Initializes Warp configurations (quorum and self-signing settings) for each destination subnet
func (c *Config) InitializeWarpConfigs() error {
// Fetch the Warp quorum values for each destination subnet.
for _, destinationSubnet := range c.DestinationBlockchains {
err := destinationSubnet.initializeWarpQuorum()
err := destinationSubnet.initializeWarpConfigs()
if err != nil {
return fmt.Errorf(
"failed to initialize Warp quorum for destination subnet %s: %w",
Expand Down Expand Up @@ -256,6 +243,15 @@ func (c *Config) GetWarpQuorum(blockchainID ids.ID) (WarpQuorum, error) {
return WarpQuorum{}, errFailedToGetWarpQuorum
}

func (c *Config) GetWarpRequirePrimaryNetworkSigners(blockchainID ids.ID) (bool, error) {
for _, s := range c.DestinationBlockchains {
if blockchainID.String() == s.BlockchainID {
return s.warpRequirePrimaryNetworkSigners, nil
}
}
iansuvak marked this conversation as resolved.
Show resolved Hide resolved
return false, errFailedToGetWarpQuorum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this error should say anything about the Warp Quorum. We error here iff the destination blockchain is in the config.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the wording to indicate that the blockchainID is not in the destination blockchains. Thanks!

}

var _ peers.Config = &Config{}

func (c *Config) GetPChainAPI() *basecfg.APIConfig {
Expand Down
80 changes: 60 additions & 20 deletions relayer/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,32 +242,22 @@ func TestEitherKMSOrAccountPrivateKey(t *testing.T) {
}
}

func TestGetWarpQuorum(t *testing.T) {
func TestGetWarpConfig(t *testing.T) {
blockchainID, err := ids.FromString("p433wpuXyJiDhyazPYyZMJeaoPSW76CBZ2x7wrVPLgvokotXz")
require.NoError(t, err)
subnetID, err := ids.FromString("2PsShLjrFFwR51DMcAh8pyuwzLn1Ym3zRhuXLTmLCR1STk2mL6")
require.NoError(t, err)

testCases := []struct {
name string
blockchainID ids.ID
subnetID ids.ID
chainConfig params.ChainConfigWithUpgradesJSON
getChainConfigCalls int
expectedError error
expectedQuorum WarpQuorum
name string
blockchainID ids.ID
subnetID ids.ID
chainConfig params.ChainConfigWithUpgradesJSON
getChainConfigCalls int
expectedError error
expectedQuorum WarpQuorum
expectedRequirePrimaryNeworkSigners bool
}{
{
name: "primary network",
blockchainID: blockchainID,
subnetID: ids.Empty,
getChainConfigCalls: 0,
expectedError: nil,
expectedQuorum: WarpQuorum{
QuorumNumerator: warp.WarpDefaultQuorumNumerator,
QuorumDenominator: warp.WarpQuorumDenominator,
},
},
{
name: "subnet genesis precompile",
blockchainID: blockchainID,
Expand All @@ -287,6 +277,7 @@ func TestGetWarpQuorum(t *testing.T) {
QuorumNumerator: warp.WarpDefaultQuorumNumerator,
QuorumDenominator: warp.WarpQuorumDenominator,
},
expectedRequirePrimaryNeworkSigners: false,
},
{
name: "subnet genesis precompile non-default",
Expand All @@ -307,6 +298,7 @@ func TestGetWarpQuorum(t *testing.T) {
QuorumNumerator: 50,
QuorumDenominator: warp.WarpQuorumDenominator,
},
expectedRequirePrimaryNeworkSigners: false,
},
{
name: "subnet upgrade precompile",
Expand All @@ -329,6 +321,7 @@ func TestGetWarpQuorum(t *testing.T) {
QuorumNumerator: warp.WarpDefaultQuorumNumerator,
QuorumDenominator: warp.WarpQuorumDenominator,
},
expectedRequirePrimaryNeworkSigners: false,
},
{
name: "subnet upgrade precompile non-default",
Expand All @@ -351,6 +344,51 @@ func TestGetWarpQuorum(t *testing.T) {
QuorumNumerator: 50,
QuorumDenominator: warp.WarpQuorumDenominator,
},
expectedRequirePrimaryNeworkSigners: false,
},
{
name: "require primary network signers",
blockchainID: blockchainID,
subnetID: subnetID,
getChainConfigCalls: 1,
chainConfig: params.ChainConfigWithUpgradesJSON{
ChainConfig: params.ChainConfig{
GenesisPrecompiles: params.Precompiles{
warpConfigKey: &warp.Config{
QuorumNumerator: 0,
RequirePrimaryNetworkSigners: true,
},
},
},
},
expectedError: nil,
expectedQuorum: WarpQuorum{
QuorumNumerator: warp.WarpDefaultQuorumNumerator,
QuorumDenominator: warp.WarpQuorumDenominator,
},
expectedRequirePrimaryNeworkSigners: true,
},
{
name: "require primary network signers explicit false",
blockchainID: blockchainID,
subnetID: subnetID,
getChainConfigCalls: 1,
chainConfig: params.ChainConfigWithUpgradesJSON{
ChainConfig: params.ChainConfig{
GenesisPrecompiles: params.Precompiles{
warpConfigKey: &warp.Config{
QuorumNumerator: 0,
RequirePrimaryNetworkSigners: false,
},
},
},
},
expectedError: nil,
expectedQuorum: WarpQuorum{
QuorumNumerator: warp.WarpDefaultQuorumNumerator,
QuorumDenominator: warp.WarpQuorumDenominator,
},
expectedRequirePrimaryNeworkSigners: false,
},
}

Expand All @@ -364,9 +402,11 @@ func TestGetWarpQuorum(t *testing.T) {
).Times(testCase.getChainConfigCalls),
)

quorum, err := getWarpQuorum(testCase.subnetID, testCase.blockchainID, client)
warpConfig, err := getWarpConfig(client)
require.Equal(t, testCase.expectedError, err)
quorum := calculateQuorum(warpConfig.QuorumNumerator)
require.Equal(t, testCase.expectedQuorum, quorum)
require.Equal(t, testCase.expectedRequirePrimaryNeworkSigners, warpConfig.RequirePrimaryNetworkSigners)
})
}
}
Expand Down
26 changes: 19 additions & 7 deletions relayer/config/destination_blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (
"fmt"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
basecfg "github.com/ava-labs/awm-relayer/config"
"github.com/ava-labs/awm-relayer/utils"
"github.com/ava-labs/subnet-evm/precompile/contracts/warp"
"github.com/ethereum/go-ethereum/crypto"
)

Expand All @@ -23,7 +25,8 @@ type DestinationBlockchain struct {
AccountPrivateKey string `mapstructure:"account-private-key" json:"account-private-key"`

// Fetched from the chain after startup
warpQuorum WarpQuorum
warpQuorum WarpQuorum
warpRequirePrimaryNetworkSigners bool

// convenience fields to access parsed data after initialization
subnetID ids.ID
Expand Down Expand Up @@ -77,7 +80,7 @@ func (s *DestinationBlockchain) GetBlockchainID() ids.ID {
return s.blockchainID
}

func (s *DestinationBlockchain) initializeWarpQuorum() error {
func (s *DestinationBlockchain) initializeWarpConfigs() error {
blockchainID, err := ids.FromString(s.BlockchainID)
if err != nil {
return fmt.Errorf("invalid blockchainID in configuration. error: %w", err)
Expand All @@ -86,23 +89,32 @@ func (s *DestinationBlockchain) initializeWarpQuorum() error {
if err != nil {
return fmt.Errorf("invalid subnetID in configuration. error: %w", err)
}
// If the destination blockchain is the primary network, use the default quorum
// primary network signers here are irrelevant and can be left at default value
if subnetID == constants.PrimaryNetworkID {
s.warpQuorum = WarpQuorum{
QuorumNumerator: warp.WarpDefaultQuorumNumerator,
QuorumDenominator: warp.WarpQuorumDenominator,
}
return nil
}

client, err := utils.NewEthClientWithConfig(
context.Background(),
s.RPCEndpoint.BaseURL,
s.RPCEndpoint.HTTPHeaders,
s.RPCEndpoint.QueryParams,
)
defer client.Close()
if err != nil {
return fmt.Errorf("failed to dial destination blockchain %s: %w", blockchainID, err)
}
defer client.Close()
quorum, err := getWarpQuorum(subnetID, blockchainID, client)
warpConfig, err := getWarpConfig(client)
if err != nil {
return fmt.Errorf("failed to fetch warp quorum for subnet %s: %w", subnetID, err)
return fmt.Errorf("failed to fetch warp config for blockchain %s: %w", blockchainID, err)
}

s.warpQuorum = quorum
s.warpQuorum = calculateQuorum(warpConfig.QuorumNumerator)
s.warpRequirePrimaryNetworkSigners = warpConfig.RequirePrimaryNetworkSigners
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion relayer/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func main() {
}
// Initialize the Warp Quorum values by fetching via RPC
// We do this here so that BuildConfig doesn't need to make RPC calls
if err = cfg.InitializeWarpQuorums(); err != nil {
if err = cfg.InitializeWarpConfigs(); err != nil {
panic(fmt.Errorf("couldn't initialize warp quorums: %w", err))
}

Expand Down