From 484d447296a9399ddd3395ad8e6c26193b608728 Mon Sep 17 00:00:00 2001 From: Yacov Manevich Date: Tue, 17 Sep 2024 22:11:42 +0200 Subject: [PATCH] Make snowman use snowflake directly instead of snowball Snowball was introduced in order to improve the stability of snowflake, by taking into account the history when returning the preference. However, if deployed with a configuration where the preference is small enough, and a network partition causes a 50-50 split of the stake, it can actually backfire, as described in 6e1a905. Additionally, latest research [1] points out that snowflake suffices for snowman. This commit removes snowball from snowman and adds a test that simulates a mixed network which runs snowman with and without snowball, and ensures that a mixed network still converges. [1] https://arxiv.org/abs/2404.14250 Signed-off-by: Yacov Manevich --- chains/manager.go | 5 +- .../snowball/binary_snowball_test.go | 139 +++--- .../snowball/consensus_performance_test.go | 8 +- .../snowball/consensus_reversibility_test.go | 2 +- snow/consensus/snowball/flat_test.go | 6 +- .../consensus/snowball/nnary_snowball_test.go | 133 ------ snow/consensus/snowball/tree.go | 2 +- snow/consensus/snowball/tree_test.go | 445 ++++++++++-------- .../consensus/snowball/unary_snowball_test.go | 76 --- snow/consensus/snowman/consensus_test.go | 6 +- snow/consensus/snowman/mixed_test.go | 55 +++ snow/consensus/snowman/network_test.go | 4 + snow/consensus/snowman/snowman_block.go | 2 +- snow/consensus/snowman/topological.go | 10 +- snow/consensus/snowman/topological_test.go | 8 +- snow/engine/snowman/config_test.go | 2 +- snow/engine/snowman/engine_test.go | 4 +- vms/platformvm/vm_test.go | 2 +- 18 files changed, 408 insertions(+), 501 deletions(-) delete mode 100644 snow/consensus/snowball/nnary_snowball_test.go delete mode 100644 snow/consensus/snowball/unary_snowball_test.go create mode 100644 snow/consensus/snowman/mixed_test.go diff --git a/chains/manager.go b/chains/manager.go index 2fdd3c0b73f9..28f1528bc28e 100644 --- a/chains/manager.go +++ b/chains/manager.go @@ -28,6 +28,7 @@ import ( "github.com/ava-labs/avalanchego/network" "github.com/ava-labs/avalanchego/network/p2p" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/snow/consensus/snowball" "github.com/ava-labs/avalanchego/snow/engine/avalanche/bootstrap/queue" "github.com/ava-labs/avalanchego/snow/engine/avalanche/state" "github.com/ava-labs/avalanchego/snow/engine/avalanche/vertex" @@ -922,7 +923,7 @@ func (m *manager) createAvalancheChain( return nil, fmt.Errorf("couldn't initialize snow base message handler: %w", err) } - var snowmanConsensus smcon.Consensus = &smcon.Topological{} + var snowmanConsensus smcon.Consensus = &smcon.Topological{Factory: snowball.SnowflakeFactory} if m.TracingEnabled { snowmanConsensus = smcon.Trace(snowmanConsensus, m.Tracer) } @@ -1321,7 +1322,7 @@ func (m *manager) createSnowmanChain( return nil, fmt.Errorf("couldn't initialize snow base message handler: %w", err) } - var consensus smcon.Consensus = &smcon.Topological{} + var consensus smcon.Consensus = &smcon.Topological{Factory: snowball.SnowflakeFactory} if m.TracingEnabled { consensus = smcon.Trace(consensus, m.Tracer) } diff --git a/snow/consensus/snowball/binary_snowball_test.go b/snow/consensus/snowball/binary_snowball_test.go index 968743ef36a8..bd0d7fcf8cd4 100644 --- a/snow/consensus/snowball/binary_snowball_test.go +++ b/snow/consensus/snowball/binary_snowball_test.go @@ -19,25 +19,26 @@ func TestBinarySnowball(t *testing.T) { beta := 2 terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - sb := newBinarySnowball(alphaPreference, terminationConditions, red) - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + sf := newBinarySnowflake(alphaPreference, terminationConditions, red) - sb.RecordPoll(alphaConfidence, blue) - require.Equal(blue, sb.Preference()) - require.False(sb.Finalized()) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, red) - require.Equal(blue, sb.Preference()) - require.False(sb.Finalized()) + sf.RecordPoll(alphaConfidence, blue) + require.Equal(blue, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, blue) - require.Equal(blue, sb.Preference()) - require.False(sb.Finalized()) + sf.RecordPoll(alphaConfidence, red) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, blue) - require.Equal(blue, sb.Preference()) - require.True(sb.Finalized()) + sf.RecordPoll(alphaConfidence, blue) + require.Equal(blue, sf.Preference()) + require.False(sf.Finalized()) + + sf.RecordPoll(alphaConfidence, blue) + require.Equal(blue, sf.Preference()) + require.True(sf.Finalized()) } func TestBinarySnowballRecordPollPreference(t *testing.T) { @@ -50,32 +51,32 @@ func TestBinarySnowballRecordPollPreference(t *testing.T) { beta := 2 terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - sb := newBinarySnowball(alphaPreference, terminationConditions, red) - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + sf := newBinarySnowflake(alphaPreference, terminationConditions, red) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, blue) - require.Equal(blue, sb.Preference()) - require.False(sb.Finalized()) + sf.RecordPoll(alphaConfidence, blue) + require.Equal(blue, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, red) - require.Equal(blue, sb.Preference()) - require.False(sb.Finalized()) + sf.RecordPoll(alphaConfidence, red) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaPreference, red) - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + sf.RecordPoll(alphaPreference, red) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, red) - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + sf.RecordPoll(alphaConfidence, red) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, red) - require.Equal(red, sb.Preference()) - require.True(sb.Finalized()) + sf.RecordPoll(alphaConfidence, red) + require.Equal(red, sf.Preference()) + require.True(sf.Finalized()) - expected := "SB(Preference = 0, PreferenceStrength[0] = 4, PreferenceStrength[1] = 1, SF(Confidence = [2], Finalized = true, SL(Preference = 0)))" - require.Equal(expected, sb.String()) + expected := "SF(Confidence = [2], Finalized = true, SL(Preference = 0))" + require.Equal(expected, sf.String()) } func TestBinarySnowballRecordUnsuccessfulPoll(t *testing.T) { @@ -88,26 +89,26 @@ func TestBinarySnowballRecordUnsuccessfulPoll(t *testing.T) { beta := 2 terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - sb := newBinarySnowball(alphaPreference, terminationConditions, red) - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + sf := newBinarySnowflake(alphaPreference, terminationConditions, red) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, blue) - require.Equal(blue, sb.Preference()) - require.False(sb.Finalized()) + sf.RecordPoll(alphaConfidence, blue) + require.Equal(blue, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordUnsuccessfulPoll() + sf.RecordUnsuccessfulPoll() - sb.RecordPoll(alphaConfidence, blue) - require.Equal(blue, sb.Preference()) - require.False(sb.Finalized()) + sf.RecordPoll(alphaConfidence, blue) + require.Equal(blue, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, blue) - require.Equal(blue, sb.Preference()) - require.True(sb.Finalized()) + sf.RecordPoll(alphaConfidence, blue) + require.Equal(blue, sf.Preference()) + require.True(sf.Finalized()) - expected := "SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 3, SF(Confidence = [2], Finalized = true, SL(Preference = 1)))" - require.Equal(expected, sb.String()) + expected := "SF(Confidence = [2], Finalized = true, SL(Preference = 1))" + require.Equal(expected, sf.String()) } func TestBinarySnowballAcceptWeirdColor(t *testing.T) { @@ -120,36 +121,36 @@ func TestBinarySnowballAcceptWeirdColor(t *testing.T) { beta := 2 terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - sb := newBinarySnowball(alphaPreference, terminationConditions, red) + sf := newBinarySnowflake(alphaPreference, terminationConditions, red) - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, red) - sb.RecordUnsuccessfulPoll() + sf.RecordPoll(alphaConfidence, red) + sf.RecordUnsuccessfulPoll() - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, red) + sf.RecordPoll(alphaConfidence, red) - sb.RecordUnsuccessfulPoll() + sf.RecordUnsuccessfulPoll() - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + require.Equal(red, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, blue) + sf.RecordPoll(alphaConfidence, blue) - require.Equal(red, sb.Preference()) - require.False(sb.Finalized()) + require.Equal(blue, sf.Preference()) + require.False(sf.Finalized()) - sb.RecordPoll(alphaConfidence, blue) + sf.RecordPoll(alphaConfidence, blue) - require.Equal(blue, sb.Preference()) - require.True(sb.Finalized()) + require.Equal(blue, sf.Preference()) + require.True(sf.Finalized()) - expected := "SB(Preference = 1, PreferenceStrength[0] = 2, PreferenceStrength[1] = 2, SF(Confidence = [2], Finalized = true, SL(Preference = 0)))" - require.Equal(expected, sb.String()) + expected := "SF(Confidence = [2], Finalized = true, SL(Preference = 0))" + require.Equal(expected, sf.String()) } func TestBinarySnowballLockColor(t *testing.T) { diff --git a/snow/consensus/snowball/consensus_performance_test.go b/snow/consensus/snowball/consensus_performance_test.go index dbd3d95e6730..cb66637a3c63 100644 --- a/snow/consensus/snowball/consensus_performance_test.go +++ b/snow/consensus/snowball/consensus_performance_test.go @@ -28,10 +28,10 @@ func TestDualAlphaOptimization(t *testing.T) { source = prng.NewMT19937() ) - singleAlphaNetwork := NewNetwork(SnowballFactory, params, numColors, source) + singleAlphaNetwork := NewNetwork(SnowflakeFactory, params, numColors, source) params.AlphaPreference = params.K/2 + 1 - dualAlphaNetwork := NewNetwork(SnowballFactory, params, numColors, source) + dualAlphaNetwork := NewNetwork(SnowflakeFactory, params, numColors, source) source.Seed(seed) for i := 0; i < numNodes; i++ { @@ -61,8 +61,8 @@ func TestTreeConvergenceOptimization(t *testing.T) { source = prng.NewMT19937() ) - treeNetwork := NewNetwork(SnowballFactory, params, numColors, source) - flatNetwork := NewNetwork(SnowballFactory, params, numColors, source) + treeNetwork := NewNetwork(SnowflakeFactory, params, numColors, source) + flatNetwork := NewNetwork(SnowflakeFactory, params, numColors, source) source.Seed(seed) for i := 0; i < numNodes; i++ { diff --git a/snow/consensus/snowball/consensus_reversibility_test.go b/snow/consensus/snowball/consensus_reversibility_test.go index 578fea1dea18..da64a3ed4568 100644 --- a/snow/consensus/snowball/consensus_reversibility_test.go +++ b/snow/consensus/snowball/consensus_reversibility_test.go @@ -23,7 +23,7 @@ func TestSnowballGovernance(t *testing.T) { source = prng.NewMT19937() ) - nBitwise := NewNetwork(SnowballFactory, params, numColors, source) + nBitwise := NewNetwork(SnowflakeFactory, params, numColors, source) source.Seed(seed) for i := 0; i < numRed; i++ { diff --git a/snow/consensus/snowball/flat_test.go b/snow/consensus/snowball/flat_test.go index 51b7390bb88d..1e9f92b656b0 100644 --- a/snow/consensus/snowball/flat_test.go +++ b/snow/consensus/snowball/flat_test.go @@ -20,7 +20,7 @@ func TestFlat(t *testing.T) { AlphaConfidence: 3, Beta: 2, } - f := NewFlat(SnowballFactory, params, Red) + f := NewFlat(SnowflakeFactory, params, Red) f.Add(Green) f.Add(Blue) @@ -34,7 +34,7 @@ func TestFlat(t *testing.T) { twoGreen := bag.Of(Green, Green) require.True(f.RecordPoll(twoGreen)) - require.Equal(Blue, f.Preference()) + require.Equal(Green, f.Preference()) require.False(f.Finalized()) threeGreen := bag.Of(Green, Green, Green) @@ -56,6 +56,6 @@ func TestFlat(t *testing.T) { require.Equal(Green, f.Preference()) require.True(f.Finalized()) - expected := "SB(Preference = 2mcwQKiD8VEspmMJpL1dc7okQQ5dDVAWeCBZ7FWBFAbxpv3t7w, PreferenceStrength = 4, SF(Confidence = [2], Finalized = true, SL(Preference = 2mcwQKiD8VEspmMJpL1dc7okQQ5dDVAWeCBZ7FWBFAbxpv3t7w)))" + expected := "SF(Confidence = [2], Finalized = true, SL(Preference = 2mcwQKiD8VEspmMJpL1dc7okQQ5dDVAWeCBZ7FWBFAbxpv3t7w))" require.Equal(expected, f.String()) } diff --git a/snow/consensus/snowball/nnary_snowball_test.go b/snow/consensus/snowball/nnary_snowball_test.go deleted file mode 100644 index 8a5e66143db2..000000000000 --- a/snow/consensus/snowball/nnary_snowball_test.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package snowball - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestNnarySnowball(t *testing.T) { - require := require.New(t) - - alphaPreference, alphaConfidence := 1, 2 - beta := 2 - terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - - sb := newNnarySnowball(alphaPreference, terminationConditions, Red) - sb.Add(Blue) - sb.Add(Green) - - require.Equal(Red, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Blue) - require.Equal(Blue, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Red) - require.Equal(Blue, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaPreference, Red) - require.Equal(Red, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Red) - require.Equal(Red, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaPreference, Blue) - require.Equal(Red, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Blue) - require.Equal(Red, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Blue) - require.Equal(Blue, sb.Preference()) - require.True(sb.Finalized()) -} - -func TestVirtuousNnarySnowball(t *testing.T) { - require := require.New(t) - - alphaPreference, alphaConfidence := 1, 2 - beta := 1 - terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - - sb := newNnarySnowball(alphaPreference, terminationConditions, Red) - - require.Equal(Red, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Red) - require.Equal(Red, sb.Preference()) - require.True(sb.Finalized()) -} - -func TestNarySnowballRecordUnsuccessfulPoll(t *testing.T) { - require := require.New(t) - - alphaPreference, alphaConfidence := 1, 2 - beta := 2 - terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - - sb := newNnarySnowball(alphaPreference, terminationConditions, Red) - sb.Add(Blue) - - require.Equal(Red, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Blue) - require.Equal(Blue, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordUnsuccessfulPoll() - - sb.RecordPoll(alphaConfidence, Blue) - - require.Equal(Blue, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Blue) - - require.Equal(Blue, sb.Preference()) - require.True(sb.Finalized()) - - 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++ { - sb.RecordPoll(alphaConfidence, Red) - - require.Equal(Blue, sb.Preference()) - require.True(sb.Finalized()) - } -} - -func TestNarySnowballDifferentSnowflakeColor(t *testing.T) { - require := require.New(t) - - alphaPreference, alphaConfidence := 1, 2 - beta := 2 - terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - - sb := newNnarySnowball(alphaPreference, terminationConditions, Red) - sb.Add(Blue) - - require.Equal(Red, sb.Preference()) - require.False(sb.Finalized()) - - sb.RecordPoll(alphaConfidence, Blue) - - require.Equal(Blue, sb.nnarySnowflake.Preference()) - - sb.RecordPoll(alphaConfidence, Red) - - require.Equal(Blue, sb.Preference()) - require.Equal(Red, sb.nnarySnowflake.Preference()) -} diff --git a/snow/consensus/snowball/tree.go b/snow/consensus/snowball/tree.go index c6773e30c54e..a11b92e1fd03 100644 --- a/snow/consensus/snowball/tree.go +++ b/snow/consensus/snowball/tree.go @@ -360,7 +360,7 @@ func (u *unaryNode) Add(newChoice ids.ID) node { newChild := &unaryNode{ tree: u.tree, preference: newChoice, - decidedPrefix: index + 1, // The new child assumes this branch has decided in it's favor + decidedPrefix: index + 1, // The new child assumes this branch has decided in its favor commonPrefix: ids.NumBits, // The new child has no conflicts under this branch snow: newChildSnow, } diff --git a/snow/consensus/snowball/tree_test.go b/snow/consensus/snowball/tree_test.go index fc9c8944b768..8095863afb10 100644 --- a/snow/consensus/snowball/tree_test.go +++ b/snow/consensus/snowball/tree_test.go @@ -15,7 +15,7 @@ import ( "github.com/ava-labs/avalanchego/utils/bag" ) -const initialUnaryDescription = "SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [0, 256)" +const initialUnaryDescription = "SF(Confidence = [0], Finalized = false) Bits = [0, 256)" func TestSnowballSingleton(t *testing.T) { require := require.New(t) @@ -26,7 +26,7 @@ func TestSnowballSingleton(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, Red) + tree := NewTree(SnowflakeFactory, params, Red) require.False(tree.Finalized()) @@ -66,7 +66,7 @@ func TestSnowballRecordUnsuccessfulPoll(t *testing.T) { AlphaConfidence: 1, Beta: 3, } - tree := NewTree(SnowballFactory, params, Red) + tree := NewTree(SnowflakeFactory, params, Red) require.False(tree.Finalized()) @@ -95,7 +95,7 @@ func TestSnowballBinary(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, Red) + tree := NewTree(SnowflakeFactory, params, Red) tree.Add(Blue) require.Equal(Red, tree.Preference()) @@ -108,7 +108,7 @@ func TestSnowballBinary(t *testing.T) { oneRed := bag.Of(Red) require.True(tree.RecordPoll(oneRed)) - require.Equal(Blue, tree.Preference()) + require.Equal(Red, tree.Preference()) require.False(tree.Finalized()) require.True(tree.RecordPoll(oneBlue)) @@ -137,14 +137,14 @@ func TestSnowballLastBinary(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, zero) + tree := NewTree(SnowflakeFactory, params, zero) tree.Add(one) // Should do nothing tree.Add(one) - expected := `SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [0, 255) - SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 255` + expected := `SF(Confidence = [0], Finalized = false) Bits = [0, 255) + SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 255` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -154,15 +154,15 @@ func TestSnowballLastBinary(t *testing.T) { require.Equal(one, tree.Preference()) require.False(tree.Finalized()) - expected = `SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [0, 255) - SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 255` + expected = `SF(Confidence = [1], Finalized = false) Bits = [0, 255) + 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, PreferenceStrength[0] = 0, PreferenceStrength[1] = 2, SF(Confidence = [2], Finalized = true, SL(Preference = 1))) Bit = 255" + expected = "SF(Confidence = [2], Finalized = true, SL(Preference = 1)) Bit = 255" require.Equal(expected, tree.String()) } @@ -178,12 +178,12 @@ func TestSnowballFirstBinary(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, zero) + tree := NewTree(SnowflakeFactory, params, zero) tree.Add(one) - expected := `SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -193,16 +193,16 @@ func TestSnowballFirstBinary(t *testing.T) { require.Equal(one, tree.Preference()) require.False(tree.Finalized()) - expected = `SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [1, 256)` + expected = `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [1], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.True(tree.RecordPoll(oneBag)) require.Equal(one, tree.Preference()) require.True(tree.Finalized()) - expected = `SB(PreferenceStrength = 2, SF(Confidence = [2], Finalized = true)) Bits = [1, 256)` + expected = `SF(Confidence = [2], Finalized = true) Bits = [1, 256)` require.Equal(expected, tree.String()) } @@ -220,15 +220,15 @@ func TestSnowballAddDecidedFirstBit(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, zero) + tree := NewTree(SnowflakeFactory, params, zero) tree.Add(c1000) tree.Add(c1100) - expected := `SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -238,21 +238,21 @@ func TestSnowballAddDecidedFirstBit(t *testing.T) { require.Equal(c1000, tree.Preference()) require.False(tree.Finalized()) - expected = `SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected = `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) threeBag := bag.Of(c1100) require.True(tree.RecordPoll(threeBag)) - require.Equal(c1000, tree.Preference()) + require.Equal(c1100, tree.Preference()) require.False(tree.Finalized()) - expected = `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256)` + expected = `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [1], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) // Adding six should have no effect because the first bit is already decided @@ -273,14 +273,14 @@ func TestSnowballAddPreviouslyRejected(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, zero) + tree := NewTree(SnowflakeFactory, params, zero) tree.Add(two) { - expected := `SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [0, 1) - SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [0], Finalized = false) Bits = [0, 1) + SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -290,10 +290,10 @@ func TestSnowballAddPreviouslyRejected(t *testing.T) { require.True(tree.RecordPoll(zeroBag)) { - expected := `SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [0, 1) - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [1], Finalized = false) Bits = [0, 1) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -303,22 +303,22 @@ func TestSnowballAddPreviouslyRejected(t *testing.T) { require.True(tree.RecordPoll(twoBag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [1], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) - require.Equal(zero, tree.Preference()) + require.Equal(two, tree.Preference()) require.False(tree.Finalized()) } tree.Add(one) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [1], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) - require.Equal(zero, tree.Preference()) + require.Equal(two, tree.Preference()) require.False(tree.Finalized()) } } @@ -335,13 +335,13 @@ func TestSnowballNewUnary(t *testing.T) { AlphaConfidence: 1, Beta: 3, } - tree := NewTree(SnowballFactory, params, zero) + tree := NewTree(SnowflakeFactory, params, zero) tree.Add(one) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -351,9 +351,9 @@ func TestSnowballNewUnary(t *testing.T) { require.True(tree.RecordPoll(oneBag)) { - expected := `SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [1], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(one, tree.Preference()) require.False(tree.Finalized()) @@ -362,9 +362,9 @@ func TestSnowballNewUnary(t *testing.T) { require.True(tree.RecordPoll(oneBag)) { - expected := `SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 2, SF(Confidence = [2], Finalized = false, SL(Preference = 1))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(PreferenceStrength = 2, SF(Confidence = [2], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [2], Finalized = false, SL(Preference = 1)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [2], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(one, tree.Preference()) require.False(tree.Finalized()) @@ -384,18 +384,18 @@ func TestSnowballTransitiveReset(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, zero) + tree := NewTree(SnowflakeFactory, params, zero) tree.Add(two) tree.Add(eight) { - expected := `SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [0, 1) - SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 3) - SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 3 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [4, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [4, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [0], Finalized = false) Bits = [0, 1) + SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 3) + SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 3 + SF(Confidence = [0], Finalized = false) Bits = [4, 256) + SF(Confidence = [0], Finalized = false) Bits = [4, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -405,13 +405,13 @@ func TestSnowballTransitiveReset(t *testing.T) { require.True(tree.RecordPoll(zeroBag)) { - expected := `SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [0, 1) - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 3) - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 3 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [4, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [4, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [1], Finalized = false) Bits = [0, 1) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 3) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 3 + SF(Confidence = [1], Finalized = false) Bits = [4, 256) + SF(Confidence = [0], Finalized = false) Bits = [4, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -421,13 +421,13 @@ func TestSnowballTransitiveReset(t *testing.T) { require.False(tree.RecordPoll(emptyBag)) { - expected := `SB(PreferenceStrength = 1, SF(Confidence = [0], Finalized = false)) Bits = [0, 1) - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 3) - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 3 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [4, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [4, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [0], Finalized = false) Bits = [0, 1) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 3) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 3 + SF(Confidence = [1], Finalized = false) Bits = [4, 256) + SF(Confidence = [0], Finalized = false) Bits = [4, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -436,13 +436,13 @@ func TestSnowballTransitiveReset(t *testing.T) { require.True(tree.RecordPoll(zeroBag)) { - expected := `SB(PreferenceStrength = 2, SF(Confidence = [1], Finalized = false)) Bits = [0, 1) - SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 2, SF(Confidence = [1], Finalized = false)) Bits = [2, 3) - SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 3 - SB(PreferenceStrength = 2, SF(Confidence = [1], Finalized = false)) Bits = [4, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [4, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [1], Finalized = false) Bits = [0, 1) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 3) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 3 + SF(Confidence = [1], Finalized = false) Bits = [4, 256) + SF(Confidence = [0], Finalized = false) Bits = [4, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.False(tree.Finalized()) @@ -451,7 +451,7 @@ func TestSnowballTransitiveReset(t *testing.T) { require.True(tree.RecordPoll(zeroBag)) { - expected := "SB(PreferenceStrength = 3, SF(Confidence = [2], Finalized = true)) Bits = [4, 256)" + expected := "SF(Confidence = [2], Finalized = true) Bits = [4, 256)" require.Equal(expected, tree.String()) require.Equal(zero, tree.Preference()) require.True(tree.Finalized()) @@ -467,7 +467,7 @@ func TestSnowballTrinary(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, Green) + tree := NewTree(SnowflakeFactory, params, Green) tree.Add(Red) tree.Add(Blue) @@ -485,23 +485,44 @@ func TestSnowballTrinary(t *testing.T) { require.Equal(Red, tree.Preference()) require.False(tree.Finalized()) + // * + // 1/ \ + // R * + // / \ + // G B + blueBag := bag.Of(Blue) require.True(tree.RecordPoll(blueBag)) - require.Equal(Red, tree.Preference()) + require.Equal(Blue, tree.Preference()) require.False(tree.Finalized()) - // Here is a case where voting for a color makes a different color become - // the preferred color. This is intended behavior. + // * + // 1/ \1 + // R * + // / \1 + // G B + greenBag := bag.Of(Green) require.True(tree.RecordPoll(greenBag)) - require.Equal(Blue, tree.Preference()) + require.Equal(Green, tree.Preference()) require.False(tree.Finalized()) + // * + // 1/ \2 + // R * + // 1/ \1 + // G B + // Red has already been rejected here, so this is not a successful poll. require.False(tree.RecordPoll(redBag)) - require.Equal(Blue, tree.Preference()) + require.Equal(Green, tree.Preference()) require.False(tree.Finalized()) + // * + // 1/ \3 + // R * + // 2/ \1 + // G B require.True(tree.RecordPoll(greenBag)) require.Equal(Green, tree.Preference()) require.False(tree.Finalized()) @@ -520,7 +541,7 @@ func TestSnowballCloseTrinary(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, yellow) + tree := NewTree(SnowflakeFactory, params, yellow) tree.Add(cyan) tree.Add(magenta) @@ -538,19 +559,37 @@ func TestSnowballCloseTrinary(t *testing.T) { require.Equal(yellow, tree.Preference()) require.False(tree.Finalized()) + // * + // / \1 + // C * + // 1/ \ + // Y M + magentaBag := bag.Of(magenta) require.True(tree.RecordPoll(magentaBag)) - require.Equal(yellow, tree.Preference()) + require.Equal(magenta, tree.Preference()) require.False(tree.Finalized()) + // * + // / \2 + // C * + // 1/ \1 + // Y M + // Cyan has already been rejected here, so these are not successful polls. cyanBag := bag.Of(cyan) require.False(tree.RecordPoll(cyanBag)) - require.Equal(yellow, tree.Preference()) + require.Equal(magenta, tree.Preference()) require.False(tree.Finalized()) + // * + // / \2 + // C * + // 1/ \1 + // Y M + require.False(tree.RecordPoll(cyanBag)) - require.Equal(yellow, tree.Preference()) + require.Equal(magenta, tree.Preference()) require.False(tree.Finalized()) } @@ -567,7 +606,7 @@ func TestSnowballResetChild(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, c0000) + tree := NewTree(SnowflakeFactory, params, c0000) tree.Add(c0100) tree.Add(c1000) @@ -578,11 +617,11 @@ func TestSnowballResetChild(t *testing.T) { require.True(tree.RecordPoll(c0000Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -592,11 +631,11 @@ func TestSnowballResetChild(t *testing.T) { require.False(tree.RecordPoll(emptyBag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -605,11 +644,11 @@ func TestSnowballResetChild(t *testing.T) { require.True(tree.RecordPoll(c0000Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(PreferenceStrength = 2, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -629,7 +668,7 @@ func TestSnowballResetSibling(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, c0000) + tree := NewTree(SnowflakeFactory, params, c0000) tree.Add(c0100) tree.Add(c1000) @@ -640,11 +679,11 @@ func TestSnowballResetSibling(t *testing.T) { require.True(tree.RecordPoll(c0100Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0100, tree.Preference()) require.False(tree.Finalized()) @@ -654,24 +693,24 @@ func TestSnowballResetSibling(t *testing.T) { require.True(tree.RecordPoll(c1000Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 0 - SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 0 + SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [1], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) - require.Equal(c0100, tree.Preference()) + require.Equal(c1000, tree.Preference()) require.False(tree.Finalized()) } require.True(tree.RecordPoll(c0100Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 2, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 2, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 2, SF(Confidence = [1], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [1], Finalized = false) Bits = [2, 256) + SF(Confidence = [1], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0100, tree.Preference()) require.False(tree.Finalized()) @@ -694,14 +733,14 @@ func TestSnowball5Colors(t *testing.T) { colors = append(colors, ids.Empty.Prefix(uint64(i))) } - tree0 := NewTree(SnowballFactory, params, colors[4]) + tree0 := NewTree(SnowflakeFactory, params, colors[4]) tree0.Add(colors[0]) tree0.Add(colors[1]) tree0.Add(colors[2]) tree0.Add(colors[3]) - tree1 := NewTree(SnowballFactory, params, colors[3]) + tree1 := NewTree(SnowflakeFactory, params, colors[3]) tree1.Add(colors[0]) tree1.Add(colors[1]) @@ -727,7 +766,7 @@ func TestSnowballFineGrained(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, c0000) + tree := NewTree(SnowflakeFactory, params, c0000) require.Equal(initialUnaryDescription, tree.String()) require.Equal(c0000, tree.Preference()) @@ -736,9 +775,9 @@ func TestSnowballFineGrained(t *testing.T) { tree.Add(c1100) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -747,11 +786,11 @@ func TestSnowballFineGrained(t *testing.T) { tree.Add(c1000) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [0], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -760,14 +799,14 @@ func TestSnowballFineGrained(t *testing.T) { tree.Add(c0010) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 2) - SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 2 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [3, 256) - SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 2) + SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 2 + SF(Confidence = [0], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -777,14 +816,14 @@ func TestSnowballFineGrained(t *testing.T) { require.True(tree.RecordPoll(c0000Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [1, 2) - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 2 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [3, 256) - SB(Preference = 1, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [1], Finalized = false) Bits = [1, 2) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 2 + SF(Confidence = [1], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -794,17 +833,17 @@ func TestSnowballFineGrained(t *testing.T) { require.True(tree.RecordPoll(c0010Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 2 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [3, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 2 + SF(Confidence = [1], Finalized = false) Bits = [3, 256) + SF(Confidence = [1], Finalized = false) Bits = [3, 256)` require.Equal(expected, tree.String()) - require.Equal(c0000, tree.Preference()) + require.Equal(c0010, tree.Preference()) require.False(tree.Finalized()) } require.True(tree.RecordPoll(c0010Bag)) { - expected := "SB(PreferenceStrength = 2, SF(Confidence = [2], Finalized = true)) Bits = [3, 256)" + expected := "SF(Confidence = [2], Finalized = true) Bits = [3, 256)" require.Equal(expected, tree.String()) require.Equal(c0010, tree.Preference()) require.True(tree.Finalized()) @@ -820,7 +859,7 @@ func TestSnowballDoubleAdd(t *testing.T) { AlphaConfidence: 1, Beta: 3, } - tree := NewTree(SnowballFactory, params, Red) + tree := NewTree(SnowflakeFactory, params, Red) tree.Add(Red) require.Equal(initialUnaryDescription, tree.String()) @@ -844,7 +883,7 @@ func TestSnowballConsistent(t *testing.T) { source = prng.NewMT19937() ) - n := NewNetwork(SnowballFactory, params, numColors, source) + n := NewNetwork(SnowflakeFactory, params, numColors, source) source.Seed(seed) for i := 0; i < numNodes; i++ { @@ -872,7 +911,7 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { AlphaConfidence: 1, Beta: 2, } - tree := NewTree(SnowballFactory, params, c0000) + tree := NewTree(SnowflakeFactory, params, c0000) require.Equal(initialUnaryDescription, tree.String()) require.Equal(c0000, tree.Preference()) @@ -881,9 +920,9 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { tree.Add(c1000) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -892,12 +931,12 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { tree.Add(c0010) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 2) - SB(Preference = 0, PreferenceStrength[0] = 0, PreferenceStrength[1] = 0, SF(Confidence = [0], Finalized = false, SL(Preference = 0))) Bit = 2 - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [0], Finalized = false) Bits = [1, 2) + SF(Confidence = [0], Finalized = false, SL(Preference = 0)) Bit = 2 + SF(Confidence = [0], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -907,12 +946,12 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { require.True(tree.RecordPoll(c0000Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [1, 2) - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 2 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [1], Finalized = false) Bits = [1, 2) + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 2 + SF(Confidence = [1], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -921,13 +960,13 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { tree.Add(c0100) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 0 - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 1 - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 2 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [2, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [1, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 0 + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 1 + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 2 + SF(Confidence = [1], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [2, 256) + SF(Confidence = [0], Finalized = false) Bits = [1, 256)` require.Equal(expected, tree.String()) require.Equal(c0000, tree.Preference()) require.False(tree.Finalized()) @@ -937,13 +976,13 @@ func TestSnowballFilterBinaryChildren(t *testing.T) { require.True(tree.RecordPoll(c0100Bag)) { - expected := `SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 1, SF(Confidence = [1], Finalized = false, SL(Preference = 1))) Bit = 1 - SB(Preference = 0, PreferenceStrength[0] = 1, PreferenceStrength[1] = 0, SF(Confidence = [1], Finalized = false, SL(Preference = 0))) Bit = 2 - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 0, SF(Confidence = [0], Finalized = false)) Bits = [3, 256) - SB(PreferenceStrength = 1, SF(Confidence = [1], Finalized = false)) Bits = [2, 256)` + expected := `SF(Confidence = [1], Finalized = false, SL(Preference = 1)) Bit = 1 + SF(Confidence = [1], Finalized = false, SL(Preference = 0)) Bit = 2 + SF(Confidence = [1], Finalized = false) Bits = [3, 256) + SF(Confidence = [0], Finalized = false) Bits = [3, 256) + SF(Confidence = [1], Finalized = false) Bits = [2, 256)` require.Equal(expected, tree.String()) - require.Equal(c0000, tree.Preference()) + require.Equal(c0100, tree.Preference()) require.False(tree.Finalized()) } } @@ -957,7 +996,7 @@ func TestSnowballRecordPreferencePollBinary(t *testing.T) { AlphaConfidence: 3, Beta: 2, } - tree := NewTree(SnowballFactory, params, Red) + tree := NewTree(SnowflakeFactory, params, Red) tree.Add(Blue) require.Equal(Red, tree.Preference()) require.False(tree.Finalized()) @@ -969,7 +1008,7 @@ func TestSnowballRecordPreferencePollBinary(t *testing.T) { twoRed := bag.Of(Red, Red) require.True(tree.RecordPoll(twoRed)) - require.Equal(Blue, tree.Preference()) + require.Equal(Red, tree.Preference()) require.False(tree.Finalized()) threeRed := bag.Of(Red, Red, Red) @@ -980,6 +1019,10 @@ func TestSnowballRecordPreferencePollBinary(t *testing.T) { require.True(tree.RecordPoll(threeRed)) require.Equal(Red, tree.Preference()) require.True(tree.Finalized()) + + require.False(tree.RecordPoll(threeBlue)) + require.Equal(Red, tree.Preference()) + require.True(tree.Finalized()) } func TestSnowballRecordPreferencePollUnary(t *testing.T) { @@ -991,7 +1034,7 @@ func TestSnowballRecordPreferencePollUnary(t *testing.T) { AlphaConfidence: 3, Beta: 2, } - tree := NewTree(SnowballFactory, params, Red) + tree := NewTree(SnowflakeFactory, params, Red) require.Equal(Red, tree.Preference()) require.False(tree.Finalized()) @@ -1004,7 +1047,7 @@ func TestSnowballRecordPreferencePollUnary(t *testing.T) { threeBlue := bag.Of(Blue, Blue, Blue) require.True(tree.RecordPoll(threeBlue)) - require.Equal(Red, tree.Preference()) + require.Equal(Blue, tree.Preference()) require.False(tree.Finalized()) require.True(tree.RecordPoll(threeBlue)) diff --git a/snow/consensus/snowball/unary_snowball_test.go b/snow/consensus/snowball/unary_snowball_test.go deleted file mode 100644 index 007d2ab53090..000000000000 --- a/snow/consensus/snowball/unary_snowball_test.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package snowball - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func UnarySnowballStateTest(t *testing.T, sb *unarySnowball, expectedPreferenceStrength int, expectedConfidence []int, expectedFinalized bool) { - require := require.New(t) - - require.Equal(expectedPreferenceStrength, sb.preferenceStrength) - require.Equal(expectedConfidence, sb.confidence) - require.Equal(expectedFinalized, sb.Finalized()) -} - -func TestUnarySnowball(t *testing.T) { - require := require.New(t) - - alphaPreference, alphaConfidence := 1, 2 - beta := 2 - terminationConditions := newSingleTerminationCondition(alphaConfidence, beta) - - sb := newUnarySnowball(alphaPreference, terminationConditions) - - sb.RecordPoll(alphaConfidence) - UnarySnowballStateTest(t, &sb, 1, []int{1}, false) - - sb.RecordPoll(alphaPreference) - UnarySnowballStateTest(t, &sb, 2, []int{0}, false) - - sb.RecordPoll(alphaConfidence) - UnarySnowballStateTest(t, &sb, 3, []int{1}, false) - - sb.RecordUnsuccessfulPoll() - UnarySnowballStateTest(t, &sb, 3, []int{0}, false) - - sb.RecordPoll(alphaConfidence) - UnarySnowballStateTest(t, &sb, 4, []int{1}, false) - - sbCloneIntf := sb.Clone() - require.IsType(&unarySnowball{}, sbCloneIntf) - sbClone := sbCloneIntf.(*unarySnowball) - - UnarySnowballStateTest(t, sbClone, 4, []int{1}, false) - - binarySnowball := sbClone.Extend(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 < 5; i++ { - require.Zero(binarySnowball.Preference()) - require.False(binarySnowball.Finalized()) - binarySnowball.RecordPoll(alphaConfidence, 1) - binarySnowball.RecordUnsuccessfulPoll() - } - - require.Equal(1, binarySnowball.Preference()) - require.False(binarySnowball.Finalized()) - - binarySnowball.RecordPoll(alphaConfidence, 1) - require.Equal(1, binarySnowball.Preference()) - require.False(binarySnowball.Finalized()) - - binarySnowball.RecordPoll(alphaConfidence, 1) - require.Equal(1, binarySnowball.Preference()) - require.True(binarySnowball.Finalized()) - - 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 bbeda976698b..cf1460605520 100644 --- a/snow/consensus/snowman/consensus_test.go +++ b/snow/consensus/snowman/consensus_test.go @@ -691,7 +691,7 @@ func RecordPollTransitivelyResetConfidenceTest(t *testing.T, factory Factory) { votesFor3 := bag.Of(block3.ID()) require.NoError(sm.RecordPoll(context.Background(), votesFor3)) require.Equal(2, sm.NumProcessing()) - require.Equal(block2.ID(), sm.Preference()) + require.Equal(block3.ID(), sm.Preference()) require.NoError(sm.RecordPoll(context.Background(), votesFor3)) require.Zero(sm.NumProcessing()) @@ -1301,6 +1301,10 @@ func ErrorOnTransitiveRejectionTest(t *testing.T, factory Factory) { require.ErrorIs(err, errTest) } +func TestRandomized(t *testing.T) { + RandomizedConsistencyTest(t, TopologicalFactory{factory: snowball.SnowflakeFactory}) +} + func RandomizedConsistencyTest(t *testing.T, factory Factory) { require := require.New(t) diff --git a/snow/consensus/snowman/mixed_test.go b/snow/consensus/snowman/mixed_test.go new file mode 100644 index 000000000000..a5b30d19dad9 --- /dev/null +++ b/snow/consensus/snowman/mixed_test.go @@ -0,0 +1,55 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package snowman + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "gonum.org/v1/gonum/mathext/prng" + + "github.com/ava-labs/avalanchego/snow/consensus/snowball" +) + +func TestConvergenceSnowFlakeSnowBall(t *testing.T) { + require := require.New(t) + + params := snowball.Parameters{ + K: 20, + AlphaPreference: 11, + AlphaConfidence: 11, + Beta: 20, + ConcurrentRepolls: 1, + OptimalProcessing: 1, + MaxOutstandingItems: 1, + MaxItemProcessingTime: 1, + } + + for peerCount := 20; peerCount < 2000; peerCount *= 10 { + numNodes := peerCount + + t.Run(fmt.Sprintf("%d nodes", numNodes), func(t *testing.T) { + n := NewNetwork(params, 10, prng.NewMT19937()) + for i := 0; i < numNodes; i++ { + var sm Consensus + if i%2 == 0 { + factory := TopologicalFactory{factory: snowball.SnowflakeFactory} + sm = factory.New() + } else { + factory := TopologicalFactory{factory: snowball.SnowballFactory} + sm = factory.New() + } + + require.NoError(n.AddNode(t, sm)) + } + + for !n.Finalized() { + require.NoError(n.Round()) + } + + require.True(n.Agreement()) + }) + } +} diff --git a/snow/consensus/snowman/network_test.go b/snow/consensus/snowman/network_test.go index 5e89280a2989..dc6781806e6a 100644 --- a/snow/consensus/snowman/network_test.go +++ b/snow/consensus/snowman/network_test.go @@ -51,6 +51,7 @@ func NewNetwork(params snowball.Parameters, numColors int, rngSource sampler.Sou HeightV: dependency.HeightV + 1, }) } + return n } @@ -63,6 +64,7 @@ func (n *Network) shuffleColors() { colors = append(colors, n.colors[int(index)]) } n.colors = colors + utils.Sort(n.colors) } @@ -74,12 +76,14 @@ func (n *Network) AddNode(t testing.TB, sm Consensus) error { } n.shuffleColors() + for _, blk := range n.colors { copiedBlk := *blk if err := sm.Add(&copiedBlk); err != nil { return err } } + n.nodes = append(n.nodes, sm) n.running = append(n.running, sm) return nil diff --git a/snow/consensus/snowman/snowman_block.go b/snow/consensus/snowman/snowman_block.go index 236c93645a02..84b14422287e 100644 --- a/snow/consensus/snowman/snowman_block.go +++ b/snow/consensus/snowman/snowman_block.go @@ -36,7 +36,7 @@ func (n *snowmanBlock) AddChild(child Block) { // if the snowball instance is nil, this is the first child. So the instance // should be initialized. if n.sb == nil { - n.sb = snowball.NewTree(snowball.SnowballFactory, n.t.params, childID) + n.sb = snowball.NewTree(n.t.Factory, n.t.params, childID) n.children = make(map[ids.ID]Block) } else { n.sb.Add(childID) diff --git a/snow/consensus/snowman/topological.go b/snow/consensus/snowman/topological.go index 9888652f0764..c3939297fb4c 100644 --- a/snow/consensus/snowman/topological.go +++ b/snow/consensus/snowman/topological.go @@ -29,16 +29,20 @@ var ( ) // TopologicalFactory implements Factory by returning a topological struct -type TopologicalFactory struct{} +type TopologicalFactory struct { + factory snowball.Factory +} -func (TopologicalFactory) New() Consensus { - return &Topological{} +func (tf TopologicalFactory) New() Consensus { + return &Topological{Factory: tf.factory} } // Topological implements the Snowman interface by using a tree tracking the // strongly preferred branch. This tree structure amortizes network polls to // vote on more than just the next block. type Topological struct { + Factory snowball.Factory + metrics *metrics // pollNumber is the number of times RecordPolls has been called diff --git a/snow/consensus/snowman/topological_test.go b/snow/consensus/snowman/topological_test.go index 540b5a8f2eb1..f85ed36b7261 100644 --- a/snow/consensus/snowman/topological_test.go +++ b/snow/consensus/snowman/topological_test.go @@ -3,8 +3,12 @@ package snowman -import "testing" +import ( + "testing" + + "github.com/ava-labs/avalanchego/snow/consensus/snowball" +) func TestTopological(t *testing.T) { - runConsensusTests(t, TopologicalFactory{}) + runConsensusTests(t, TopologicalFactory{factory: snowball.SnowflakeFactory}) } diff --git a/snow/engine/snowman/config_test.go b/snow/engine/snowman/config_test.go index fe13d4f474c1..c1649121ee44 100644 --- a/snow/engine/snowman/config_test.go +++ b/snow/engine/snowman/config_test.go @@ -34,6 +34,6 @@ func DefaultConfig(t testing.TB) Config { MaxOutstandingItems: 1, MaxItemProcessingTime: 1, }, - Consensus: &snowman.Topological{}, + Consensus: &snowman.Topological{Factory: snowball.SnowflakeFactory}, } } diff --git a/snow/engine/snowman/engine_test.go b/snow/engine/snowman/engine_test.go index c7fa4f45bbe9..0e405754268e 100644 --- a/snow/engine/snowman/engine_test.go +++ b/snow/engine/snowman/engine_test.go @@ -3012,7 +3012,7 @@ func TestGetProcessingAncestor(t *testing.T) { ctx = snowtest.ConsensusContext( snowtest.Context(t, snowtest.PChainID), ) - consensus = &snowman.Topological{} + consensus = &snowman.Topological{Factory: snowball.SnowflakeFactory} ) require.NoError(consensus.Initialize( ctx, @@ -3086,7 +3086,7 @@ func TestShouldIssueBlock(t *testing.T) { require.NoError(t, blocks[0].Accept(context.Background())) - c := &snowman.Topological{} + c := &snowman.Topological{Factory: snowball.SnowflakeFactory} require.NoError(t, c.Initialize( ctx, snowball.DefaultParameters, diff --git a/vms/platformvm/vm_test.go b/vms/platformvm/vm_test.go index ab31ba76402e..30dd57660d39 100644 --- a/vms/platformvm/vm_test.go +++ b/vms/platformvm/vm_test.go @@ -1373,7 +1373,7 @@ func TestBootstrapPartiallyAccepted(t *testing.T) { MaxOutstandingItems: 1, MaxItemProcessingTime: 1, }, - Consensus: &smcon.Topological{}, + Consensus: &smcon.Topological{Factory: snowball.SnowflakeFactory}, } engine, err := smeng.New(engineConfig) require.NoError(err)