Skip to content

Commit

Permalink
[WIP] Activate Error Driven Snowflake
Browse files Browse the repository at this point in the history
Signed-off-by: Yacov Manevich <[email protected]>
  • Loading branch information
yacovm committed Aug 8, 2024
1 parent 6626d2b commit 3eece44
Show file tree
Hide file tree
Showing 16 changed files with 393 additions and 52 deletions.
40 changes: 32 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,19 @@ var (
errFileDoesNotExist = errors.New("file does not exist")
)

func getConsensusConfig(v *viper.Viper) snowball.Parameters {
func getConsensusConfig(v *viper.Viper) (snowball.Parameters, error) {
var terminationCriteria []snowball.TerminationCriteria

tcText := v.GetString(SnowTerminationCriteriaJSONKey)
if v.IsSet(SnowTerminationCriteriaJSONKey) && tcText != "" {
if err := json.Unmarshal([]byte(tcText), &terminationCriteria); err != nil {
return snowball.Parameters{}, fmt.Errorf("%w: failed parsing %s: %s is not a valid JSON array of the form "+
"{\"consecutiveSuccesses\":x,\"voteThreshold\":y}", snowball.ErrParametersInvalid, SnowTerminationCriteriaJSONKey, tcText)
}
}

p := snowball.Parameters{
TerminationCriteria: terminationCriteria,
K: v.GetInt(SnowSampleSizeKey),
AlphaPreference: v.GetInt(SnowPreferenceQuorumSizeKey),
AlphaConfidence: v.GetInt(SnowConfidenceQuorumSizeKey),
Expand All @@ -105,7 +116,7 @@ func getConsensusConfig(v *viper.Viper) snowball.Parameters {
p.AlphaPreference = v.GetInt(SnowQuorumSizeKey)
p.AlphaConfidence = p.AlphaPreference
}
return p
return p, nil
}

func getLoggingConfig(v *viper.Viper) (logging.Config, error) {
Expand Down Expand Up @@ -1063,7 +1074,10 @@ func getSubnetConfigsFromFlags(v *viper.Viper, subnetIDs []ids.ID) (map[ids.ID]s
res := make(map[ids.ID]subnets.Config)
for _, subnetID := range subnetIDs {
if rawSubnetConfigBytes, ok := subnetConfigs[subnetID]; ok {
config := getDefaultSubnetConfig(v)
config, err := getDefaultSubnetConfig(v)
if err != nil {
return nil, err
}
if err := json.Unmarshal(rawSubnetConfigBytes, &config); err != nil {
return nil, err
}
Expand Down Expand Up @@ -1116,7 +1130,10 @@ func getSubnetConfigsFromDir(v *viper.Viper, subnetIDs []ids.ID) (map[ids.ID]sub
return nil, err
}

config := getDefaultSubnetConfig(v)
config, err := getDefaultSubnetConfig(v)
if err != nil {
return nil, err
}
if err := json.Unmarshal(file, &config); err != nil {
return nil, fmt.Errorf("%w: %w", errUnmarshalling, err)
}
Expand All @@ -1136,13 +1153,17 @@ func getSubnetConfigsFromDir(v *viper.Viper, subnetIDs []ids.ID) (map[ids.ID]sub
return subnetConfigs, nil
}

func getDefaultSubnetConfig(v *viper.Viper) subnets.Config {
func getDefaultSubnetConfig(v *viper.Viper) (subnets.Config, error) {
cc, err := getConsensusConfig(v)
if err != nil {
return subnets.Config{}, err
}
return subnets.Config{
ConsensusParameters: getConsensusConfig(v),
ConsensusParameters: cc,
ValidatorOnly: false,
ProposerMinBlockDelay: proposervm.DefaultMinBlockDelay,
ProposerNumHistoricalBlocks: proposervm.DefaultNumHistoricalBlocks,
}
}, nil
}

func getCPUTargeterConfig(v *viper.Viper) (tracker.TargeterConfig, error) {
Expand Down Expand Up @@ -1373,7 +1394,10 @@ func GetNodeConfig(v *viper.Viper) (node.Config, error) {
return node.Config{}, fmt.Errorf("couldn't read subnet configs: %w", err)
}

primaryNetworkConfig := getDefaultSubnetConfig(v)
primaryNetworkConfig, err := getDefaultSubnetConfig(v)
if err != nil {
return node.Config{}, err
}
if err := primaryNetworkConfig.Valid(); err != nil {
return node.Config{}, fmt.Errorf("invalid consensus parameters: %w", err)
}
Expand Down
78 changes: 78 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,32 @@ func TestGetSubnetConfigsFromFile(t *testing.T) {
}
}

func TestGetSubnetConfigsFromFlagsInvalidJSON(t *testing.T) {
subnetID, err := ids.FromString("2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i")
require.NoError(t, err)

require := require.New(t)

encodedFileContent := base64.StdEncoding.EncodeToString([]byte(`{
"2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i": {
"consensusParameters": {
"terminationCriteria":{"consecutiveSuccesses":5,"voteThreshold":10},
"k": 30,
"alphaPreference": 16,
"alphaConfidence": 15
},
"validatorOnly": true
}
}`))

// build viper config
v := setupViperFlags()
v.Set(SubnetConfigContentKey, encodedFileContent)

_, err = getSubnetConfigs(v, []ids.ID{subnetID})
require.Errorf(err, "json: cannot unmarshal object into Go struct field Parameters.consensusParameters.terminationCriteria of type []snowball.TerminationCriteria")
}

func TestGetSubnetConfigsFromFlags(t *testing.T) {
subnetID, err := ids.FromString("2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i")
require.NoError(t, err)
Expand Down Expand Up @@ -519,6 +545,58 @@ func TestGetSubnetConfigsFromFlags(t *testing.T) {
},
expectedErr: nil,
},
"correct config with termination criteria": {
givenJSON: `{
"2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i": {
"consensusParameters": {
"terminationCriteria":[{"consecutiveSuccesses":5,"voteThreshold":10},{"consecutiveSuccesses":4,"voteThreshold":11}],
"k": 30,
"alphaPreference": 16,
"alphaConfidence": 0
},
"validatorOnly": true
}
}`,
testF: func(require *require.Assertions, given map[ids.ID]subnets.Config) {
id, _ := ids.FromString("2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i")
config, ok := given[id]
require.True(ok)
require.True(config.ValidatorOnly)
require.Equal([]snowball.TerminationCriteria{{ConsecutiveSuccesses: 5, VoteThreshold: 10}, {ConsecutiveSuccesses: 4, VoteThreshold: 11}},
config.ConsensusParameters.TerminationCriteria)
require.Equal(16, config.ConsensusParameters.AlphaPreference)
require.Equal(30, config.ConsensusParameters.K)
// must still respect defaults
require.Equal(256, config.ConsensusParameters.MaxOutstandingItems)
},
expectedErr: nil,
},
"conflict between alpha confidence and termination criteria": {
givenJSON: `{
"2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i": {
"consensusParameters": {
"terminationCriteria":[{"consecutiveSuccesses":5,"voteThreshold":10},{"consecutiveSuccesses":4,"voteThreshold":11}],
"k": 30,
"alphaPreference": 16,
"alphaConfidence": 15
},
"validatorOnly": true
}
}`,
testF: func(require *require.Assertions, given map[ids.ID]subnets.Config) {
id, _ := ids.FromString("2Ctt6eGAeo4MLqTmGa7AdRecuVMPGWEX9wSsCLBYrLhX4a394i")
config, ok := given[id]
require.True(ok)
require.True(config.ValidatorOnly)
require.Equal([]snowball.TerminationCriteria{{ConsecutiveSuccesses: 5, VoteThreshold: 10}, {ConsecutiveSuccesses: 4, VoteThreshold: 11}},
config.ConsensusParameters.TerminationCriteria)
require.Equal(16, config.ConsensusParameters.AlphaPreference)
require.Equal(30, config.ConsensusParameters.K)
// must still respect defaults
require.Equal(256, config.ConsensusParameters.MaxOutstandingItems)
},
expectedErr: snowball.ErrParametersInvalid,
},
}

for name, test := range tests {
Expand Down
1 change: 1 addition & 0 deletions config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ func addNodeFlags(fs *pflag.FlagSet) {
fs.Uint(BootstrapAncestorsMaxContainersReceivedKey, 2000, "This node reads at most this many containers from an incoming Ancestors message")

// Consensus
fs.String(SnowTerminationCriteriaJSONKey, "", "Termination criteria for poll")
fs.Int(SnowSampleSizeKey, snowball.DefaultParameters.K, "Number of nodes to query for each network poll")
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))
Expand Down
1 change: 1 addition & 0 deletions config/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ const (
LogRotaterMaxAgeKey = "log-rotater-max-age"
LogRotaterCompressEnabledKey = "log-rotater-compress-enabled"
LogDisableDisplayPluginLogsKey = "log-disable-display-plugin-logs"
SnowTerminationCriteriaJSONKey = "snow-termination-criteria"
SnowSampleSizeKey = "snow-sample-size"
SnowQuorumSizeKey = "snow-quorum-size"
SnowPreferenceQuorumSizeKey = "snow-preference-quorum-size"
Expand Down
10 changes: 5 additions & 5 deletions snow/consensus/snowball/binary_snowball_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestBinarySnowball(t *testing.T) {

alphaPreference, alphaConfidence := 2, 3
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newBinarySnowball(alphaPreference, terminationConditions, red)
require.Equal(red, sb.Preference())
Expand Down Expand Up @@ -48,7 +48,7 @@ func TestBinarySnowballRecordPollPreference(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newBinarySnowball(alphaPreference, terminationConditions, red)
require.Equal(red, sb.Preference())
Expand Down Expand Up @@ -86,7 +86,7 @@ func TestBinarySnowballRecordUnsuccessfulPoll(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newBinarySnowball(alphaPreference, terminationConditions, red)
require.Equal(red, sb.Preference())
Expand Down Expand Up @@ -118,7 +118,7 @@ func TestBinarySnowballAcceptWeirdColor(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newBinarySnowball(alphaPreference, terminationConditions, red)

Expand Down Expand Up @@ -160,7 +160,7 @@ func TestBinarySnowballLockColor(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 1
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newBinarySnowball(alphaPreference, terminationConditions, red)

Expand Down
2 changes: 1 addition & 1 deletion snow/consensus/snowball/binary_snowflake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestBinarySnowflake(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sf := newBinarySnowflake(alphaPreference, terminationConditions, red)

Expand Down
8 changes: 4 additions & 4 deletions snow/consensus/snowball/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ var (
type snowballFactory struct{}

func (snowballFactory) NewNnary(params Parameters, choice ids.ID) Nnary {
sb := newNnarySnowball(params.AlphaPreference, newSingleTerminationCondition(params.AlphaConfidence, params.Beta), choice)
sb := newNnarySnowball(params.AlphaPreference, params.terminationConditions(), choice)
return &sb
}

func (snowballFactory) NewUnary(params Parameters) Unary {
sb := newUnarySnowball(params.AlphaPreference, newSingleTerminationCondition(params.AlphaConfidence, params.Beta))
sb := newUnarySnowball(params.AlphaPreference, params.terminationConditions())
return &sb
}

type snowflakeFactory struct{}

func (snowflakeFactory) NewNnary(params Parameters, choice ids.ID) Nnary {
sf := newNnarySnowflake(params.AlphaPreference, newSingleTerminationCondition(params.AlphaConfidence, params.Beta), choice)
sf := newNnarySnowflake(params.AlphaPreference, params.terminationConditions(), choice)
return &sf
}

func (snowflakeFactory) NewUnary(params Parameters) Unary {
sf := newUnarySnowflake(params.AlphaPreference, newSingleTerminationCondition(params.AlphaConfidence, params.Beta))
sf := newUnarySnowflake(params.AlphaPreference, params.terminationConditions())
return &sf
}
8 changes: 4 additions & 4 deletions snow/consensus/snowball/nnary_snowball_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestNnarySnowball(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newNnarySnowball(alphaPreference, terminationConditions, Red)
sb.Add(Blue)
Expand Down Expand Up @@ -57,7 +57,7 @@ func TestVirtuousNnarySnowball(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 1
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newNnarySnowball(alphaPreference, terminationConditions, Red)

Expand All @@ -74,7 +74,7 @@ func TestNarySnowballRecordUnsuccessfulPoll(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newNnarySnowball(alphaPreference, terminationConditions, Red)
sb.Add(Blue)
Expand Down Expand Up @@ -114,7 +114,7 @@ func TestNarySnowballDifferentSnowflakeColor(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newNnarySnowball(alphaPreference, terminationConditions, Red)
sb.Add(Blue)
Expand Down
7 changes: 4 additions & 3 deletions snow/consensus/snowball/nnary_snowflake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ func TestNnarySnowflake(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)

terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sf := newNnarySnowflake(alphaPreference, terminationConditions, Red)
sf.Add(Blue)
Expand Down Expand Up @@ -55,7 +56,7 @@ func TestNnarySnowflakeConfidenceReset(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 4
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sf := newNnarySnowflake(alphaPreference, terminationConditions, Red)
sf.Add(Blue)
Expand Down Expand Up @@ -89,7 +90,7 @@ func TestVirtuousNnarySnowflake(t *testing.T) {

alphaPreference, alphaConfidence := 1, 2
beta := 2
terminationConditions := newSingleTerminationCondition(alphaConfidence, beta)
terminationConditions := newTerminationCondition([]TerminationCriteria{{VoteThreshold: alphaConfidence, ConsecutiveSuccesses: beta}})

sb := newNnarySnowflake(alphaPreference, terminationConditions, Red)
require.Equal(Red, sb.Preference())
Expand Down
Loading

0 comments on commit 3eece44

Please sign in to comment.