Skip to content

Commit

Permalink
Update tmpnet fixture to include Proof-of-Possession for initial stak…
Browse files Browse the repository at this point in the history
…ers (#2391)
  • Loading branch information
marun authored Dec 11, 2023
1 parent d2457c5 commit 159aafb
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 46 deletions.
73 changes: 34 additions & 39 deletions tests/fixture/tmpnet/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/ava-labs/avalanchego/utils/formatting/address"
"github.com/ava-labs/avalanchego/utils/perms"
"github.com/ava-labs/avalanchego/utils/units"
"github.com/ava-labs/avalanchego/vms/platformvm/reward"
"github.com/ava-labs/avalanchego/vms/platformvm/signer"
)

const (
Expand All @@ -49,14 +49,13 @@ var (
// Arbitrarily large amount of AVAX (10^12) to fund keys on the C-Chain for testing
DefaultFundedKeyCChainAmount = new(big.Int).Exp(big.NewInt(10), big.NewInt(30), nil)

errEmptyValidatorsForGenesis = errors.New("failed to generate genesis: empty validator IDs")
errNoKeysForGenesis = errors.New("failed to generate genesis: no keys to fund")
errInvalidNetworkIDForGenesis = errors.New("network ID can't be mainnet, testnet or local network ID")
errMissingValidatorsForGenesis = errors.New("no genesis validators provided")
errMissingBalancesForGenesis = errors.New("no genesis balances given")
errMissingTLSKeyForNodeID = fmt.Errorf("failed to ensure node ID: missing value for %q", config.StakingTLSKeyContentKey)
errMissingCertForNodeID = fmt.Errorf("failed to ensure node ID: missing value for %q", config.StakingCertContentKey)
errInvalidKeypair = fmt.Errorf("%q and %q must be provided together or not at all", config.StakingTLSKeyContentKey, config.StakingCertContentKey)
errNoKeysForGenesis = errors.New("failed to generate genesis: no keys to fund")
errInvalidNetworkIDForGenesis = errors.New("network ID can't be mainnet, testnet or local network ID")
errMissingStakersForGenesis = errors.New("no genesis stakers provided")
errMissingBalancesForGenesis = errors.New("no genesis balances given")
errMissingTLSKeyForNodeID = fmt.Errorf("failed to ensure node ID: missing value for %q", config.StakingTLSKeyContentKey)
errMissingCertForNodeID = fmt.Errorf("failed to ensure node ID: missing value for %q", config.StakingCertContentKey)
errInvalidKeypair = fmt.Errorf("%q and %q must be provided together or not at all", config.StakingTLSKeyContentKey, config.StakingCertContentKey)
)

// Defines a mapping of flag keys to values intended to be supplied to
Expand Down Expand Up @@ -129,14 +128,11 @@ type NetworkConfig struct {
}

// Ensure genesis is generated if not already present.
func (c *NetworkConfig) EnsureGenesis(networkID uint32, validatorIDs []ids.NodeID) error {
func (c *NetworkConfig) EnsureGenesis(networkID uint32, initialStakers []genesis.UnparsedStaker) error {
if c.Genesis != nil {
return nil
}

if len(validatorIDs) == 0 {
return errEmptyValidatorsForGenesis
}
if len(c.FundedKeys) == 0 {
return errNoKeysForGenesis
}
Expand All @@ -151,7 +147,7 @@ func (c *NetworkConfig) EnsureGenesis(networkID uint32, validatorIDs []ids.NodeI
}
}

genesis, err := NewTestGenesis(networkID, xChainBalances, cChainBalances, validatorIDs)
genesis, err := NewTestGenesis(networkID, xChainBalances, cChainBalances, initialStakers)
if err != nil {
return err
}
Expand Down Expand Up @@ -206,6 +202,24 @@ func (nc *NodeConfig) EnsureKeys() error {
return nc.EnsureNodeID()
}

// Derives the nodes proof-of-possession. Requires the node to have a
// BLS signing key.
func (nc *NodeConfig) GetProofOfPossession() (*signer.ProofOfPossession, error) {
signingKey, err := nc.Flags.GetStringVal(config.StakingSignerKeyContentKey)
if err != nil {
return nil, err
}
signingKeyBytes, err := base64.StdEncoding.DecodeString(signingKey)
if err != nil {
return nil, err
}
secretKey, err := bls.SecretKeyFromBytes(signingKeyBytes)
if err != nil {
return nil, err
}
return signer.NewProofOfPossession(secretKey), nil
}

// Ensures a BLS signing key is generated if not already present.
func (nc *NodeConfig) EnsureBLSSigningKey() error {
// Attempt to retrieve an existing key
Expand Down Expand Up @@ -312,15 +326,15 @@ func NewTestGenesis(
networkID uint32,
xChainBalances XChainBalanceMap,
cChainBalances core.GenesisAlloc,
validatorIDs []ids.NodeID,
initialStakers []genesis.UnparsedStaker,
) (*genesis.UnparsedConfig, error) {
// Validate inputs
switch networkID {
case constants.TestnetID, constants.MainnetID, constants.LocalID:
return nil, errInvalidNetworkIDForGenesis
}
if len(validatorIDs) == 0 {
return nil, errMissingValidatorsForGenesis
if len(initialStakers) == 0 {
return nil, errMissingStakersForGenesis
}
if len(xChainBalances) == 0 || len(cChainBalances) == 0 {
return nil, errMissingBalancesForGenesis
Expand All @@ -336,8 +350,8 @@ func NewTestGenesis(
return nil, fmt.Errorf("failed to format stake address: %w", err)
}

// Ensure the total stake allows a MegaAvax per validator
totalStake := uint64(len(validatorIDs)) * units.MegaAvax
// Ensure the total stake allows a MegaAvax per staker
totalStake := uint64(len(initialStakers)) * units.MegaAvax

// The eth address is only needed to link pre-mainnet assets. Until that capability
// becomes necessary for testing, use a bogus address.
Expand Down Expand Up @@ -367,6 +381,7 @@ func NewTestGenesis(
InitialStakeDuration: 365 * 24 * 60 * 60, // 1 year
InitialStakeDurationOffset: 90 * 60, // 90 minutes
Message: "hello avalanche!",
InitialStakers: initialStakers,
}

// Set X-Chain balances
Expand Down Expand Up @@ -409,25 +424,5 @@ func NewTestGenesis(
}
config.CChainGenesis = string(cChainGenesisBytes)

// Give staking rewards for initial validators to a random address. Any testing of staking rewards
// will be easier to perform with nodes other than the initial validators since the timing of
// staking can be more easily controlled.
rewardAddr, err := address.Format("X", constants.GetHRP(networkID), ids.GenerateTestShortID().Bytes())
if err != nil {
return nil, fmt.Errorf("failed to format reward address: %w", err)
}

// Configure provided validator node IDs as initial stakers
for _, validatorID := range validatorIDs {
config.InitialStakers = append(
config.InitialStakers,
genesis.UnparsedStaker{
NodeID: validatorID,
RewardAddress: rewardAddr,
DelegationFee: .01 * reward.PercentDenominator,
},
)
}

return config, nil
}
44 changes: 37 additions & 7 deletions tests/fixture/tmpnet/local/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import (
"github.com/ava-labs/avalanchego/tests/fixture/tmpnet"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
"github.com/ava-labs/avalanchego/utils/formatting/address"
"github.com/ava-labs/avalanchego/utils/perms"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/platformvm/reward"
)

const (
Expand Down Expand Up @@ -238,18 +240,18 @@ func (ln *LocalNetwork) PopulateLocalNetworkConfig(networkID uint32, nodeCount i
}

// Ensure each node has keys and an associated node ID. This
// ensures the availability of validator node IDs for genesis
// generation.
// ensures the availability of node IDs and proofs of possession
// for genesis generation.
for _, node := range ln.Nodes {
if err := node.EnsureKeys(); err != nil {
return err
}
}

// Assume all initial nodes are validator ids
validatorIDs := make([]ids.NodeID, 0, len(ln.Nodes))
for _, node := range ln.Nodes {
validatorIDs = append(validatorIDs, node.NodeID)
// Assume all the initial nodes are stakers
initialStakers, err := stakersForNodes(networkID, ln.Nodes)
if err != nil {
return err
}

if keyCount > 0 {
Expand All @@ -265,7 +267,7 @@ func (ln *LocalNetwork) PopulateLocalNetworkConfig(networkID uint32, nodeCount i
ln.FundedKeys = keys
}

if err := ln.EnsureGenesis(networkID, validatorIDs); err != nil {
if err := ln.EnsureGenesis(networkID, initialStakers); err != nil {
return err
}

Expand Down Expand Up @@ -713,3 +715,31 @@ func (ln *LocalNetwork) GetBootstrapIPsAndIDs() ([]string, []string, error) {

return bootstrapIPs, bootstrapIDs, nil
}

// Returns staker configuration for the given set of nodes.
func stakersForNodes(networkID uint32, nodes []*LocalNode) ([]genesis.UnparsedStaker, error) {
// Give staking rewards for initial validators to a random address. Any testing of staking rewards
// will be easier to perform with nodes other than the initial validators since the timing of
// staking can be more easily controlled.
rewardAddr, err := address.Format("X", constants.GetHRP(networkID), ids.GenerateTestShortID().Bytes())
if err != nil {
return nil, fmt.Errorf("failed to format reward address: %w", err)
}

// Configure provided nodes as initial stakers
initialStakers := make([]genesis.UnparsedStaker, len(nodes))
for i, node := range nodes {
pop, err := node.GetProofOfPossession()
if err != nil {
return nil, fmt.Errorf("failed to derive proof of possession: %w", err)
}
initialStakers[i] = genesis.UnparsedStaker{
NodeID: node.NodeID,
RewardAddress: rewardAddr,
DelegationFee: .01 * reward.PercentDenominator,
Signer: pop,
}
}

return initialStakers, nil
}

0 comments on commit 159aafb

Please sign in to comment.