diff --git a/config/config.go b/config/config.go index f859cbd58b52..973e0652b788 100644 --- a/config/config.go +++ b/config/config.go @@ -89,9 +89,10 @@ var ( ) func getConsensusConfig(v *viper.Viper) snowball.Parameters { - return snowball.Parameters{ - K: v.GetInt(SnowSampleSizeKey), - Alpha: v.GetInt(SnowQuorumSizeKey), + p := snowball.Parameters{ + K: v.GetInt(SnowSampleSizeKey), + AlphaPreference: v.GetInt(SnowPreferenceQuorumSizeKey), + AlphaConfidence: v.GetInt(SnowConfidenceQuorumSizeKey), // During the X-chain linearization we require BetaVirtuous and // BetaRogue to be equal. Therefore we use the more conservative // BetaRogue value for both BetaVirtuous and BetaRogue. @@ -105,6 +106,11 @@ func getConsensusConfig(v *viper.Viper) snowball.Parameters { MaxOutstandingItems: v.GetInt(SnowMaxProcessingKey), MaxItemProcessingTime: v.GetDuration(SnowMaxTimeProcessingKey), } + if v.IsSet(SnowQuorumSizeKey) { + p.AlphaPreference = v.GetInt(SnowQuorumSizeKey) + p.AlphaConfidence = p.AlphaPreference + } + return p } func getLoggingConfig(v *viper.Viper) (logging.Config, error) { @@ -447,7 +453,10 @@ func getNetworkConfig( } func getBenchlistConfig(v *viper.Viper, consensusParameters snowball.Parameters) (benchlist.Config, error) { - alpha := consensusParameters.Alpha + // AlphaConfidence is used here to ensure that benching can't cause a + // liveness failure. If AlphaPreference were used, the benchlist may grow to + // a point that committing would be extremely unlikely to happen. + alpha := consensusParameters.AlphaConfidence k := consensusParameters.K config := benchlist.Config{ Threshold: v.GetInt(BenchlistFailThresholdKey), @@ -1102,6 +1111,11 @@ func getSubnetConfigsFromFlags(v *viper.Viper, subnetIDs []ids.ID) (map[ids.ID]s return nil, err } + if config.ConsensusParameters.Alpha != nil { + config.ConsensusParameters.AlphaPreference = *config.ConsensusParameters.Alpha + config.ConsensusParameters.AlphaConfidence = config.ConsensusParameters.AlphaPreference + } + if err := config.Valid(); err != nil { return nil, err } @@ -1150,6 +1164,11 @@ func getSubnetConfigsFromDir(v *viper.Viper, subnetIDs []ids.ID) (map[ids.ID]sub return nil, fmt.Errorf("%w: %w", errUnmarshalling, err) } + if config.ConsensusParameters.Alpha != nil { + config.ConsensusParameters.AlphaPreference = *config.ConsensusParameters.Alpha + config.ConsensusParameters.AlphaConfidence = config.ConsensusParameters.AlphaPreference + } + if err := config.Valid(); err != nil { return nil, err } diff --git a/config/config_test.go b/config/config_test.go index 075f046b7122..8c2498d02c75 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -399,7 +399,7 @@ func TestGetSubnetConfigsFromFile(t *testing.T) { }, "invalid consensus parameters": { fileName: "2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i.json", - givenJSON: `{"consensusParameters":{"k": 111, "alpha":1234} }`, + givenJSON: `{"consensusParameters":{"k": 111, "alphaPreference":1234} }`, testF: func(require *require.Assertions, given map[ids.ID]subnets.Config) { require.Nil(given) }, @@ -407,14 +407,14 @@ func TestGetSubnetConfigsFromFile(t *testing.T) { }, "correct config": { fileName: "2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i.json", - givenJSON: `{"validatorOnly": true, "consensusParameters":{"alpha":16} }`, + givenJSON: `{"validatorOnly": true, "consensusParameters":{"alphaConfidence":16} }`, testF: func(require *require.Assertions, given map[ids.ID]subnets.Config) { id, _ := ids.FromString("2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i") config, ok := given[id] require.True(ok) require.Equal(true, config.ValidatorOnly) - require.Equal(16, config.ConsensusParameters.Alpha) + require.Equal(16, config.ConsensusParameters.AlphaConfidence) // must still respect defaults require.Equal(20, config.ConsensusParameters.K) }, @@ -499,7 +499,7 @@ func TestGetSubnetConfigsFromFlags(t *testing.T) { "2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i": { "consensusParameters": { "k": 111, - "alpha": 1234 + "alphaPreference": 1234 } } }`, @@ -513,7 +513,8 @@ func TestGetSubnetConfigsFromFlags(t *testing.T) { "2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i": { "consensusParameters": { "k": 30, - "alpha": 20 + "alphaPreference": 16, + "alphaConfidence": 20 }, "validatorOnly": true } @@ -523,7 +524,8 @@ func TestGetSubnetConfigsFromFlags(t *testing.T) { config, ok := given[id] require.True(ok) require.Equal(true, config.ValidatorOnly) - require.Equal(20, config.ConsensusParameters.Alpha) + require.Equal(16, config.ConsensusParameters.AlphaPreference) + require.Equal(20, config.ConsensusParameters.AlphaConfidence) require.Equal(30, config.ConsensusParameters.K) // must still respect defaults require.Equal(uint(10), config.GossipConfig.AppGossipValidatorSize) diff --git a/config/flags.go b/config/flags.go index 28ea0379da80..254d70fea2dd 100644 --- a/config/flags.go +++ b/config/flags.go @@ -299,7 +299,9 @@ func addNodeFlags(fs *pflag.FlagSet) { // Consensus 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") + fs.Int(SnowQuorumSizeKey, snowball.DefaultParameters.AlphaConfidence, "Threshold of nodes required to update this node's preference and increase its confidence in a network poll") + fs.Int(SnowPreferenceQuorumSizeKey, snowball.DefaultParameters.AlphaPreference, fmt.Sprintf("Threshold of nodes required to update this node's preference in a network poll. Ignored if %s is provided", SnowQuorumSizeKey)) + fs.Int(SnowConfidenceQuorumSizeKey, snowball.DefaultParameters.AlphaConfidence, fmt.Sprintf("Threshold of nodes required to increase this node's confidence in a network poll. Ignored if %s is provided", SnowQuorumSizeKey)) // TODO: Replace this temporary flag description after the X-chain // linearization with "Beta value to use for virtuous transactions" fs.Int(SnowVirtuousCommitThresholdKey, snowball.DefaultParameters.BetaVirtuous, "This flag is temporarily ignored due to the X-chain linearization") diff --git a/config/keys.go b/config/keys.go index a41e33986d65..a62e960f16bb 100644 --- a/config/keys.go +++ b/config/keys.go @@ -123,6 +123,8 @@ const ( LogDisableDisplayPluginLogsKey = "log-disable-display-plugin-logs" SnowSampleSizeKey = "snow-sample-size" SnowQuorumSizeKey = "snow-quorum-size" + SnowPreferenceQuorumSizeKey = "snow-preference-quorum-size" + SnowConfidenceQuorumSizeKey = "snow-confidence-quorum-size" SnowVirtuousCommitThresholdKey = "snow-virtuous-commit-threshold" SnowRogueCommitThresholdKey = "snow-rogue-commit-threshold" SnowConcurrentRepollsKey = "snow-concurrent-repolls" diff --git a/snow/consensus/snowball/binary_snowball.go b/snow/consensus/snowball/binary_snowball.go index d490d53010f2..aa1dc37bbe34 100644 --- a/snow/consensus/snowball/binary_snowball.go +++ b/snow/consensus/snowball/binary_snowball.go @@ -19,13 +19,13 @@ type binarySnowball struct { // wrap the binary snowflake logic binarySnowflake - // preference is the choice with the largest number of successful polls. - // Ties are broken by switching choice lazily + // preference is the choice with the largest number of polls which preferred + // the color. Ties are broken by switching choice lazily preference int - // numSuccessfulPolls tracks the total number of successful network polls of - // the 0 and 1 choices - numSuccessfulPolls [2]int + // preferenceStrength tracks the total number of network polls which + // preferred each choice + preferenceStrength [2]int } func (sb *binarySnowball) Preference() int { @@ -40,18 +40,27 @@ func (sb *binarySnowball) Preference() int { } func (sb *binarySnowball) RecordSuccessfulPoll(choice int) { - sb.numSuccessfulPolls[choice]++ - if sb.numSuccessfulPolls[choice] > sb.numSuccessfulPolls[1-choice] { - sb.preference = choice - } + sb.increasePreferenceStrength(choice) sb.binarySnowflake.RecordSuccessfulPoll(choice) } +func (sb *binarySnowball) RecordPollPreference(choice int) { + sb.increasePreferenceStrength(choice) + sb.binarySnowflake.RecordPollPreference(choice) +} + func (sb *binarySnowball) String() string { return fmt.Sprintf( - "SB(Preference = %d, NumSuccessfulPolls[0] = %d, NumSuccessfulPolls[1] = %d, %s)", + "SB(Preference = %d, PreferenceStrength[0] = %d, PreferenceStrength[1] = %d, %s)", sb.preference, - sb.numSuccessfulPolls[0], - sb.numSuccessfulPolls[1], + sb.preferenceStrength[0], + sb.preferenceStrength[1], &sb.binarySnowflake) } + +func (sb *binarySnowball) increasePreferenceStrength(choice int) { + sb.preferenceStrength[choice]++ + if sb.preferenceStrength[choice] > sb.preferenceStrength[1-choice] { + sb.preference = choice + } +} diff --git a/snow/consensus/snowball/binary_snowball_test.go b/snow/consensus/snowball/binary_snowball_test.go index 934009dee4ad..42b6b404caa0 100644 --- a/snow/consensus/snowball/binary_snowball_test.go +++ b/snow/consensus/snowball/binary_snowball_test.go @@ -38,6 +38,42 @@ func TestBinarySnowball(t *testing.T) { require.True(sb.Finalized()) } +func TestBinarySnowballRecordPollPreference(t *testing.T) { + require := require.New(t) + + red := 0 + blue := 1 + + beta := 2 + + sb := newBinarySnowball(beta, red) + require.Equal(red, sb.Preference()) + require.False(sb.Finalized()) + + sb.RecordSuccessfulPoll(blue) + require.Equal(blue, sb.Preference()) + require.False(sb.Finalized()) + + sb.RecordSuccessfulPoll(red) + require.Equal(blue, sb.Preference()) + require.False(sb.Finalized()) + + sb.RecordPollPreference(red) + require.Equal(red, sb.Preference()) + require.False(sb.Finalized()) + + sb.RecordSuccessfulPoll(red) + require.Equal(red, sb.Preference()) + require.False(sb.Finalized()) + + sb.RecordSuccessfulPoll(red) + require.Equal(red, sb.Preference()) + require.True(sb.Finalized()) + + expected := "SB(Preference = 0, PreferenceStrength[0] = 4, PreferenceStrength[1] = 1, SF(Confidence = 2, Finalized = true, SL(Preference = 0)))" + require.Equal(expected, sb.String()) +} + func TestBinarySnowballRecordUnsuccessfulPoll(t *testing.T) { require := require.New(t) @@ -64,7 +100,7 @@ func TestBinarySnowballRecordUnsuccessfulPoll(t *testing.T) { require.Equal(blue, sb.Preference()) require.True(sb.Finalized()) - expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 3, SF(Confidence = 2, Finalized = true, SL(Preference = 1)))" + expected := "SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 3, SF(Confidence = 2, Finalized = true, SL(Preference = 1)))" require.Equal(expected, sb.String()) } @@ -104,7 +140,7 @@ func TestBinarySnowballAcceptWeirdColor(t *testing.T) { require.Equal(blue, sb.Preference()) require.True(sb.Finalized()) - expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 2, SF(Confidence = 2, Finalized = true, SL(Preference = 0)))" + expected := "SB(Preference = 1, PreferenceStrength[0] = 2, PreferenceStrength[1] = 2, SF(Confidence = 2, Finalized = true, SL(Preference = 0)))" require.Equal(expected, sb.String()) } @@ -128,11 +164,12 @@ func TestBinarySnowballLockColor(t *testing.T) { require.Equal(red, sb.Preference()) require.True(sb.Finalized()) + sb.RecordPollPreference(blue) sb.RecordSuccessfulPoll(blue) require.Equal(red, sb.Preference()) require.True(sb.Finalized()) - expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 2, SF(Confidence = 1, Finalized = true, SL(Preference = 0)))" + expected := "SB(Preference = 1, PreferenceStrength[0] = 1, PreferenceStrength[1] = 3, SF(Confidence = 1, Finalized = true, SL(Preference = 0)))" require.Equal(expected, sb.String()) } diff --git a/snow/consensus/snowball/binary_snowflake.go b/snow/consensus/snowball/binary_snowflake.go index ae30204a772a..d95ef9709ec6 100644 --- a/snow/consensus/snowball/binary_snowflake.go +++ b/snow/consensus/snowball/binary_snowflake.go @@ -49,6 +49,15 @@ func (sf *binarySnowflake) RecordSuccessfulPoll(choice int) { sf.binarySlush.RecordSuccessfulPoll(choice) } +func (sf *binarySnowflake) RecordPollPreference(choice int) { + if sf.finalized { + return // This instance is already decided. + } + + sf.confidence = 0 + sf.binarySlush.RecordSuccessfulPoll(choice) +} + func (sf *binarySnowflake) RecordUnsuccessfulPoll() { sf.confidence = 0 } diff --git a/snow/consensus/snowball/binary_snowflake_test.go b/snow/consensus/snowball/binary_snowflake_test.go index cafafd72da78..2f14396da959 100644 --- a/snow/consensus/snowball/binary_snowflake_test.go +++ b/snow/consensus/snowball/binary_snowflake_test.go @@ -37,8 +37,15 @@ func TestBinarySnowflake(t *testing.T) { require.Equal(blue, sf.Preference()) require.False(sf.Finalized()) + sf.RecordPollPreference(red) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) + sf.RecordSuccessfulPoll(blue) + require.Equal(blue, sf.Preference()) + require.False(sf.Finalized()) + sf.RecordSuccessfulPoll(blue) require.Equal(blue, sf.Preference()) require.True(sf.Finalized()) } diff --git a/snow/consensus/snowball/consensus.go b/snow/consensus/snowball/consensus.go index 36f9ead42802..3f3c508af053 100644 --- a/snow/consensus/snowball/consensus.go +++ b/snow/consensus/snowball/consensus.go @@ -61,6 +61,11 @@ type NnarySnowflake interface { // specified choice. Assumes the choice was previously added. RecordSuccessfulPoll(choice ids.ID) + // RecordPollPreference records a poll that preferred the specified choice + // but did not contribute towards finalizing the specified choice. Assumes + // the choice was previously added. + RecordPollPreference(choice ids.ID) + // RecordUnsuccessfulPoll resets the snowflake counter of this instance RecordUnsuccessfulPoll() @@ -100,6 +105,10 @@ type BinarySnowflake interface { // specified choice RecordSuccessfulPoll(choice int) + // RecordPollPreference records a poll that preferred the specified choice + // but did not contribute towards finalizing the specified choice + RecordPollPreference(choice int) + // RecordUnsuccessfulPoll resets the snowflake counter of this instance RecordUnsuccessfulPoll() @@ -130,6 +139,10 @@ type UnarySnowball interface { // RecordSuccessfulPoll records a successful poll towards finalizing RecordSuccessfulPoll() + // RecordPollPreference records a poll that strengthens the preference but + // did not contribute towards finalizing + RecordPollPreference() + // RecordUnsuccessfulPoll resets the snowflake counter of this instance RecordUnsuccessfulPoll() diff --git a/snow/consensus/snowball/consensus_performance_test.go b/snow/consensus/snowball/consensus_performance_test.go index b4aa2c53722d..a84e1e60a9c7 100644 --- a/snow/consensus/snowball/consensus_performance_test.go +++ b/snow/consensus/snowball/consensus_performance_test.go @@ -11,46 +11,87 @@ import ( "github.com/ava-labs/avalanchego/utils/sampler" ) -func TestSnowballOptimized(t *testing.T) { +// Test that a network running the lower AlphaPreference converges faster than a +// network running equal Alpha values. +func TestDualAlphaOptimization(t *testing.T) { require := require.New(t) numColors := 10 numNodes := 100 params := Parameters{ - K: 20, Alpha: 15, BetaVirtuous: 20, BetaRogue: 30, + K: 20, + AlphaPreference: 15, + AlphaConfidence: 15, + BetaVirtuous: 15, + BetaRogue: 20, } seed := int64(0) - nBitwise := Network{} - nBitwise.Initialize(params, numColors) + singleAlphaNetwork := Network{} + singleAlphaNetwork.Initialize(params, numColors) - nNaive := nBitwise + params.AlphaPreference = params.K/2 + 1 + dualAlphaNetwork := Network{} + dualAlphaNetwork.Initialize(params, numColors) sampler.Seed(seed) for i := 0; i < numNodes; i++ { - nBitwise.AddNode(NewTree) + dualAlphaNetwork.AddNode(NewTree) } sampler.Seed(seed) for i := 0; i < numNodes; i++ { - nNaive.AddNode(NewFlat) + singleAlphaNetwork.AddNode(NewTree) } + // Although this can theoretically fail with a correct implementation, it + // shouldn't in practice + runNetworksInLockstep(require, seed, &dualAlphaNetwork, &singleAlphaNetwork) +} + +// Test that a network running the snowball tree converges faster than a network +// running the flat snowball protocol. +func TestTreeConvergenceOptimization(t *testing.T) { + require := require.New(t) + + numColors := 10 + numNodes := 100 + params := DefaultParameters + seed := int64(0) + + treeNetwork := Network{} + treeNetwork.Initialize(params, numColors) + + flatNetwork := treeNetwork + + sampler.Seed(seed) + for i := 0; i < numNodes; i++ { + treeNetwork.AddNode(NewTree) + } + + sampler.Seed(seed) + for i := 0; i < numNodes; i++ { + flatNetwork.AddNode(NewFlat) + } + + // Although this can theoretically fail with a correct implementation, it + // shouldn't in practice + runNetworksInLockstep(require, seed, &treeNetwork, &flatNetwork) +} + +func runNetworksInLockstep(require *require.Assertions, seed int64, fast *Network, slow *Network) { numRounds := 0 - for !nBitwise.Finalized() && !nBitwise.Disagreement() && !nNaive.Finalized() && !nNaive.Disagreement() { + for !fast.Finalized() && !fast.Disagreement() && !slow.Finalized() && !slow.Disagreement() { sampler.Seed(int64(numRounds) + seed) - nBitwise.Round() + fast.Round() sampler.Seed(int64(numRounds) + seed) - nNaive.Round() + slow.Round() numRounds++ } - require.False(nBitwise.Disagreement()) - require.False(nNaive.Disagreement()) - - // Although this can theoretically fail with a correct implementation, it - // shouldn't in practice - require.True(nBitwise.Finalized()) - require.True(nBitwise.Agreement()) + require.False(fast.Disagreement()) + require.False(slow.Disagreement()) + require.True(fast.Finalized()) + require.True(fast.Agreement()) } diff --git a/snow/consensus/snowball/consensus_reversibility_test.go b/snow/consensus/snowball/consensus_reversibility_test.go index d3549edc839a..fd03a0411581 100644 --- a/snow/consensus/snowball/consensus_reversibility_test.go +++ b/snow/consensus/snowball/consensus_reversibility_test.go @@ -18,9 +18,7 @@ func TestSnowballGovernance(t *testing.T) { numNodes := 100 numByzantine := 10 numRed := 55 - params := Parameters{ - K: 20, Alpha: 15, BetaVirtuous: 20, BetaRogue: 30, - } + params := DefaultParameters seed := int64(0) nBitwise := Network{} diff --git a/snow/consensus/snowball/flat.go b/snow/consensus/snowball/flat.go index 25bb8c85f655..7f633efb8006 100644 --- a/snow/consensus/snowball/flat.go +++ b/snow/consensus/snowball/flat.go @@ -27,11 +27,18 @@ type Flat struct { } func (f *Flat) RecordPoll(votes bag.Bag[ids.ID]) bool { - if pollMode, numVotes := votes.Mode(); numVotes >= f.params.Alpha { + pollMode, numVotes := votes.Mode() + switch { + // AlphaConfidence is guaranteed to be >= AlphaPreference, so we must check + // if the poll had enough votes to increase the confidence first. + case numVotes >= f.params.AlphaConfidence: f.RecordSuccessfulPoll(pollMode) return true + case numVotes >= f.params.AlphaPreference: + f.RecordPollPreference(pollMode) + return true + default: + f.RecordUnsuccessfulPoll() + return false } - - f.RecordUnsuccessfulPoll() - return false } diff --git a/snow/consensus/snowball/flat_test.go b/snow/consensus/snowball/flat_test.go index 22665e610785..dac78fc0cede 100644 --- a/snow/consensus/snowball/flat_test.go +++ b/snow/consensus/snowball/flat_test.go @@ -15,7 +15,11 @@ func TestFlat(t *testing.T) { require := require.New(t) params := Parameters{ - K: 2, Alpha: 2, BetaVirtuous: 1, BetaRogue: 2, + K: 3, + AlphaPreference: 2, + AlphaConfidence: 3, + BetaVirtuous: 1, + BetaRogue: 2, } f := NewFlat(params, Red) f.Add(Green) @@ -24,24 +28,35 @@ func TestFlat(t *testing.T) { require.Equal(Red, f.Preference()) require.False(f.Finalized()) - twoBlue := bag.Of(Blue, Blue) - require.True(f.RecordPoll(twoBlue)) + threeBlue := bag.Of(Blue, Blue, Blue) + require.True(f.RecordPoll(threeBlue)) require.Equal(Blue, f.Preference()) require.False(f.Finalized()) - oneRedOneBlue := bag.Of(Red, Blue) - require.False(f.RecordPoll(oneRedOneBlue)) + twoGreen := bag.Of(Green, Green) + require.True(f.RecordPoll(twoGreen)) require.Equal(Blue, f.Preference()) require.False(f.Finalized()) - require.True(f.RecordPoll(twoBlue)) - require.Equal(Blue, f.Preference()) + threeGreen := bag.Of(Green, Green, Green) + require.True(f.RecordPoll(threeGreen)) + require.Equal(Green, f.Preference()) require.False(f.Finalized()) - require.True(f.RecordPoll(twoBlue)) - require.Equal(Blue, f.Preference()) + // Reset the confidence from previous round + oneEach := bag.Of(Red, Green, Blue) + require.False(f.RecordPoll(oneEach)) + require.Equal(Green, f.Preference()) + require.False(f.Finalized()) + + require.True(f.RecordPoll(threeGreen)) + require.Equal(Green, f.Preference()) + require.False(f.Finalized()) // Not finalized before BetaRogue rounds + + require.True(f.RecordPoll(threeGreen)) + require.Equal(Green, f.Preference()) require.True(f.Finalized()) - expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF(Confidence = 2, Finalized = true, SL(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES)))" + expected := "SB(Preference = 2mcwQKiD8VEspmMJpL1dc7okQQ5dDVAWeCBZ7FWBFAbxpv3t7w, PreferenceStrength = 4, SF(Confidence = 2, Finalized = true, SL(Preference = 2mcwQKiD8VEspmMJpL1dc7okQQ5dDVAWeCBZ7FWBFAbxpv3t7w)))" require.Equal(expected, f.String()) } diff --git a/snow/consensus/snowball/nnary_snowball.go b/snow/consensus/snowball/nnary_snowball.go index fb6412cf2690..0fe8c25f8617 100644 --- a/snow/consensus/snowball/nnary_snowball.go +++ b/snow/consensus/snowball/nnary_snowball.go @@ -15,7 +15,7 @@ func newNnarySnowball(betaVirtuous, betaRogue int, choice ids.ID) nnarySnowball return nnarySnowball{ nnarySnowflake: newNnarySnowflake(betaVirtuous, betaRogue, choice), preference: choice, - numSuccessfulPolls: make(map[ids.ID]int), + preferenceStrength: make(map[ids.ID]int), } } @@ -24,17 +24,16 @@ type nnarySnowball struct { // wrap the n-nary snowflake logic nnarySnowflake - // preference is the choice with the largest number of successful polls. - // Ties are broken by switching choice lazily + // preference is the choice with the largest number of polls which preferred + // it. Ties are broken by switching choice lazily preference ids.ID - // maxSuccessfulPolls maximum number of successful polls this instance has - // gotten for any choice - maxSuccessfulPolls int + // maxPreferenceStrength is the maximum value stored in [preferenceStrength] + maxPreferenceStrength int - // numSuccessfulPolls tracks the total number of successful network polls of - // the choices - numSuccessfulPolls map[ids.ID]int + // preferenceStrength tracks the total number of network polls which + // preferred that choice + preferenceStrength map[ids.ID]int } func (sb *nnarySnowball) Preference() ids.ID { @@ -49,18 +48,26 @@ func (sb *nnarySnowball) Preference() ids.ID { } func (sb *nnarySnowball) RecordSuccessfulPoll(choice ids.ID) { - numSuccessfulPolls := sb.numSuccessfulPolls[choice] + 1 - sb.numSuccessfulPolls[choice] = numSuccessfulPolls - - if numSuccessfulPolls > sb.maxSuccessfulPolls { - sb.preference = choice - sb.maxSuccessfulPolls = numSuccessfulPolls - } - + sb.increasePreferenceStrength(choice) sb.nnarySnowflake.RecordSuccessfulPoll(choice) } +func (sb *nnarySnowball) RecordPollPreference(choice ids.ID) { + sb.increasePreferenceStrength(choice) + sb.nnarySnowflake.RecordPollPreference(choice) +} + func (sb *nnarySnowball) String() string { - return fmt.Sprintf("SB(Preference = %s, NumSuccessfulPolls = %d, %s)", - sb.preference, sb.maxSuccessfulPolls, &sb.nnarySnowflake) + return fmt.Sprintf("SB(Preference = %s, PreferenceStrength = %d, %s)", + sb.preference, sb.maxPreferenceStrength, &sb.nnarySnowflake) +} + +func (sb *nnarySnowball) increasePreferenceStrength(choice ids.ID) { + preferenceStrength := sb.preferenceStrength[choice] + 1 + sb.preferenceStrength[choice] = preferenceStrength + + if preferenceStrength > sb.maxPreferenceStrength { + sb.preference = choice + sb.maxPreferenceStrength = preferenceStrength + } } diff --git a/snow/consensus/snowball/nnary_snowball_test.go b/snow/consensus/snowball/nnary_snowball_test.go index 2ce223b3072d..10b63ce647cb 100644 --- a/snow/consensus/snowball/nnary_snowball_test.go +++ b/snow/consensus/snowball/nnary_snowball_test.go @@ -30,8 +30,20 @@ func TestNnarySnowball(t *testing.T) { require.Equal(Blue, sb.Preference()) require.False(sb.Finalized()) + sb.RecordPollPreference(Red) + require.Equal(Red, sb.Preference()) + require.False(sb.Finalized()) + + sb.RecordSuccessfulPoll(Red) + require.Equal(Red, sb.Preference()) + require.False(sb.Finalized()) + + sb.RecordPollPreference(Blue) + require.Equal(Red, sb.Preference()) + require.False(sb.Finalized()) + sb.RecordSuccessfulPoll(Blue) - require.Equal(Blue, sb.Preference()) + require.Equal(Red, sb.Preference()) require.False(sb.Finalized()) sb.RecordSuccessfulPoll(Blue) @@ -83,7 +95,7 @@ func TestNarySnowballRecordUnsuccessfulPoll(t *testing.T) { require.Equal(Blue, sb.Preference()) require.True(sb.Finalized()) - expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF(Confidence = 2, Finalized = true, SL(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES)))" + expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, PreferenceStrength = 3, SF(Confidence = 2, Finalized = true, SL(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES)))" require.Equal(expected, sb.String()) for i := 0; i < 4; i++ { diff --git a/snow/consensus/snowball/nnary_snowflake.go b/snow/consensus/snowball/nnary_snowflake.go index c9f3f0d8f701..503fcd614c7b 100644 --- a/snow/consensus/snowball/nnary_snowflake.go +++ b/snow/consensus/snowball/nnary_snowflake.go @@ -67,6 +67,15 @@ func (sf *nnarySnowflake) RecordSuccessfulPoll(choice ids.ID) { sf.nnarySlush.RecordSuccessfulPoll(choice) } +func (sf *nnarySnowflake) RecordPollPreference(choice ids.ID) { + if sf.finalized { + return // This instance is already decided. + } + + sf.confidence = 0 + sf.nnarySlush.RecordSuccessfulPoll(choice) +} + func (sf *nnarySnowflake) RecordUnsuccessfulPoll() { sf.confidence = 0 } diff --git a/snow/consensus/snowball/nnary_snowflake_test.go b/snow/consensus/snowball/nnary_snowflake_test.go index e0200d076b9b..07601a6065eb 100644 --- a/snow/consensus/snowball/nnary_snowflake_test.go +++ b/snow/consensus/snowball/nnary_snowflake_test.go @@ -26,6 +26,10 @@ func TestNnarySnowflake(t *testing.T) { require.Equal(Blue, sf.Preference()) require.False(sf.Finalized()) + sf.RecordPollPreference(Red) + require.Equal(Red, sf.Preference()) + require.False(sf.Finalized()) + sf.RecordSuccessfulPoll(Red) require.Equal(Red, sf.Preference()) require.False(sf.Finalized()) @@ -34,11 +38,48 @@ func TestNnarySnowflake(t *testing.T) { require.Equal(Red, sf.Preference()) require.True(sf.Finalized()) + sf.RecordPollPreference(Blue) + require.Equal(Red, sf.Preference()) + require.True(sf.Finalized()) + sf.RecordSuccessfulPoll(Blue) require.Equal(Red, sf.Preference()) require.True(sf.Finalized()) } +func TestNnarySnowflakeConfidenceReset(t *testing.T) { + require := require.New(t) + + betaVirtuous := 4 + betaRogue := 4 + + sf := newNnarySnowflake(betaVirtuous, betaRogue, Red) + sf.Add(Blue) + sf.Add(Green) + + require.Equal(Red, sf.Preference()) + require.False(sf.Finalized()) + + // Increase Blue's confidence without finalizing + for i := 0; i < betaRogue-1; i++ { + sf.RecordSuccessfulPoll(Blue) + require.Equal(Blue, sf.Preference()) + require.False(sf.Finalized()) + } + + // Increase Red's confidence without finalizing + for i := 0; i < betaRogue-1; i++ { + sf.RecordSuccessfulPoll(Red) + require.Equal(Red, sf.Preference()) + require.False(sf.Finalized()) + } + + // One more round of voting for Red should accept Red + sf.RecordSuccessfulPoll(Red) + require.Equal(Red, sf.Preference()) + require.True(sf.Finalized()) +} + func TestVirtuousNnarySnowflake(t *testing.T) { require := require.New(t) diff --git a/snow/consensus/snowball/parameters.go b/snow/consensus/snowball/parameters.go index 482b442d73c7..29bb0ba9e215 100644 --- a/snow/consensus/snowball/parameters.go +++ b/snow/consensus/snowball/parameters.go @@ -37,7 +37,8 @@ const ( var ( DefaultParameters = Parameters{ K: 20, - Alpha: 15, + AlphaPreference: 15, + AlphaConfidence: 15, BetaVirtuous: 15, BetaRogue: 20, ConcurrentRepolls: 4, @@ -51,11 +52,26 @@ var ( // Parameters required for snowball consensus type Parameters struct { - K int `json:"k" yaml:"k"` - Alpha int `json:"alpha" yaml:"alpha"` - BetaVirtuous int `json:"betaVirtuous" yaml:"betaVirtuous"` - BetaRogue int `json:"betaRogue" yaml:"betaRogue"` + // K is the number of nodes to query and sample in a round. + K int `json:"k" yaml:"k"` + // Alpha is used for backwards compatibility purposes and is only referenced + // during json parsing. + Alpha *int `json:"alpha,omitempty" yaml:"alpha,omitempty"` + // AlphaPreference is the vote threshold to change your preference. + AlphaPreference int `json:"alphaPreference" yaml:"alphaPreference"` + // AlphaConfidence is the vote threshold to increase your confidence. + AlphaConfidence int `json:"alphaConfidence" yaml:"alphaConfidence"` + // BetaVirtuous is the number of consecutive successful queries required for + // finalization on a virtuous instance. + BetaVirtuous int `json:"betaVirtuous" yaml:"betaVirtuous"` + // BetaRogue is the number of consecutive successful queries required for + // finalization on a rogue instance. + BetaRogue int `json:"betaRogue" yaml:"betaRogue"` + // ConcurrentRepolls is the number of outstanding polls the engine will + // target to have while there is something processing. ConcurrentRepolls int `json:"concurrentRepolls" yaml:"concurrentRepolls"` + // OptimalProcessing is used to limit block creation when a large number of + // blocks are processing. OptimalProcessing int `json:"optimalProcessing" yaml:"optimalProcessing"` // Reports unhealthy if more than this number of items are outstanding. @@ -67,12 +83,26 @@ type Parameters struct { } // Verify returns nil if the parameters describe a valid initialization. +// +// An initialization is valid if the following conditions are met: +// +// - K/2 < AlphaPreference <= AlphaConfidence <= K +// - 0 < BetaVirtuous <= BetaRogue +// - 0 < ConcurrentRepolls <= BetaRogue +// - 0 < OptimalProcessing +// - 0 < MaxOutstandingItems +// - 0 < MaxItemProcessingTime +// +// Note: K/2 < K implies that 0 <= K/2, so we don't need an explicit check that +// AlphaPreference is positive. func (p Parameters) Verify() error { switch { - case p.Alpha <= p.K/2: - return fmt.Errorf("%w: k = %d, alpha = %d: fails the condition that: k/2 < alpha", ErrParametersInvalid, p.K, p.Alpha) - case p.K < p.Alpha: - return fmt.Errorf("%w: k = %d, alpha = %d: fails the condition that: alpha <= k", ErrParametersInvalid, p.K, p.Alpha) + case p.AlphaPreference <= p.K/2: + return fmt.Errorf("%w: k = %d, alphaPreference = %d: fails the condition that: k/2 < alphaPreference", ErrParametersInvalid, p.K, p.AlphaPreference) + case p.AlphaConfidence < p.AlphaPreference: + return fmt.Errorf("%w: alphaPreference = %d, alphaConfidence = %d: fails the condition that: alphaPreference <= alphaConfidence", ErrParametersInvalid, p.AlphaPreference, p.AlphaConfidence) + case p.K < p.AlphaConfidence: + return fmt.Errorf("%w: k = %d, alphaConfidence = %d: fails the condition that: alphaConfidence <= k", ErrParametersInvalid, p.K, p.AlphaConfidence) case p.BetaVirtuous <= 0: return fmt.Errorf("%w: betaVirtuous = %d: fails the condition that: 0 < betaVirtuous", ErrParametersInvalid, p.BetaVirtuous) case p.BetaRogue == 3 && p.BetaVirtuous == 28: @@ -95,8 +125,9 @@ func (p Parameters) Verify() error { } func (p Parameters) MinPercentConnectedHealthy() float64 { - alpha := p.Alpha - k := p.K - r := float64(alpha) / float64(k) - return r*(1-MinPercentConnectedBuffer) + MinPercentConnectedBuffer + // AlphaConfidence is used here to ensure that the node can still feasibly + // accept operations. If AlphaPreference were used, committing could be + // extremely unlikely to happen, even while healthy. + alphaRatio := float64(p.AlphaConfidence) / float64(p.K) + return alphaRatio*(1-MinPercentConnectedBuffer) + MinPercentConnectedBuffer } diff --git a/snow/consensus/snowball/parameters_test.go b/snow/consensus/snowball/parameters_test.go index f6172f435d75..26ffab8763c7 100644 --- a/snow/consensus/snowball/parameters_test.go +++ b/snow/consensus/snowball/parameters_test.go @@ -4,217 +4,251 @@ package snowball import ( - "fmt" "testing" "github.com/stretchr/testify/require" ) func TestParametersVerify(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - require.NoError(t, p.Verify()) -} - -func TestParametersAnotherVerify(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 28, - BetaRogue: 30, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - require.NoError(t, p.Verify()) -} - -func TestParametersYetAnotherVerify(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 3, - BetaRogue: 3, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - require.NoError(t, p.Verify()) -} - -func TestParametersInvalidK(t *testing.T) { - p := Parameters{ - K: 0, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) -} - -func TestParametersInvalidAlpha(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 0, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) -} - -func TestParametersInvalidBetaVirtuous(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 0, - BetaRogue: 1, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) -} - -func TestParametersInvalidBetaRogue(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 0, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) -} - -func TestParametersAnotherInvalidBetaRogue(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 28, - BetaRogue: 3, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) -} - -func TestParametersInvalidConcurrentRepolls(t *testing.T) { - tests := []Parameters{ - { - K: 1, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 2, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - }, - { - K: 1, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 0, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, + tests := []struct { + name string + params Parameters + expectedError error + }{ + { + name: "valid", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: nil, + }, + { + name: "invalid K", + params: Parameters{ + K: 0, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "invalid AlphaPreference 1", + params: Parameters{ + K: 2, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "invalid AlphaPreference 0", + params: Parameters{ + K: 1, + AlphaPreference: 0, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "invalid AlphaConfidence", + params: Parameters{ + K: 3, + AlphaPreference: 3, + AlphaConfidence: 2, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "invalid BetaVirtuous", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 0, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "first half fun BetaRogue", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 28, + BetaRogue: 30, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: nil, + }, + { + name: "second half fun BetaRogue", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 2, + BetaRogue: 3, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: nil, + }, + { + name: "fun invalid BetaRogue", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 28, + BetaRogue: 3, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "invalid BetaRogue", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 2, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "too few ConcurrentRepolls", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 0, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "too many ConcurrentRepolls", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 2, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "invalid OptimalProcessing", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 0, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "invalid MaxOutstandingItems", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 0, + MaxItemProcessingTime: 1, + }, + expectedError: ErrParametersInvalid, + }, + { + name: "invalid MaxItemProcessingTime", + params: Parameters{ + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 1, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 0, + }, + expectedError: ErrParametersInvalid, }, } - for _, p := range tests { - label := fmt.Sprintf("ConcurrentRepolls=%d", p.ConcurrentRepolls) - t.Run(label, func(t *testing.T) { - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.params.Verify() + require.ErrorIs(t, err, test.expectedError) }) } } -func TestParametersInvalidOptimalProcessing(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 1, - OptimalProcessing: 0, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 1, - } - - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) -} - -func TestParametersInvalidMaxOutstandingItems(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 0, - MaxItemProcessingTime: 1, - } - - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) -} - -func TestParametersInvalidMaxItemProcessingTime(t *testing.T) { - p := Parameters{ - K: 1, - Alpha: 1, - BetaVirtuous: 1, - BetaRogue: 1, - ConcurrentRepolls: 1, - OptimalProcessing: 1, - MaxOutstandingItems: 1, - MaxItemProcessingTime: 0, - } - - err := p.Verify() - require.ErrorIs(t, err, ErrParametersInvalid) -} - func TestParametersMinPercentConnectedHealthy(t *testing.T) { tests := []struct { name string @@ -229,17 +263,25 @@ func TestParametersMinPercentConnectedHealthy(t *testing.T) { { name: "custom", params: Parameters{ - K: 60, - Alpha: 15, + K: 5, + AlphaConfidence: 4, + }, + expectedMinPercentConnected: 0.84, + }, + { + name: "custom", + params: Parameters{ + K: 1001, + AlphaConfidence: 501, }, - expectedMinPercentConnected: 0.4, + expectedMinPercentConnected: 0.6, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { minStake := tt.params.MinPercentConnectedHealthy() - require.Equal(t, tt.expectedMinPercentConnected, minStake) + require.InEpsilon(t, tt.expectedMinPercentConnected, minStake, .001) }) } } diff --git a/snow/consensus/snowball/tree.go b/snow/consensus/snowball/tree.go index 8ea185745e22..052e75ec8d35 100644 --- a/snow/consensus/snowball/tree.go +++ b/snow/consensus/snowball/tree.go @@ -414,7 +414,15 @@ func (u *unaryNode) RecordPoll(votes bag.Bag[ids.ID], reset bool) (node, bool) { u.shouldReset = true // Make sure my child is also reset correctly } - if votes.Len() < u.tree.params.Alpha { + switch numVotes := votes.Len(); { + case numVotes >= u.tree.params.AlphaConfidence: + // I got enough votes to increase my confidence + u.snowball.RecordSuccessfulPoll() + case numVotes >= u.tree.params.AlphaPreference: + // I got enough votes to update my preference, but not increase my + // confidence. + u.snowball.RecordPollPreference() + default: // I didn't get enough votes, I must reset and my child must reset as // well u.snowball.RecordUnsuccessfulPoll() @@ -422,9 +430,6 @@ func (u *unaryNode) RecordPoll(votes bag.Bag[ids.ID], reset bool) (node, bool) { return u, false } - // I got enough votes this time - u.snowball.RecordSuccessfulPoll() - if u.child != nil { // We are guaranteed that u.commonPrefix will equal // u.child.DecidedPrefix(). Otherwise, there must have been a @@ -522,7 +527,7 @@ func (b *binaryNode) RecordPoll(votes bag.Bag[ids.ID], reset bool) (node, bool) bit := 0 // We only care about which bit is set if a successful poll can happen - if splitVotes[1].Len() >= b.tree.params.Alpha { + if splitVotes[1].Len() >= b.tree.params.AlphaPreference { bit = 1 } @@ -534,16 +539,21 @@ func (b *binaryNode) RecordPoll(votes bag.Bag[ids.ID], reset bool) (node, bool) b.shouldReset[1-bit] = true // They didn't get the threshold of votes prunedVotes := splitVotes[bit] - if prunedVotes.Len() < b.tree.params.Alpha { + switch numVotes := prunedVotes.Len(); { + case numVotes >= b.tree.params.AlphaConfidence: + // I got enough votes to increase my confidence. + b.snowball.RecordSuccessfulPoll(bit) + case numVotes >= b.tree.params.AlphaPreference: + // I got enough votes to update my preference, but not increase my + // confidence. + b.snowball.RecordPollPreference(bit) + default: b.snowball.RecordUnsuccessfulPoll() // The winning child didn't get enough votes either b.shouldReset[bit] = true return b, false } - // This bit got alpha votes, it was a successful poll - b.snowball.RecordSuccessfulPoll(bit) - if child := b.children[bit]; child != nil { // The votes are filtered to ensure that they are votes that should // count for the child diff --git a/snow/consensus/snowball/tree_test.go b/snow/consensus/snowball/tree_test.go index 1879b65e64bf..4aff386174ed 100644 --- a/snow/consensus/snowball/tree_test.go +++ b/snow/consensus/snowball/tree_test.go @@ -14,15 +14,17 @@ import ( "github.com/ava-labs/avalanchego/utils/sampler" ) -const ( - initialUnaryDescription = "SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 256)" -) +const initialUnaryDescription = "SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 256)" func TestSnowballSingleton(t *testing.T) { require := require.New(t) params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 2, BetaRogue: 5, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 2, + BetaRogue: 5, } tree := NewTree(params, Red) @@ -59,7 +61,11 @@ func TestSnowballRecordUnsuccessfulPoll(t *testing.T) { require := require.New(t) params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 3, BetaRogue: 5, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 3, + BetaRogue: 5, } tree := NewTree(params, Red) @@ -85,7 +91,11 @@ func TestSnowballBinary(t *testing.T) { require := require.New(t) params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, Red) tree.Add(Blue) @@ -124,7 +134,11 @@ func TestSnowballLastBinary(t *testing.T) { } params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 2, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 2, + BetaRogue: 2, } tree := NewTree(params, zero) tree.Add(one) @@ -132,8 +146,8 @@ func TestSnowballLastBinary(t *testing.T) { // Should do nothing tree.Add(one) - expected := "SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 255)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 255" + expected := "SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 255)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 255" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -143,15 +157,15 @@ func TestSnowballLastBinary(t *testing.T) { require.Equal(one, tree.Preference()) require.False(tree.Finalized()) - expected = "SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = false)) Bits = [0, 255)\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 255" + expected = "SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = false)) Bits = [0, 255)\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 255" require.Equal(expected, tree.String()) require.True(tree.RecordPoll(oneBag)) require.Equal(one, tree.Preference()) require.True(tree.Finalized()) - expected = "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 2, SF(Confidence = 2, Finalized = true, SL(Preference = 1))) Bit = 255" + expected = "SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 2, SF(Confidence = 2, Finalized = true, SL(Preference = 1))) Bit = 255" require.Equal(expected, tree.String()) } @@ -164,19 +178,23 @@ func TestSnowballAddPreviouslyRejected(t *testing.T) { four := ids.ID{0b00000100} params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, zero) tree.Add(one) tree.Add(four) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 2)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 2)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -186,11 +204,11 @@ func TestSnowballAddPreviouslyRejected(t *testing.T) { require.True(tree.RecordPoll(zeroBag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -199,11 +217,11 @@ func TestSnowballAddPreviouslyRejected(t *testing.T) { tree.Add(two) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -217,15 +235,19 @@ func TestSnowballNewUnary(t *testing.T) { one := ids.ID{0b00000001} params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 2, BetaRogue: 3, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 2, + BetaRogue: 3, } tree := NewTree(params, zero) tree.Add(one) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -235,9 +257,9 @@ func TestSnowballNewUnary(t *testing.T) { require.True(tree.RecordPoll(oneBag)) { - expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(one, tree.Preference()) require.False(tree.Finalized()) @@ -246,9 +268,9 @@ func TestSnowballNewUnary(t *testing.T) { require.True(tree.RecordPoll(oneBag)) { - expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 2, SF(Confidence = 2, Finalized = false, SL(Preference = 1))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + - " SB(NumSuccessfulPolls = 2, SF(Confidence = 2, Finalized = true)) Bits = [1, 256)" + expected := "SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 2, SF(Confidence = 2, Finalized = false, SL(Preference = 1))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + + " SB(PreferenceStrength = 2, SF(Confidence = 2, Finalized = true)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(one, tree.Preference()) require.False(tree.Finalized()) @@ -263,20 +285,24 @@ func TestSnowballTransitiveReset(t *testing.T) { eight := ids.ID{0b00001000} params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 2, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 2, + BetaRogue: 2, } tree := NewTree(params, zero) tree.Add(two) tree.Add(eight) { - expected := "SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 1)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 3)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 3\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" + expected := "SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 1)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 1\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 3)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 3\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -286,13 +312,13 @@ func TestSnowballTransitiveReset(t *testing.T) { require.True(tree.RecordPoll(zeroBag)) { - expected := "SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = false)) Bits = [0, 1)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = false)) Bits = [2, 3)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 3\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = false)) Bits = [4, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" + expected := "SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = false)) Bits = [0, 1)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = false)) Bits = [2, 3)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 3\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = false)) Bits = [4, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -302,13 +328,13 @@ func TestSnowballTransitiveReset(t *testing.T) { require.False(tree.RecordPoll(emptyBag)) { - expected := "SB(NumSuccessfulPolls = 1, SF(Confidence = 0, Finalized = false)) Bits = [0, 1)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = false)) Bits = [2, 3)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 3\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = false)) Bits = [4, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" + expected := "SB(PreferenceStrength = 1, SF(Confidence = 0, Finalized = false)) Bits = [0, 1)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = false)) Bits = [2, 3)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 3\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = false)) Bits = [4, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -317,13 +343,13 @@ func TestSnowballTransitiveReset(t *testing.T) { require.True(tree.RecordPoll(zeroBag)) { - expected := "SB(NumSuccessfulPolls = 2, SF(Confidence = 1, Finalized = false)) Bits = [0, 1)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 2, SF(Confidence = 1, Finalized = false)) Bits = [2, 3)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 3\n" + - " SB(NumSuccessfulPolls = 2, SF(Confidence = 1, Finalized = false)) Bits = [4, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" + expected := "SB(PreferenceStrength = 2, SF(Confidence = 1, Finalized = false)) Bits = [0, 1)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + + " SB(PreferenceStrength = 2, SF(Confidence = 1, Finalized = false)) Bits = [2, 3)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 3\n" + + " SB(PreferenceStrength = 2, SF(Confidence = 1, Finalized = false)) Bits = [4, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [4, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -332,7 +358,7 @@ func TestSnowballTransitiveReset(t *testing.T) { require.True(tree.RecordPoll(zeroBag)) { - expected := "SB(NumSuccessfulPolls = 3, SF(Confidence = 2, Finalized = true)) Bits = [4, 256)" + expected := "SB(PreferenceStrength = 3, SF(Confidence = 2, Finalized = true)) Bits = [4, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.True(tree.Finalized()) @@ -343,7 +369,11 @@ func TestSnowballTrinary(t *testing.T) { require := require.New(t) params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, Green) tree.Add(Red) @@ -393,7 +423,11 @@ func TestSnowballCloseTrinary(t *testing.T) { magenta := ids.ID{0x03} params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, yellow) tree.Add(cyan) @@ -438,7 +472,11 @@ func TestSnowballAddRejected(t *testing.T) { c0010 := ids.ID{0x04} // 0010 params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, c0000) tree.Add(c1000) @@ -451,11 +489,11 @@ func TestSnowballAddRejected(t *testing.T) { require.True(tree.RecordPoll(c0010Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 2\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0010, tree.Preference()) require.False(tree.Finalized()) @@ -464,11 +502,11 @@ func TestSnowballAddRejected(t *testing.T) { tree.Add(c0101) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 2\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0010, tree.Preference()) require.False(tree.Finalized()) @@ -483,7 +521,11 @@ func TestSnowballResetChild(t *testing.T) { c1000 := ids.ID{0x01} // 1000 params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, c0000) tree.Add(c0100) @@ -496,11 +538,11 @@ func TestSnowballResetChild(t *testing.T) { require.True(tree.RecordPoll(c0000Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -510,11 +552,11 @@ func TestSnowballResetChild(t *testing.T) { require.False(tree.RecordPoll(emptyBag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -523,11 +565,11 @@ func TestSnowballResetChild(t *testing.T) { require.True(tree.RecordPoll(c0000Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 2, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 1\n" + + " SB(PreferenceStrength = 2, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -542,7 +584,11 @@ func TestSnowballResetSibling(t *testing.T) { c1000 := ids.ID{0x01} // 1000 params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, c0000) tree.Add(c0100) @@ -555,11 +601,11 @@ func TestSnowballResetSibling(t *testing.T) { require.True(tree.RecordPoll(c0100Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 1\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0100, tree.Preference()) require.False(tree.Finalized()) @@ -569,11 +615,11 @@ func TestSnowballResetSibling(t *testing.T) { require.True(tree.RecordPoll(c1000Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 0\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 0\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 1\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0100, tree.Preference()) require.False(tree.Finalized()) @@ -582,11 +628,11 @@ func TestSnowballResetSibling(t *testing.T) { require.True(tree.RecordPoll(c0100Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 2, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 2, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 2, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 1\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 2, SF(Confidence = 1, Finalized = true)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0100, tree.Preference()) require.False(tree.Finalized()) @@ -598,7 +644,11 @@ func TestSnowball5Colors(t *testing.T) { numColors := 5 params := Parameters{ - K: 5, Alpha: 5, BetaVirtuous: 20, BetaRogue: 30, + K: 5, + AlphaPreference: 5, + AlphaConfidence: 5, + BetaVirtuous: 20, + BetaRogue: 30, } colors := []ids.ID{} @@ -634,7 +684,11 @@ func TestSnowballFineGrained(t *testing.T) { c0010 := ids.ID{0x04} params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, c0000) @@ -645,9 +699,9 @@ func TestSnowballFineGrained(t *testing.T) { tree.Add(c1100) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -656,11 +710,11 @@ func TestSnowballFineGrained(t *testing.T) { tree.Add(c1000) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -669,14 +723,14 @@ func TestSnowballFineGrained(t *testing.T) { tree.Add(c0010) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 2)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 2)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -686,13 +740,13 @@ func TestSnowballFineGrained(t *testing.T) { require.True(tree.RecordPoll(c0000Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -702,9 +756,9 @@ func TestSnowballFineGrained(t *testing.T) { require.True(tree.RecordPoll(c0010Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 2\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -713,7 +767,7 @@ func TestSnowballFineGrained(t *testing.T) { require.True(tree.RecordPoll(c0010Bag)) { - expected := "SB(NumSuccessfulPolls = 2, SF(Confidence = 2, Finalized = true)) Bits = [3, 256)" + expected := "SB(PreferenceStrength = 2, SF(Confidence = 2, Finalized = true)) Bits = [3, 256)" require.Equal(expected, tree.String()) require.Equal(c0010, tree.Preference()) require.True(tree.Finalized()) @@ -724,7 +778,11 @@ func TestSnowballDoubleAdd(t *testing.T) { require := require.New(t) params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 3, BetaRogue: 5, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 3, + BetaRogue: 5, } tree := NewTree(params, Red) tree.Add(Red) @@ -740,7 +798,11 @@ func TestSnowballConsistent(t *testing.T) { numColors := 50 numNodes := 100 params := Parameters{ - K: 20, Alpha: 15, BetaVirtuous: 20, BetaRogue: 30, + K: 20, + AlphaPreference: 15, + AlphaConfidence: 15, + BetaVirtuous: 20, + BetaRogue: 30, } seed := int64(0) @@ -769,7 +831,11 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { c0010 := ids.ID{0b00000100} params := Parameters{ - K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2, + K: 1, + AlphaPreference: 1, + AlphaConfidence: 1, + BetaVirtuous: 1, + BetaRogue: 2, } tree := NewTree(params, c0000) @@ -780,9 +846,9 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { tree.Add(c1000) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -791,12 +857,12 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { tree.Add(c0010) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 2)\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 2)\n" + + " SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -806,11 +872,11 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { require.True(tree.RecordPoll(c0000Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -819,11 +885,11 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { tree.Add(c0100) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + - " SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" + + " SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -833,11 +899,77 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { require.True(tree.RecordPoll(c0100Bag)) { - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" + - " SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + - " SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)" + expected := "SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" + + " SB(PreferenceStrength = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" + + " SB(PreferenceStrength = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)" require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) } } + +func TestSnowballRecordPreferencePollBinary(t *testing.T) { + require := require.New(t) + + params := Parameters{ + K: 3, + AlphaPreference: 2, + AlphaConfidence: 3, + BetaVirtuous: 2, + BetaRogue: 2, + } + tree := NewTree(params, Red) + tree.Add(Blue) + require.Equal(Red, tree.Preference()) + require.False(tree.Finalized()) + + threeBlue := bag.Of(Blue, Blue, Blue) + require.True(tree.RecordPoll(threeBlue)) + require.Equal(Blue, tree.Preference()) + require.False(tree.Finalized()) + + twoRed := bag.Of(Red, Red) + require.True(tree.RecordPoll(twoRed)) + require.Equal(Blue, tree.Preference()) + require.False(tree.Finalized()) + + threeRed := bag.Of(Red, Red, Red) + require.True(tree.RecordPoll(threeRed)) + require.Equal(Red, tree.Preference()) + require.False(tree.Finalized()) + + require.True(tree.RecordPoll(threeRed)) + require.Equal(Red, tree.Preference()) + require.True(tree.Finalized()) +} + +func TestSnowballRecordPreferencePollUnary(t *testing.T) { + require := require.New(t) + + params := Parameters{ + K: 3, + AlphaPreference: 2, + AlphaConfidence: 3, + BetaVirtuous: 2, + BetaRogue: 2, + } + tree := NewTree(params, Red) + require.Equal(Red, tree.Preference()) + require.False(tree.Finalized()) + + twoRed := bag.Of(Red, Red) + require.True(tree.RecordPoll(twoRed)) + require.Equal(Red, tree.Preference()) + require.False(tree.Finalized()) + + tree.Add(Blue) + + threeBlue := bag.Of(Blue, Blue, Blue) + require.True(tree.RecordPoll(threeBlue)) + require.Equal(Red, tree.Preference()) + require.False(tree.Finalized()) + + require.True(tree.RecordPoll(threeBlue)) + require.Equal(Blue, tree.Preference()) + require.True(tree.Finalized()) +} diff --git a/snow/consensus/snowball/unary_snowball.go b/snow/consensus/snowball/unary_snowball.go index 36df4b3b25ee..6223d6f3a0cc 100644 --- a/snow/consensus/snowball/unary_snowball.go +++ b/snow/consensus/snowball/unary_snowball.go @@ -18,15 +18,20 @@ type unarySnowball struct { // wrap the unary snowflake logic unarySnowflake - // numSuccessfulPolls tracks the total number of successful network polls - numSuccessfulPolls int + // preferenceStrength tracks the total number of polls with a preference + preferenceStrength int } func (sb *unarySnowball) RecordSuccessfulPoll() { - sb.numSuccessfulPolls++ + sb.preferenceStrength++ sb.unarySnowflake.RecordSuccessfulPoll() } +func (sb *unarySnowball) RecordPollPreference() { + sb.preferenceStrength++ + sb.unarySnowflake.RecordUnsuccessfulPoll() +} + func (sb *unarySnowball) Extend(beta int, choice int) BinarySnowball { bs := &binarySnowball{ binarySnowflake: binarySnowflake{ @@ -37,7 +42,7 @@ func (sb *unarySnowball) Extend(beta int, choice int) BinarySnowball { }, preference: choice, } - bs.numSuccessfulPolls[choice] = sb.numSuccessfulPolls + bs.preferenceStrength[choice] = sb.preferenceStrength return bs } @@ -47,7 +52,7 @@ func (sb *unarySnowball) Clone() UnarySnowball { } func (sb *unarySnowball) String() string { - return fmt.Sprintf("SB(NumSuccessfulPolls = %d, %s)", - sb.numSuccessfulPolls, + return fmt.Sprintf("SB(PreferenceStrength = %d, %s)", + sb.preferenceStrength, &sb.unarySnowflake) } diff --git a/snow/consensus/snowball/unary_snowball_test.go b/snow/consensus/snowball/unary_snowball_test.go index 1446a243088a..6fd6cd9b40c7 100644 --- a/snow/consensus/snowball/unary_snowball_test.go +++ b/snow/consensus/snowball/unary_snowball_test.go @@ -9,10 +9,10 @@ import ( "github.com/stretchr/testify/require" ) -func UnarySnowballStateTest(t *testing.T, sb *unarySnowball, expectedNumSuccessfulPolls, expectedConfidence int, expectedFinalized bool) { +func UnarySnowballStateTest(t *testing.T, sb *unarySnowball, expectedPreferenceStrength, expectedConfidence int, expectedFinalized bool) { require := require.New(t) - require.Equal(expectedNumSuccessfulPolls, sb.numSuccessfulPolls) + require.Equal(expectedPreferenceStrength, sb.preferenceStrength) require.Equal(expectedConfidence, sb.confidence) require.Equal(expectedFinalized, sb.Finalized()) } @@ -27,25 +27,31 @@ func TestUnarySnowball(t *testing.T) { sb.RecordSuccessfulPoll() UnarySnowballStateTest(t, &sb, 1, 1, false) + sb.RecordPollPreference() + UnarySnowballStateTest(t, &sb, 2, 0, false) + + sb.RecordSuccessfulPoll() + UnarySnowballStateTest(t, &sb, 3, 1, false) + sb.RecordUnsuccessfulPoll() - UnarySnowballStateTest(t, &sb, 1, 0, false) + UnarySnowballStateTest(t, &sb, 3, 0, false) sb.RecordSuccessfulPoll() - UnarySnowballStateTest(t, &sb, 2, 1, false) + UnarySnowballStateTest(t, &sb, 4, 1, false) sbCloneIntf := sb.Clone() require.IsType(&unarySnowball{}, sbCloneIntf) sbClone := sbCloneIntf.(*unarySnowball) - UnarySnowballStateTest(t, sbClone, 2, 1, false) + UnarySnowballStateTest(t, sbClone, 4, 1, false) binarySnowball := sbClone.Extend(beta, 0) - expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0)))" + expected := "SB(Preference = 0, PreferenceStrength[0] = 4, PreferenceStrength[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0)))" require.Equal(expected, binarySnowball.String()) binarySnowball.RecordUnsuccessfulPoll() - for i := 0; i < 3; i++ { + for i := 0; i < 5; i++ { require.Zero(binarySnowball.Preference()) require.False(binarySnowball.Finalized()) binarySnowball.RecordSuccessfulPoll(1) @@ -63,6 +69,6 @@ func TestUnarySnowball(t *testing.T) { require.Equal(1, binarySnowball.Preference()) require.True(binarySnowball.Finalized()) - expected = "SB(NumSuccessfulPolls = 2, SF(Confidence = 1, Finalized = false))" + expected = "SB(PreferenceStrength = 4, SF(Confidence = 1, Finalized = false))" require.Equal(expected, sb.String()) } diff --git a/snow/consensus/snowman/consensus_test.go b/snow/consensus/snowman/consensus_test.go index 69beb061c165..401435738b18 100644 --- a/snow/consensus/snowman/consensus_test.go +++ b/snow/consensus/snowman/consensus_test.go @@ -96,7 +96,8 @@ func InitializeTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 3, BetaRogue: 5, ConcurrentRepolls: 1, @@ -120,7 +121,8 @@ func NumProcessingTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -161,7 +163,8 @@ func AddToTailTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 3, BetaRogue: 5, ConcurrentRepolls: 1, @@ -199,7 +202,8 @@ func AddToNonTailTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 3, BetaRogue: 5, ConcurrentRepolls: 1, @@ -246,7 +250,8 @@ func AddToUnknownTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 3, BetaRogue: 5, ConcurrentRepolls: 1, @@ -285,7 +290,8 @@ func StatusOrProcessingPreviouslyAcceptedTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 3, BetaRogue: 5, ConcurrentRepolls: 1, @@ -313,7 +319,8 @@ func StatusOrProcessingPreviouslyRejectedTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 3, BetaRogue: 5, ConcurrentRepolls: 1, @@ -349,7 +356,8 @@ func StatusOrProcessingUnissuedTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 3, BetaRogue: 5, ConcurrentRepolls: 1, @@ -385,7 +393,8 @@ func StatusOrProcessingIssuedTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 3, BetaRogue: 5, ConcurrentRepolls: 1, @@ -423,7 +432,8 @@ func RecordPollAcceptSingleBlockTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 2, BetaRogue: 3, ConcurrentRepolls: 1, @@ -464,7 +474,8 @@ func RecordPollAcceptAndRejectTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -519,7 +530,8 @@ func RecordPollSplitVoteNoChangeTest(t *testing.T, factory Factory) { params := snowball.Parameters{ K: 2, - Alpha: 2, + AlphaPreference: 2, + AlphaConfidence: 2, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -578,7 +590,8 @@ func RecordPollWhenFinalizedTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -602,7 +615,8 @@ func RecordPollRejectTransitivelyTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -671,7 +685,8 @@ func RecordPollTransitivelyResetConfidenceTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 2, BetaRogue: 2, ConcurrentRepolls: 1, @@ -762,7 +777,8 @@ func RecordPollInvalidVoteTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 2, BetaRogue: 2, ConcurrentRepolls: 1, @@ -802,7 +818,8 @@ func RecordPollTransitiveVotingTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 3, - Alpha: 3, + AlphaPreference: 3, + AlphaConfidence: 3, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -911,7 +928,8 @@ func RecordPollDivergedVotingTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -1013,7 +1031,8 @@ func RecordPollDivergedVotingWithNoConflictingBitTest(t *testing.T, factory Fact ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -1116,7 +1135,8 @@ func RecordPollChangePreferredChainTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 10, BetaRogue: 10, ConcurrentRepolls: 1, @@ -1222,7 +1242,8 @@ func LastAcceptedTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -1305,7 +1326,8 @@ func MetricsProcessingErrorTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1333,7 +1355,8 @@ func MetricsAcceptedErrorTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1361,7 +1384,8 @@ func MetricsRejectedErrorTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1389,7 +1413,8 @@ func ErrorOnInitialRejectionTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1427,7 +1452,8 @@ func ErrorOnAcceptTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1463,7 +1489,8 @@ func ErrorOnRejectSiblingTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1508,7 +1535,8 @@ func ErrorOnTransitiveRejectionTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1561,7 +1589,8 @@ func RandomizedConsistencyTest(t *testing.T, factory Factory) { numNodes := 100 params := snowball.Parameters{ K: 20, - Alpha: 15, + AlphaPreference: 15, + AlphaConfidence: 15, BetaVirtuous: 20, BetaRogue: 30, ConcurrentRepolls: 1, @@ -1594,7 +1623,8 @@ func ErrorOnAddDecidedBlockTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1623,7 +1653,8 @@ func ErrorOnAddDuplicateBlockIDTest(t *testing.T, factory Factory) { ctx := snow.DefaultConsensusContextTest() params := snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -1708,7 +1739,7 @@ func RecordPollWithDefaultParameters(t *testing.T, factory Factory) { require.NoError(sm.Add(context.Background(), blk2)) votes := bag.Bag[ids.ID]{} - votes.AddCount(blk1.ID(), params.Alpha) + votes.AddCount(blk1.ID(), params.AlphaConfidence) // as "blk1" and "blk2" are in conflict, we need beta rogue rounds to finalize for i := 0; i < params.BetaRogue; i++ { // should not finalize with less than beta rogue rounds diff --git a/snow/consensus/snowman/poll/early_term_no_traversal.go b/snow/consensus/snowman/poll/early_term_no_traversal.go index 53925daef811..fcad5b71932b 100644 --- a/snow/consensus/snowman/poll/early_term_no_traversal.go +++ b/snow/consensus/snowman/poll/early_term_no_traversal.go @@ -11,19 +11,24 @@ import ( ) type earlyTermNoTraversalFactory struct { - alpha int + alphaPreference int + alphaConfidence int } // NewEarlyTermNoTraversalFactory returns a factory that returns polls with // early termination, without doing DAG traversals -func NewEarlyTermNoTraversalFactory(alpha int) Factory { - return &earlyTermNoTraversalFactory{alpha: alpha} +func NewEarlyTermNoTraversalFactory(alphaPreference int, alphaConfidence int) Factory { + return &earlyTermNoTraversalFactory{ + alphaPreference: alphaPreference, + alphaConfidence: alphaConfidence, + } } func (f *earlyTermNoTraversalFactory) New(vdrs bag.Bag[ids.NodeID]) Poll { return &earlyTermNoTraversalPoll{ - polled: vdrs, - alpha: f.alpha, + polled: vdrs, + alphaPreference: f.alphaPreference, + alphaConfidence: f.alphaConfidence, } } @@ -31,9 +36,10 @@ func (f *earlyTermNoTraversalFactory) New(vdrs bag.Bag[ids.NodeID]) Poll { // the result of the poll. However, does not terminate tightly with this bound. // It terminates as quickly as it can without performing any DAG traversals. type earlyTermNoTraversalPoll struct { - votes bag.Bag[ids.ID] - polled bag.Bag[ids.NodeID] - alpha int + votes bag.Bag[ids.ID] + polled bag.Bag[ids.NodeID] + alphaPreference int + alphaConfidence int } // Vote registers a response for this poll @@ -54,9 +60,12 @@ func (p *earlyTermNoTraversalPoll) Drop(vdr ids.NodeID) { // Finished returns true when one of the following conditions is met. // // 1. There are no outstanding votes. -// 2. It is impossible for the poll to achieve an alpha majority after applying +// 2. It is impossible for the poll to achieve an alphaPreference majority +// after applying transitive voting. +// 3. A single element has achieved an alphaPreference majority and it is +// impossible for it to achieve an alphaConfidence majority after applying // transitive voting. -// 3. A single element has achieved an alpha majority. +// 4. A single element has achieved an alphaConfidence majority. func (p *earlyTermNoTraversalPoll) Finished() bool { remaining := p.polled.Len() if remaining == 0 { @@ -65,12 +74,13 @@ func (p *earlyTermNoTraversalPoll) Finished() bool { received := p.votes.Len() maxPossibleVotes := received + remaining - if maxPossibleVotes < p.alpha { + if maxPossibleVotes < p.alphaPreference { return true // Case 2 } _, freq := p.votes.Mode() - return freq >= p.alpha // Case 3 + return freq >= p.alphaPreference && maxPossibleVotes < p.alphaConfidence || // Case 3 + freq >= p.alphaConfidence // Case 4 } // Result returns the result of this poll diff --git a/snow/consensus/snowman/poll/early_term_no_traversal_test.go b/snow/consensus/snowman/poll/early_term_no_traversal_test.go index 7fe7d55ec79a..8255818abdbb 100644 --- a/snow/consensus/snowman/poll/early_term_no_traversal_test.go +++ b/snow/consensus/snowman/poll/early_term_no_traversal_test.go @@ -17,7 +17,7 @@ func TestEarlyTermNoTraversalResults(t *testing.T) { vdrs := bag.Of(vdr1) // k = 1 alpha := 1 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) poll := factory.New(vdrs) poll.Vote(vdr1, blkID1) @@ -34,7 +34,7 @@ func TestEarlyTermNoTraversalString(t *testing.T) { vdrs := bag.Of(vdr1, vdr2) // k = 2 alpha := 2 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) poll := factory.New(vdrs) poll.Vote(vdr1, blkID1) @@ -52,7 +52,7 @@ func TestEarlyTermNoTraversalDropsDuplicatedVotes(t *testing.T) { vdrs := bag.Of(vdr1, vdr2) // k = 2 alpha := 2 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) poll := factory.New(vdrs) poll.Vote(vdr1, blkID1) @@ -66,13 +66,13 @@ func TestEarlyTermNoTraversalDropsDuplicatedVotes(t *testing.T) { } // Tests case 2 -func TestEarlyTermNoTraversalTerminatesEarlyWithoutAlpha(t *testing.T) { +func TestEarlyTermNoTraversalTerminatesEarlyWithoutAlphaPreference(t *testing.T) { require := require.New(t) vdrs := bag.Of(vdr1, vdr2, vdr3) // k = 3 alpha := 2 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) poll := factory.New(vdrs) poll.Drop(vdr1) @@ -83,13 +83,38 @@ func TestEarlyTermNoTraversalTerminatesEarlyWithoutAlpha(t *testing.T) { } // Tests case 3 -func TestEarlyTermNoTraversalTerminatesEarlyWithAlpha(t *testing.T) { +func TestEarlyTermNoTraversalTerminatesEarlyWithAlphaPreference(t *testing.T) { require := require.New(t) vdrs := bag.Of(vdr1, vdr2, vdr3, vdr4, vdr5) // k = 5 - alpha := 3 + alphaPreference := 3 + alphaConfidence := 5 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alphaPreference, alphaConfidence) + poll := factory.New(vdrs) + + poll.Vote(vdr1, blkID1) + require.False(poll.Finished()) + + poll.Vote(vdr2, blkID1) + require.False(poll.Finished()) + + poll.Vote(vdr3, blkID1) + require.False(poll.Finished()) + + poll.Drop(vdr4) + require.True(poll.Finished()) +} + +// Tests case 4 +func TestEarlyTermNoTraversalTerminatesEarlyWithAlphaConfidence(t *testing.T) { + require := require.New(t) + + vdrs := bag.Of(vdr1, vdr2, vdr3, vdr4, vdr5) // k = 5 + alphaPreference := 3 + alphaConfidence := 3 + + factory := NewEarlyTermNoTraversalFactory(alphaPreference, alphaConfidence) poll := factory.New(vdrs) poll.Vote(vdr1, blkID1) @@ -113,7 +138,7 @@ func TestEarlyTermNoTraversalForSharedAncestor(t *testing.T) { vdrs := bag.Of(vdr1, vdr2, vdr3, vdr4) // k = 4 alpha := 4 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) poll := factory.New(vdrs) poll.Vote(vdr1, blkID2) @@ -135,7 +160,7 @@ func TestEarlyTermNoTraversalWithWeightedResponses(t *testing.T) { vdrs := bag.Of(vdr1, vdr2, vdr2) // k = 3 alpha := 2 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) poll := factory.New(vdrs) poll.Vote(vdr2, blkID1) @@ -152,7 +177,7 @@ func TestEarlyTermNoTraversalDropWithWeightedResponses(t *testing.T) { vdrs := bag.Of(vdr1, vdr2, vdr2) // k = 3 alpha := 2 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) poll := factory.New(vdrs) poll.Drop(vdr2) diff --git a/snow/consensus/snowman/poll/set_test.go b/snow/consensus/snowman/poll/set_test.go index d25af3fe2de2..8200f25dc5f0 100644 --- a/snow/consensus/snowman/poll/set_test.go +++ b/snow/consensus/snowman/poll/set_test.go @@ -31,7 +31,7 @@ var ( func TestNewSetErrorOnMetrics(t *testing.T) { require := require.New(t) - factory := NewEarlyTermNoTraversalFactory(1) + factory := NewEarlyTermNoTraversalFactory(1, 1) log := logging.NoLog{} namespace := "" registerer := prometheus.NewRegistry() @@ -52,7 +52,7 @@ func TestCreateAndFinishPollOutOfOrder_NewerFinishesFirst(t *testing.T) { vdrs := []ids.NodeID{vdr1, vdr2, vdr3} // k = 3 alpha := 3 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) log := logging.NoLog{} namespace := "" registerer := prometheus.NewRegistry() @@ -88,7 +88,7 @@ func TestCreateAndFinishPollOutOfOrder_OlderFinishesFirst(t *testing.T) { vdrs := []ids.NodeID{vdr1, vdr2, vdr3} // k = 3 alpha := 3 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) log := logging.NoLog{} namespace := "" registerer := prometheus.NewRegistry() @@ -124,7 +124,7 @@ func TestCreateAndFinishPollOutOfOrder_UnfinishedPollsGaps(t *testing.T) { vdrs := []ids.NodeID{vdr1, vdr2, vdr3} // k = 3 alpha := 3 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) log := logging.NoLog{} namespace := "" registerer := prometheus.NewRegistry() @@ -168,7 +168,7 @@ func TestCreateAndFinishSuccessfulPoll(t *testing.T) { vdrs := bag.Of(vdr1, vdr2) // k = 2 alpha := 2 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) log := logging.NoLog{} namespace := "" registerer := prometheus.NewRegistry() @@ -200,7 +200,7 @@ func TestCreateAndFinishFailedPoll(t *testing.T) { vdrs := bag.Of(vdr1, vdr2) // k = 2 alpha := 1 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) log := logging.NoLog{} namespace := "" registerer := prometheus.NewRegistry() @@ -229,7 +229,7 @@ func TestSetString(t *testing.T) { vdrs := bag.Of(vdr1) // k = 1 alpha := 1 - factory := NewEarlyTermNoTraversalFactory(alpha) + factory := NewEarlyTermNoTraversalFactory(alpha, alpha) log := logging.NoLog{} namespace := "" registerer := prometheus.NewRegistry() diff --git a/snow/consensus/snowman/topological.go b/snow/consensus/snowman/topological.go index a536638bc6dd..7cf6cde8139e 100644 --- a/snow/consensus/snowman/topological.go +++ b/snow/consensus/snowman/topological.go @@ -291,7 +291,7 @@ func (ts *Topological) RecordPoll(ctx context.Context, voteBag bag.Bag[ids.ID]) ts.pollNumber++ var voteStack []votes - if voteBag.Len() >= ts.params.Alpha { + if voteBag.Len() >= ts.params.AlphaPreference { // Since we received at least alpha votes, it's possible that // we reached an alpha majority on a processing block. // We must perform the traversals to calculate all block @@ -459,7 +459,7 @@ func (ts *Topological) pushVotes() []votes { // If there are at least Alpha votes, then this block needs to record // the poll on the snowball instance - if kahnNode.votes.Len() >= ts.params.Alpha { + if kahnNode.votes.Len() >= ts.params.AlphaPreference { voteStack = append(voteStack, votes{ parentID: leafID, votes: kahnNode.votes, diff --git a/snow/engine/snowman/config_test.go b/snow/engine/snowman/config_test.go index a395efe30c79..c0b31298891a 100644 --- a/snow/engine/snowman/config_test.go +++ b/snow/engine/snowman/config_test.go @@ -20,7 +20,8 @@ func DefaultConfigs() Config { VM: &block.TestVM{}, Params: snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, diff --git a/snow/engine/snowman/transitive.go b/snow/engine/snowman/transitive.go index a884fa2975a7..d61e36128006 100644 --- a/snow/engine/snowman/transitive.go +++ b/snow/engine/snowman/transitive.go @@ -112,7 +112,10 @@ func newTransitive(config Config) (*Transitive, error) { acceptedFrontiers := tracker.NewAccepted() config.Validators.RegisterCallbackListener(acceptedFrontiers) - factory := poll.NewEarlyTermNoTraversalFactory(config.Params.Alpha) + factory := poll.NewEarlyTermNoTraversalFactory( + config.Params.AlphaPreference, + config.Params.AlphaConfidence, + ) t := &Transitive{ Config: config, StateSummaryFrontierHandler: common.NewNoOpStateSummaryFrontierHandler(config.Ctx.Log), @@ -126,7 +129,8 @@ func newTransitive(config Config) (*Transitive, error) { nonVerifieds: ancestor.NewTree(), nonVerifiedCache: nonVerifiedCache, acceptedFrontiers: acceptedFrontiers, - polls: poll.NewSet(factory, + polls: poll.NewSet( + factory, config.Ctx.Log, "", config.Ctx.Registerer, diff --git a/snow/engine/snowman/transitive_test.go b/snow/engine/snowman/transitive_test.go index 2868428a7fdc..45d007cd2b6c 100644 --- a/snow/engine/snowman/transitive_test.go +++ b/snow/engine/snowman/transitive_test.go @@ -323,7 +323,8 @@ func TestEngineMultipleQuery(t *testing.T) { engCfg := DefaultConfigs() engCfg.Params = snowball.Parameters{ K: 3, - Alpha: 2, + AlphaPreference: 2, + AlphaConfidence: 2, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -722,7 +723,8 @@ func TestVoteCanceling(t *testing.T) { engCfg := DefaultConfigs() engCfg.Params = snowball.Parameters{ K: 3, - Alpha: 2, + AlphaPreference: 2, + AlphaConfidence: 2, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -1594,7 +1596,8 @@ func TestEngineDoubleChit(t *testing.T) { engCfg := DefaultConfigs() engCfg.Params = snowball.Parameters{ K: 2, - Alpha: 2, + AlphaPreference: 2, + AlphaConfidence: 2, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1, @@ -1697,7 +1700,8 @@ func TestEngineBuildBlockLimit(t *testing.T) { engCfg := DefaultConfigs() engCfg.Params.K = 1 - engCfg.Params.Alpha = 1 + engCfg.Params.AlphaPreference = 1 + engCfg.Params.AlphaConfidence = 1 engCfg.Params.OptimalProcessing = 1 vals := validators.NewSet() @@ -2723,7 +2727,8 @@ func TestEngineApplyAcceptedFrontierInQueryFailed(t *testing.T) { engCfg := DefaultConfigs() engCfg.Params = snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 2, BetaRogue: 2, ConcurrentRepolls: 1, diff --git a/snow/networking/handler/health_test.go b/snow/networking/handler/health_test.go index b3402eb0f874..ba89790ce02a 100644 --- a/snow/networking/handler/health_test.go +++ b/snow/networking/handler/health_test.go @@ -37,7 +37,7 @@ func TestHealthCheckSubnet(t *testing.T) { "custom consensus params": { func() snowball.Parameters { params := snowball.DefaultParameters - params.K = params.Alpha + params.K = params.AlphaConfidence return params }(), }, diff --git a/subnets/config_test.go b/subnets/config_test.go index 35af67946697..2294a1e5176a 100644 --- a/subnets/config_test.go +++ b/subnets/config_test.go @@ -15,7 +15,8 @@ import ( var validParameters = snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 1, BetaRogue: 1, ConcurrentRepolls: 1, @@ -34,8 +35,8 @@ func TestValid(t *testing.T) { name: "invalid consensus parameters", s: Config{ ConsensusParameters: snowball.Parameters{ - K: 2, - Alpha: 1, + K: 2, + AlphaPreference: 1, }, }, expectedErr: snowball.ErrParametersInvalid, diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index 2f8348d28c10..d086fe699295 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -1684,7 +1684,8 @@ func TestBootstrapPartiallyAccepted(t *testing.T) { Validators: beacons, Params: snowball.Parameters{ K: 1, - Alpha: 1, + AlphaPreference: 1, + AlphaConfidence: 1, BetaVirtuous: 20, BetaRogue: 20, ConcurrentRepolls: 1,