Skip to content

Commit

Permalink
Separate subnet stake connected health and metrics from P-chain (ava-…
Browse files Browse the repository at this point in the history
…labs#1358)

Co-authored-by: Stephen Buttolph <stephen@avalabs.org>
  • Loading branch information
ceyonur and StephenButtolph committed Jun 8, 2023
1 parent efb7d90 commit 925230d
Show file tree
Hide file tree
Showing 25 changed files with 543 additions and 418 deletions.
68 changes: 39 additions & 29 deletions chains/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ var (
errUnknownVMType = errors.New("the vm should have type avalanche.DAGVM or snowman.ChainVM")
errCreatePlatformVM = errors.New("attempted to create a chain running the PlatformVM")
errNotBootstrapped = errors.New("subnets not bootstrapped")
errNoPlatformSubnetConfig = errors.New("subnet config for platform chain not found")
errNoPrimaryNetworkConfig = errors.New("no subnet config for primary network found")

_ Manager = (*manager)(nil)
)
Expand Down Expand Up @@ -145,7 +145,7 @@ type ChainParameters struct {
VMID ids.ID
// The IDs of the feature extensions this chain is running.
FxIDs []ids.ID
// Should only be set if the default beacons can't be used.
// Invariant: Only used when [ID] is the P-chain ID.
CustomBeacons validators.Set
}

Expand Down Expand Up @@ -521,48 +521,43 @@ func (m *manager) buildChain(chainParams ChainParameters, sb subnets.Subnet) (*c
}

var vdrs validators.Set // Validators validating this blockchain
var ok bool
var hasValidators bool
if m.SybilProtectionEnabled {
vdrs, ok = m.Validators.Get(chainParams.SubnetID)
vdrs, hasValidators = m.Validators.Get(chainParams.SubnetID)
} else { // Sybil protection is disabled. Every peer validates every subnet.
vdrs, ok = m.Validators.Get(constants.PrimaryNetworkID)
vdrs, hasValidators = m.Validators.Get(constants.PrimaryNetworkID)
}
if !ok {
if !hasValidators {
return nil, fmt.Errorf("couldn't get validator set of subnet with ID %s. The subnet may not exist", chainParams.SubnetID)
}

beacons := vdrs
if chainParams.CustomBeacons != nil {
beacons = chainParams.CustomBeacons
}

bootstrapWeight := beacons.Weight()

var chain *chain
switch vm := vm.(type) {
case vertex.LinearizableVMWithEngine:
chain, err = m.createAvalancheChain(
ctx,
chainParams.GenesisData,
vdrs,
beacons,
vm,
fxs,
bootstrapWeight,
sb,
)
if err != nil {
return nil, fmt.Errorf("error while creating new avalanche vm %w", err)
}
case block.ChainVM:
beacons := vdrs
if chainParams.ID == constants.PlatformChainID {
beacons = chainParams.CustomBeacons
}

chain, err = m.createSnowmanChain(
ctx,
chainParams.GenesisData,
vdrs,
beacons,
vm,
fxs,
bootstrapWeight,
sb,
)
if err != nil {
Expand All @@ -588,11 +583,9 @@ func (m *manager) AddRegistrant(r Registrant) {
func (m *manager) createAvalancheChain(
ctx *snow.ConsensusContext,
genesisData []byte,
vdrs,
beacons validators.Set,
vdrs validators.Set,
vm vertex.LinearizableVMWithEngine,
fxs []*common.Fx,
bootstrapWeight uint64,
sb subnets.Subnet,
) (*chain, error) {
ctx.Lock.Lock()
Expand Down Expand Up @@ -806,12 +799,20 @@ func (m *manager) createAvalancheChain(
appSender: snowmanMessageSender,
}

bootstrapWeight := vdrs.Weight()

consensusParams := sb.Config().ConsensusParameters
sampleK := consensusParams.K
if uint64(sampleK) > bootstrapWeight {
sampleK = int(bootstrapWeight)
}

connectedValidators, err := tracker.NewMeteredPeers("", ctx.Registerer)
if err != nil {
return nil, fmt.Errorf("error creating peer tracker: %w", err)
}
vdrs.RegisterCallbackListener(connectedValidators)

// Asynchronously passes messages from the network to the consensus engine
h, err := handler.New(
ctx,
Expand All @@ -822,18 +823,19 @@ func (m *manager) createAvalancheChain(
m.ResourceTracker,
validators.UnhandledSubnetConnector, // avalanche chains don't use subnet connector
sb,
connectedValidators,
)
if err != nil {
return nil, fmt.Errorf("error initializing network handler: %w", err)
}

connectedPeers := tracker.NewPeers()
startupTracker := tracker.NewStartup(connectedPeers, (3*bootstrapWeight+3)/4)
beacons.RegisterCallbackListener(startupTracker)
connectedBeacons := tracker.NewPeers()
startupTracker := tracker.NewStartup(connectedBeacons, (3*bootstrapWeight+3)/4)
vdrs.RegisterCallbackListener(startupTracker)

snowmanCommonCfg := common.Config{
Ctx: ctx,
Beacons: beacons,
Beacons: vdrs,
SampleK: sampleK,
Alpha: bootstrapWeight/2 + 1, // must be > 50%
StartupTracker: startupTracker,
Expand Down Expand Up @@ -898,7 +900,7 @@ func (m *manager) createAvalancheChain(

avalancheCommonCfg := common.Config{
Ctx: ctx,
Beacons: beacons,
Beacons: vdrs,
SampleK: sampleK,
StartupTracker: startupTracker,
Alpha: bootstrapWeight/2 + 1, // must be > 50%
Expand Down Expand Up @@ -979,11 +981,10 @@ func (m *manager) createAvalancheChain(
func (m *manager) createSnowmanChain(
ctx *snow.ConsensusContext,
genesisData []byte,
vdrs,
vdrs validators.Set,
beacons validators.Set,
vm block.ChainVM,
fxs []*common.Fx,
bootstrapWeight uint64,
sb subnets.Subnet,
) (*chain, error) {
ctx.Lock.Lock()
Expand Down Expand Up @@ -1140,12 +1141,20 @@ func (m *manager) createSnowmanChain(
return nil, err
}

bootstrapWeight := beacons.Weight()

consensusParams := sb.Config().ConsensusParameters
sampleK := consensusParams.K
if uint64(sampleK) > bootstrapWeight {
sampleK = int(bootstrapWeight)
}

connectedValidators, err := tracker.NewMeteredPeers("", ctx.Registerer)
if err != nil {
return nil, fmt.Errorf("error creating peer tracker: %w", err)
}
vdrs.RegisterCallbackListener(connectedValidators)

// Asynchronously passes messages from the network to the consensus engine
h, err := handler.New(
ctx,
Expand All @@ -1156,13 +1165,14 @@ func (m *manager) createSnowmanChain(
m.ResourceTracker,
subnetConnector,
sb,
connectedValidators,
)
if err != nil {
return nil, fmt.Errorf("couldn't initialize message handler: %w", err)
}

connectedPeers := tracker.NewPeers()
startupTracker := tracker.NewStartup(connectedPeers, (3*bootstrapWeight+3)/4)
connectedBeacons := tracker.NewPeers()
startupTracker := tracker.NewStartup(connectedBeacons, (3*bootstrapWeight+3)/4)
beacons.RegisterCallbackListener(startupTracker)

commonCfg := common.Config{
Expand Down Expand Up @@ -1320,7 +1330,7 @@ func (m *manager) StartChainCreator(platformParams ChainParameters) error {
// throw a fatal error.
sbConfig, ok := m.SubnetConfigs[constants.PrimaryNetworkID]
if !ok {
return errNoPlatformSubnetConfig
return errNoPrimaryNetworkConfig
}

sb := subnets.New(m.NodeID, sbConfig)
Expand Down
18 changes: 0 additions & 18 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1453,15 +1453,6 @@ func GetNodeConfig(v *viper.Viper) (node.Config, error) {
return node.Config{}, err
}

// Node health
nodeConfig.MinPercentConnectedStakeHealthy = map[ids.ID]float64{
constants.PrimaryNetworkID: calcMinConnectedStake(primaryNetworkConfig.ConsensusParameters),
}

for subnetID, config := range subnetConfigs {
nodeConfig.MinPercentConnectedStakeHealthy[subnetID] = calcMinConnectedStake(config.ConsensusParameters)
}

// Chain Configs
nodeConfig.ChainConfigs, err = getChainConfigs(v)
if err != nil {
Expand Down Expand Up @@ -1516,15 +1507,6 @@ func GetNodeConfig(v *viper.Viper) (node.Config, error) {
return nodeConfig, nil
}

// calcMinConnectedStake takes [consensusParams] as input and calculates the
// expected min connected stake percentage according to alpha and k.
func calcMinConnectedStake(consensusParams snowball.Parameters) float64 {
alpha := consensusParams.Alpha
k := consensusParams.K
r := float64(alpha) / float64(k)
return r*(1-constants.MinConnectedStakeBuffer) + constants.MinConnectedStakeBuffer
}

func providedFlags(v *viper.Viper) map[string]interface{} {
settings := v.AllSettings()
customSettings := make(map[string]interface{}, len(settings))
Expand Down
8 changes: 0 additions & 8 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,14 +551,6 @@ func TestGetSubnetConfigsFromFlags(t *testing.T) {
}
}

func TestCalcMinConnectedStake(t *testing.T) {
v := setupViperFlags()
defaultParams := getConsensusConfig(v)
defaultExpectedMinStake := 0.8
minStake := calcMinConnectedStake(defaultParams)
require.Equal(t, defaultExpectedMinStake, minStake)
}

// setups config json file and writes content
func setupConfigJSON(t *testing.T, rootPath string, value string) string {
configFilePath := filepath.Join(rootPath, "config.json")
Expand Down
17 changes: 9 additions & 8 deletions config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/ava-labs/avalanchego/database/leveldb"
"github.com/ava-labs/avalanchego/database/memdb"
"github.com/ava-labs/avalanchego/genesis"
"github.com/ava-labs/avalanchego/snow/consensus/snowball"
"github.com/ava-labs/avalanchego/trace"
"github.com/ava-labs/avalanchego/utils/compression"
"github.com/ava-labs/avalanchego/utils/constants"
Expand Down Expand Up @@ -309,16 +310,16 @@ func addNodeFlags(fs *pflag.FlagSet) {
fs.Uint(BootstrapAncestorsMaxContainersReceivedKey, 2000, "This node reads at most this many containers from an incoming Ancestors message")

// Consensus
fs.Int(SnowSampleSizeKey, 20, "Number of nodes to query for each network poll")
fs.Int(SnowQuorumSizeKey, 15, "Alpha value to use for required number positive results")
fs.Int(SnowSampleSizeKey, snowball.DefaultParameters.K, "Number of nodes to query for each network poll")
fs.Int(SnowQuorumSizeKey, snowball.DefaultParameters.Alpha, "Alpha value to use for required number positive results")
// TODO: Replace this temporary flag description after the X-chain
// linearization with "Beta value to use for virtuous transactions"
fs.Int(SnowVirtuousCommitThresholdKey, 15, "This flag is temporarily ignored due to the X-chain linearization")
fs.Int(SnowRogueCommitThresholdKey, 20, "Beta value to use for rogue transactions")
fs.Int(SnowConcurrentRepollsKey, 4, "Minimum number of concurrent polls for finalizing consensus")
fs.Int(SnowOptimalProcessingKey, 10, "Optimal number of processing containers in consensus")
fs.Int(SnowMaxProcessingKey, 256, "Maximum number of processing items to be considered healthy")
fs.Duration(SnowMaxTimeProcessingKey, 30*time.Second, "Maximum amount of time an item should be processing and still be healthy")
fs.Int(SnowVirtuousCommitThresholdKey, snowball.DefaultParameters.BetaVirtuous, "This flag is temporarily ignored due to the X-chain linearization")
fs.Int(SnowRogueCommitThresholdKey, snowball.DefaultParameters.BetaRogue, "Beta value to use for rogue transactions")
fs.Int(SnowConcurrentRepollsKey, snowball.DefaultParameters.ConcurrentRepolls, "Minimum number of concurrent polls for finalizing consensus")
fs.Int(SnowOptimalProcessingKey, snowball.DefaultParameters.OptimalProcessing, "Optimal number of processing containers in consensus")
fs.Int(SnowMaxProcessingKey, snowball.DefaultParameters.MaxOutstandingItems, "Maximum number of processing items to be considered healthy")
fs.Duration(SnowMaxTimeProcessingKey, snowball.DefaultParameters.MaxItemProcessingTime, "Maximum amount of time an item should be processing and still be healthy")

// ProposerVM
fs.Bool(ProposerVMUseCurrentHeightKey, false, "Have the ProposerVM always report the last accepted P-chain block height")
Expand Down
4 changes: 0 additions & 4 deletions node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,6 @@ type Config struct {

TraceConfig trace.Config `json:"traceConfig"`

// See comment on [MinPercentConnectedStakeHealthy] in platformvm.Config
// TODO: consider moving to subnet config
MinPercentConnectedStakeHealthy map[ids.ID]float64 `json:"minPercentConnectedStakeHealthy"`

// See comment on [UseCurrentHeight] in platformvm.Config
UseCurrentHeight bool `json:"useCurrentHeight"`

Expand Down
55 changes: 27 additions & 28 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -787,34 +787,33 @@ func (n *Node) initVMs() error {
errs.Add(
vmRegisterer.Register(context.TODO(), constants.PlatformVMID, &platformvm.Factory{
Config: platformconfig.Config{
Chains: n.chainManager,
Validators: vdrs,
UptimeLockedCalculator: n.uptimeCalculator,
SybilProtectionEnabled: n.Config.SybilProtectionEnabled,
TrackedSubnets: n.Config.TrackedSubnets,
TxFee: n.Config.TxFee,
CreateAssetTxFee: n.Config.CreateAssetTxFee,
CreateSubnetTxFee: n.Config.CreateSubnetTxFee,
TransformSubnetTxFee: n.Config.TransformSubnetTxFee,
CreateBlockchainTxFee: n.Config.CreateBlockchainTxFee,
AddPrimaryNetworkValidatorFee: n.Config.AddPrimaryNetworkValidatorFee,
AddPrimaryNetworkDelegatorFee: n.Config.AddPrimaryNetworkDelegatorFee,
AddSubnetValidatorFee: n.Config.AddSubnetValidatorFee,
AddSubnetDelegatorFee: n.Config.AddSubnetDelegatorFee,
UptimePercentage: n.Config.UptimeRequirement,
MinValidatorStake: n.Config.MinValidatorStake,
MaxValidatorStake: n.Config.MaxValidatorStake,
MinDelegatorStake: n.Config.MinDelegatorStake,
MinDelegationFee: n.Config.MinDelegationFee,
MinStakeDuration: n.Config.MinStakeDuration,
MaxStakeDuration: n.Config.MaxStakeDuration,
RewardConfig: n.Config.RewardConfig,
ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID),
ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID),
BanffTime: version.GetBanffTime(n.Config.NetworkID),
CortinaTime: version.GetCortinaTime(n.Config.NetworkID),
MinPercentConnectedStakeHealthy: n.Config.MinPercentConnectedStakeHealthy,
UseCurrentHeight: n.Config.UseCurrentHeight,
Chains: n.chainManager,
Validators: vdrs,
UptimeLockedCalculator: n.uptimeCalculator,
SybilProtectionEnabled: n.Config.SybilProtectionEnabled,
TrackedSubnets: n.Config.TrackedSubnets,
TxFee: n.Config.TxFee,
CreateAssetTxFee: n.Config.CreateAssetTxFee,
CreateSubnetTxFee: n.Config.CreateSubnetTxFee,
TransformSubnetTxFee: n.Config.TransformSubnetTxFee,
CreateBlockchainTxFee: n.Config.CreateBlockchainTxFee,
AddPrimaryNetworkValidatorFee: n.Config.AddPrimaryNetworkValidatorFee,
AddPrimaryNetworkDelegatorFee: n.Config.AddPrimaryNetworkDelegatorFee,
AddSubnetValidatorFee: n.Config.AddSubnetValidatorFee,
AddSubnetDelegatorFee: n.Config.AddSubnetDelegatorFee,
UptimePercentage: n.Config.UptimeRequirement,
MinValidatorStake: n.Config.MinValidatorStake,
MaxValidatorStake: n.Config.MaxValidatorStake,
MinDelegatorStake: n.Config.MinDelegatorStake,
MinDelegationFee: n.Config.MinDelegationFee,
MinStakeDuration: n.Config.MinStakeDuration,
MaxStakeDuration: n.Config.MaxStakeDuration,
RewardConfig: n.Config.RewardConfig,
ApricotPhase3Time: version.GetApricotPhase3Time(n.Config.NetworkID),
ApricotPhase5Time: version.GetApricotPhase5Time(n.Config.NetworkID),
BanffTime: version.GetBanffTime(n.Config.NetworkID),
CortinaTime: version.GetCortinaTime(n.Config.NetworkID),
UseCurrentHeight: n.Config.UseCurrentHeight,
},
}),
vmRegisterer.Register(context.TODO(), constants.AVMID, &avm.Factory{
Expand Down

0 comments on commit 925230d

Please sign in to comment.