mirror of https://github.com/poanetwork/gecko.git
536 lines
16 KiB
Go
536 lines
16 KiB
Go
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||
|
// See the file LICENSE for licensing terms.
|
||
|
|
||
|
package snowball
|
||
|
|
||
|
import (
|
||
|
"math/rand"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/prometheus/client_golang/prometheus"
|
||
|
|
||
|
"github.com/ava-labs/gecko/ids"
|
||
|
)
|
||
|
|
||
|
func TestTreeParams(t *testing.T) { ParamsTest(t, TreeFactory{}) }
|
||
|
|
||
|
func TestSnowballSingleton(t *testing.T) {
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 1, Alpha: 1, BetaVirtuous: 3, BetaRogue: 5,
|
||
|
}
|
||
|
tree := Tree{}
|
||
|
tree.Initialize(params, Red)
|
||
|
|
||
|
if tree.Finalized() {
|
||
|
t.Fatalf("Snowball is finalized too soon")
|
||
|
}
|
||
|
|
||
|
oneRed := ids.Bag{}
|
||
|
oneRed.Add(Red)
|
||
|
tree.RecordPoll(oneRed)
|
||
|
|
||
|
if tree.Finalized() {
|
||
|
t.Fatalf("Snowball is finalized too soon")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(oneRed)
|
||
|
|
||
|
if tree.Finalized() {
|
||
|
t.Fatalf("Snowball is finalized too soon")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(oneRed)
|
||
|
|
||
|
if !tree.Finalized() {
|
||
|
t.Fatalf("Snowball should be finalized")
|
||
|
} else if !Red.Equals(tree.Preference()) {
|
||
|
t.Fatalf("After only voting red, something else was decided")
|
||
|
}
|
||
|
|
||
|
tree.Add(Blue)
|
||
|
|
||
|
oneBlue := ids.Bag{}
|
||
|
oneBlue.Add(Blue)
|
||
|
tree.RecordPoll(oneBlue)
|
||
|
|
||
|
if !tree.Finalized() {
|
||
|
t.Fatalf("Snowball should be finalized")
|
||
|
} else if !Red.Equals(tree.Preference()) {
|
||
|
t.Fatalf("After only voting red, something else was decided")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowballRecordUnsuccessfulPoll(t *testing.T) {
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 1, Alpha: 1, BetaVirtuous: 3, BetaRogue: 5,
|
||
|
}
|
||
|
tree := Tree{}
|
||
|
tree.Initialize(params, Red)
|
||
|
|
||
|
if tree.Finalized() {
|
||
|
t.Fatalf("Snowball is finalized too soon")
|
||
|
}
|
||
|
|
||
|
oneRed := ids.Bag{}
|
||
|
oneRed.Add(Red)
|
||
|
tree.RecordPoll(oneRed)
|
||
|
|
||
|
tree.RecordUnsuccessfulPoll()
|
||
|
|
||
|
tree.RecordPoll(oneRed)
|
||
|
|
||
|
if tree.Finalized() {
|
||
|
t.Fatalf("Snowball is finalized too soon")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(oneRed)
|
||
|
|
||
|
if tree.Finalized() {
|
||
|
t.Fatalf("Snowball is finalized too soon")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(oneRed)
|
||
|
|
||
|
if !tree.Finalized() {
|
||
|
t.Fatalf("Snowball should be finalized")
|
||
|
} else if !Red.Equals(tree.Preference()) {
|
||
|
t.Fatalf("After only voting red, something else was decided")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowballBinary(t *testing.T) {
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2,
|
||
|
}
|
||
|
tree := Tree{}
|
||
|
tree.Initialize(params, Red)
|
||
|
tree.Add(Blue)
|
||
|
|
||
|
if pref := tree.Preference(); !Red.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
oneBlue := ids.Bag{}
|
||
|
oneBlue.Add(Blue)
|
||
|
tree.RecordPoll(oneBlue)
|
||
|
|
||
|
if pref := tree.Preference(); !Blue.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
oneRed := ids.Bag{}
|
||
|
oneRed.Add(Red)
|
||
|
tree.RecordPoll(oneRed)
|
||
|
|
||
|
if pref := tree.Preference(); !Blue.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(oneBlue)
|
||
|
|
||
|
if pref := tree.Preference(); !Blue.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(oneBlue)
|
||
|
|
||
|
if pref := tree.Preference(); !Blue.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
||
|
} else if !tree.Finalized() {
|
||
|
t.Fatalf("Didn't finalized correctly")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowballLastBinary(t *testing.T) {
|
||
|
zero := ids.Empty
|
||
|
one := ids.NewID([32]byte{
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||
|
})
|
||
|
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 1, Alpha: 1, BetaVirtuous: 2, BetaRogue: 2,
|
||
|
}
|
||
|
tree := Tree{}
|
||
|
tree.Initialize(params, zero)
|
||
|
tree.Add(one)
|
||
|
|
||
|
expected := "SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [0, 255)\n" +
|
||
|
" SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 255"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !zero.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", zero, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
oneBag := ids.Bag{}
|
||
|
oneBag.Add(one)
|
||
|
tree.RecordPoll(oneBag)
|
||
|
|
||
|
if pref := tree.Preference(); !one.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", one, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(oneBag)
|
||
|
|
||
|
if pref := tree.Preference(); !one.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", one, pref)
|
||
|
} else if !tree.Finalized() {
|
||
|
t.Fatalf("Finalized too late")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowballTrinary(t *testing.T) {
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2,
|
||
|
}
|
||
|
tree := Tree{}
|
||
|
tree.Initialize(params, Green)
|
||
|
tree.Add(Red)
|
||
|
tree.Add(Blue)
|
||
|
|
||
|
// *
|
||
|
// / \
|
||
|
// R *
|
||
|
// / \
|
||
|
// G B
|
||
|
|
||
|
if pref := tree.Preference(); !Green.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Green, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
redBag := ids.Bag{}
|
||
|
redBag.Add(Red)
|
||
|
tree.RecordPoll(redBag)
|
||
|
|
||
|
if pref := tree.Preference(); !Red.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
blueBag := ids.Bag{}
|
||
|
blueBag.Add(Blue)
|
||
|
tree.RecordPoll(blueBag)
|
||
|
|
||
|
if pref := tree.Preference(); !Red.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
greenBag := ids.Bag{}
|
||
|
greenBag.Add(Green)
|
||
|
tree.RecordPoll(greenBag)
|
||
|
|
||
|
// Here is a case where voting for a color makes a different color become
|
||
|
// the preferred color. This is intended behavior.
|
||
|
if pref := tree.Preference(); !Blue.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(redBag)
|
||
|
|
||
|
if pref := tree.Preference(); !Blue.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Green, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(greenBag)
|
||
|
|
||
|
if pref := tree.Preference(); !Green.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Green, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowballCloseTrinary(t *testing.T) {
|
||
|
yellow := ids.NewID([32]byte{0x01})
|
||
|
cyan := ids.NewID([32]byte{0x02})
|
||
|
magenta := ids.NewID([32]byte{0x03})
|
||
|
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2,
|
||
|
}
|
||
|
tree := Tree{}
|
||
|
tree.Initialize(params, yellow)
|
||
|
tree.Add(cyan)
|
||
|
tree.Add(magenta)
|
||
|
|
||
|
if pref := tree.Preference(); !yellow.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", yellow, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
yellowBag := ids.Bag{}
|
||
|
yellowBag.Add(yellow)
|
||
|
tree.RecordPoll(yellowBag)
|
||
|
|
||
|
if pref := tree.Preference(); !yellow.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", yellow, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
magentaBag := ids.Bag{}
|
||
|
magentaBag.Add(magenta)
|
||
|
tree.RecordPoll(magentaBag)
|
||
|
|
||
|
if pref := tree.Preference(); !yellow.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", yellow, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
cyanBag := ids.Bag{}
|
||
|
cyanBag.Add(cyan)
|
||
|
tree.RecordPoll(cyanBag)
|
||
|
|
||
|
if pref := tree.Preference(); !yellow.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", yellow, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(cyanBag)
|
||
|
|
||
|
if pref := tree.Preference(); !yellow.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", yellow, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowball5Colors(t *testing.T) {
|
||
|
numColors := 5
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 5, Alpha: 5, BetaVirtuous: 20, BetaRogue: 30,
|
||
|
}
|
||
|
|
||
|
colors := []ids.ID{}
|
||
|
for i := 0; i < numColors; i++ {
|
||
|
colors = append(colors, ids.Empty.Prefix(uint64(i)))
|
||
|
}
|
||
|
|
||
|
tree0 := Tree{}
|
||
|
tree0.Initialize(params, colors[4])
|
||
|
|
||
|
tree0.Add(colors[0])
|
||
|
tree0.Add(colors[1])
|
||
|
tree0.Add(colors[2])
|
||
|
tree0.Add(colors[3])
|
||
|
|
||
|
tree1 := Tree{}
|
||
|
tree1.Initialize(params, colors[3])
|
||
|
|
||
|
tree1.Add(colors[0])
|
||
|
tree1.Add(colors[1])
|
||
|
tree1.Add(colors[2])
|
||
|
tree1.Add(colors[4])
|
||
|
|
||
|
s1 := tree0.String()
|
||
|
s2 := tree1.String()
|
||
|
if strings.Count(s1, " ") != strings.Count(s2, " ") {
|
||
|
t.Fatalf("Mis-matched initial values:\n\n%s\n\n%s",
|
||
|
s1, s2)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowballFineGrained(t *testing.T) {
|
||
|
c0000 := ids.NewID([32]byte{0x00})
|
||
|
c1000 := ids.NewID([32]byte{0x01})
|
||
|
c1100 := ids.NewID([32]byte{0x03})
|
||
|
c0010 := ids.NewID([32]byte{0x04})
|
||
|
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 1, Alpha: 1, BetaVirtuous: 1, BetaRogue: 2,
|
||
|
}
|
||
|
tree := Tree{}
|
||
|
tree.Initialize(params, c0000)
|
||
|
{
|
||
|
expected := "SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [0, 256)"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tree.Add(c1100)
|
||
|
{
|
||
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 0\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tree.Add(c1000)
|
||
|
{
|
||
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 0\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)\n" +
|
||
|
" SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 1, Confidence = 0, Finalized = false)) Bit = 1\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tree.Add(c0010)
|
||
|
{
|
||
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 0\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 2)\n" +
|
||
|
" SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 2\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n" +
|
||
|
" SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 1, Confidence = 0, Finalized = false)) Bit = 1\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
c0000Bag := ids.Bag{}
|
||
|
c0000Bag.Add(c0000)
|
||
|
tree.RecordPoll(c0000Bag)
|
||
|
{
|
||
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 1, Finalized = false)) Bit = 0\n" +
|
||
|
" SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 1, Finalized = false)) Bit = 2\n" +
|
||
|
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n" +
|
||
|
" SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 1, Confidence = 0, Finalized = false)) Bit = 1\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)\n" +
|
||
|
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
c0010Bag := ids.Bag{}
|
||
|
c0010Bag.Add(c0010)
|
||
|
tree.RecordPoll(c0010Bag)
|
||
|
{
|
||
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 1, SF = SF(Preference = 1, Confidence = 1, Finalized = false)) Bit = 2\n" +
|
||
|
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)\n" +
|
||
|
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tree.RecordPoll(c0010Bag)
|
||
|
{
|
||
|
expected := "SB(NumSuccessfulPolls = 2, Confidence = 2, Finalized = true) Bits = [3, 256)"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !c0010.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", c0010, pref)
|
||
|
} else if !tree.Finalized() {
|
||
|
t.Fatalf("Finalized too late")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowballDoubleAdd(t *testing.T) {
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 1, Alpha: 1, BetaVirtuous: 3, BetaRogue: 5,
|
||
|
}
|
||
|
tree := Tree{}
|
||
|
tree.Initialize(params, Red)
|
||
|
tree.Add(Red)
|
||
|
|
||
|
{
|
||
|
expected := "SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [0, 256)"
|
||
|
if str := tree.String(); expected != str {
|
||
|
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
||
|
} else if pref := tree.Preference(); !Red.Equals(pref) {
|
||
|
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
|
||
|
} else if tree.Finalized() {
|
||
|
t.Fatalf("Finalized too early")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSnowballConsistent(t *testing.T) {
|
||
|
numColors := 50
|
||
|
numNodes := 100
|
||
|
params := Parameters{
|
||
|
Metrics: prometheus.NewRegistry(),
|
||
|
K: 20, Alpha: 15, BetaVirtuous: 20, BetaRogue: 30,
|
||
|
}
|
||
|
seed := int64(0)
|
||
|
|
||
|
rand.Seed(seed)
|
||
|
|
||
|
n := Network{}
|
||
|
n.Initialize(params, numColors)
|
||
|
|
||
|
for i := 0; i < numNodes; i++ {
|
||
|
n.AddNode(&Tree{})
|
||
|
}
|
||
|
|
||
|
for !n.Finalized() && !n.Disagreement() {
|
||
|
n.Round()
|
||
|
}
|
||
|
|
||
|
if !n.Agreement() {
|
||
|
t.Fatalf("Network agreed on inconsistent values")
|
||
|
}
|
||
|
}
|