Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Split Alpha into AlphaPreference and AlphaConfidence #2125

Merged
merged 4 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 23 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
14 changes: 8 additions & 6 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,22 +399,22 @@ 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)
},
expectedErr: snowball.ErrParametersInvalid,
},
"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)
},
Expand Down Expand Up @@ -499,7 +499,7 @@ func TestGetSubnetConfigsFromFlags(t *testing.T) {
"2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i": {
"consensusParameters": {
"k": 111,
"alpha": 1234
"alphaPreference": 1234
}
}
}`,
Expand All @@ -513,7 +513,8 @@ func TestGetSubnetConfigsFromFlags(t *testing.T) {
"2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i": {
"consensusParameters": {
"k": 30,
"alpha": 20
"alphaPreference": 16,
"alphaConfidence": 20
},
"validatorOnly": true
}
Expand All @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 2 additions & 0 deletions config/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
33 changes: 21 additions & 12 deletions snow/consensus/snowball/binary_snowball.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
}
43 changes: 40 additions & 3 deletions snow/consensus/snowball/binary_snowball_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
marun marked this conversation as resolved.
Show resolved Hide resolved
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)))"
marun marked this conversation as resolved.
Show resolved Hide resolved
require.Equal(expected, sb.String())
}

func TestBinarySnowballRecordUnsuccessfulPoll(t *testing.T) {
require := require.New(t)

Expand All @@ -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())
}

Expand Down Expand Up @@ -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())
}

Expand All @@ -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())
}
9 changes: 9 additions & 0 deletions snow/consensus/snowball/binary_snowflake.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
abi87 marked this conversation as resolved.
Show resolved Hide resolved
sf.binarySlush.RecordSuccessfulPoll(choice)
}

func (sf *binarySnowflake) RecordUnsuccessfulPoll() {
sf.confidence = 0
}
Expand Down
7 changes: 7 additions & 0 deletions snow/consensus/snowball/binary_snowflake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
13 changes: 13 additions & 0 deletions snow/consensus/snowball/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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()

Expand Down