mirror of https://github.com/poanetwork/gecko.git
103 lines
2.2 KiB
Go
103 lines
2.2 KiB
Go
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||
|
// See the file LICENSE for licensing terms.
|
||
|
|
||
|
package snowball
|
||
|
|
||
|
import (
|
||
|
"github.com/ava-labs/gecko/ids"
|
||
|
"github.com/ava-labs/gecko/utils/random"
|
||
|
)
|
||
|
|
||
|
type Network struct {
|
||
|
params Parameters
|
||
|
colors []ids.ID
|
||
|
nodes, running []Consensus
|
||
|
}
|
||
|
|
||
|
func (n *Network) Initialize(params Parameters, numColors int) {
|
||
|
n.params = params
|
||
|
for i := 0; i < numColors; i++ {
|
||
|
n.colors = append(n.colors, ids.Empty.Prefix(uint64(i)))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (n *Network) AddNode(sb Consensus) {
|
||
|
s := random.Uniform{N: len(n.colors)}
|
||
|
sb.Initialize(n.params, n.colors[s.Sample()])
|
||
|
for s.CanSample() {
|
||
|
sb.Add(n.colors[s.Sample()])
|
||
|
}
|
||
|
|
||
|
n.nodes = append(n.nodes, sb)
|
||
|
if !sb.Finalized() {
|
||
|
n.running = append(n.running, sb)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (n *Network) AddNodeSpecificColor(sb Consensus, indices []int) {
|
||
|
sb.Initialize(n.params, n.colors[indices[0]])
|
||
|
for _, i := range indices[1:] {
|
||
|
sb.Add(n.colors[i])
|
||
|
}
|
||
|
|
||
|
n.nodes = append(n.nodes, sb)
|
||
|
if !sb.Finalized() {
|
||
|
n.running = append(n.running, sb)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (n *Network) Finalized() bool {
|
||
|
return len(n.running) == 0
|
||
|
}
|
||
|
|
||
|
func (n *Network) Round() {
|
||
|
if len(n.running) > 0 {
|
||
|
runningInd := random.Rand(0, len(n.running))
|
||
|
running := n.running[runningInd]
|
||
|
|
||
|
sampler := random.Uniform{N: len(n.nodes)}
|
||
|
sampledColors := ids.Bag{}
|
||
|
for i := 0; i < n.params.K; i++ {
|
||
|
peer := n.nodes[sampler.Sample()]
|
||
|
sampledColors.Add(peer.Preference())
|
||
|
}
|
||
|
|
||
|
running.RecordPoll(sampledColors)
|
||
|
|
||
|
// If this node has been finalized, remove it from the poller
|
||
|
if running.Finalized() {
|
||
|
newSize := len(n.running) - 1
|
||
|
n.running[runningInd] = n.running[newSize]
|
||
|
n.running = n.running[:newSize]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (n *Network) Disagreement() bool {
|
||
|
i := 0
|
||
|
for ; i < len(n.nodes) && !n.nodes[i].Finalized(); i++ {
|
||
|
}
|
||
|
if i < len(n.nodes) {
|
||
|
pref := n.nodes[i].Preference()
|
||
|
for ; i < len(n.nodes); i++ {
|
||
|
if node := n.nodes[i]; node.Finalized() && !pref.Equals(node.Preference()) {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (n *Network) Agreement() bool {
|
||
|
if len(n.nodes) == 0 {
|
||
|
return true
|
||
|
}
|
||
|
pref := n.nodes[0].Preference()
|
||
|
for _, node := range n.nodes {
|
||
|
if !pref.Equals(node.Preference()) {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|