Skip to content

Commit

Permalink
Make snowman use snowflake directly instead of snowball (#3403)
Browse files Browse the repository at this point in the history
Signed-off-by: Yacov Manevich <[email protected]>
  • Loading branch information
yacovm authored Jan 27, 2025
1 parent 87e6e10 commit db3b57a
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 14 deletions.
5 changes: 3 additions & 2 deletions chains/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -917,7 +918,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)
}
Expand Down Expand Up @@ -1310,7 +1311,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)
}
Expand Down
2 changes: 1 addition & 1 deletion snow/consensus/snowball/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
2 changes: 1 addition & 1 deletion snow/consensus/snowman/consensus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
55 changes: 55 additions & 0 deletions snow/consensus/snowman/mixed_test.go
Original file line number Diff line number Diff line change
@@ -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 sbFactory snowball.Factory
if i%2 == 0 {
sbFactory = snowball.SnowflakeFactory
} else {
sbFactory = snowball.SnowballFactory
}

factory := TopologicalFactory{factory: sbFactory}
sm := factory.New()
require.NoError(n.AddNode(t, sm))
}

for !n.Finalized() {
require.NoError(n.Round())
}

require.True(n.Agreement())
})
}
}
2 changes: 1 addition & 1 deletion snow/consensus/snowman/snowman_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 7 additions & 3 deletions snow/consensus/snowman/topological.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions snow/consensus/snowman/topological_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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})
}
2 changes: 1 addition & 1 deletion snow/engine/snowman/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ func DefaultConfig(t testing.TB) Config {
MaxOutstandingItems: 1,
MaxItemProcessingTime: 1,
},
Consensus: &snowman.Topological{},
Consensus: &snowman.Topological{Factory: snowball.SnowflakeFactory},
}
}
4 changes: 2 additions & 2 deletions snow/engine/snowman/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3026,7 +3026,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,
Expand Down Expand Up @@ -3100,7 +3100,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,
Expand Down
2 changes: 1 addition & 1 deletion vms/platformvm/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,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)
Expand Down

0 comments on commit db3b57a

Please sign in to comment.