mirror of https://github.com/poanetwork/gecko.git
commit
1fe5092e9b
|
@ -0,0 +1,27 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package snowball
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// binarySlush is the implementation of a binary slush instance
|
||||||
|
type binarySlush struct {
|
||||||
|
// preference is the choice that last had a successful poll. Unless there
|
||||||
|
// hasn't been a successful poll, in which case it is the initially provided
|
||||||
|
// choice.
|
||||||
|
preference int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize implements the BinarySlush interface
|
||||||
|
func (sl *binarySlush) Initialize(choice int) { sl.preference = choice }
|
||||||
|
|
||||||
|
// Preference implements the BinarySlush interface
|
||||||
|
func (sl *binarySlush) Preference() int { return sl.preference }
|
||||||
|
|
||||||
|
// RecordSuccessfulPoll implements the BinarySlush interface
|
||||||
|
func (sl *binarySlush) RecordSuccessfulPoll(choice int) { sl.preference = choice }
|
||||||
|
|
||||||
|
func (sl *binarySlush) String() string { return fmt.Sprintf("SL(Preference = %d)", sl.preference) }
|
|
@ -9,6 +9,9 @@ import (
|
||||||
|
|
||||||
// binarySnowball is the implementation of a binary snowball instance
|
// binarySnowball is the implementation of a binary snowball instance
|
||||||
type binarySnowball struct {
|
type binarySnowball struct {
|
||||||
|
// wrap the binary snowflake logic
|
||||||
|
binarySnowflake
|
||||||
|
|
||||||
// preference is the choice with the largest number of successful polls.
|
// preference is the choice with the largest number of successful polls.
|
||||||
// Ties are broken by switching choice lazily
|
// Ties are broken by switching choice lazily
|
||||||
preference int
|
preference int
|
||||||
|
@ -16,15 +19,12 @@ type binarySnowball struct {
|
||||||
// numSuccessfulPolls tracks the total number of successful network polls of
|
// numSuccessfulPolls tracks the total number of successful network polls of
|
||||||
// the 0 and 1 choices
|
// the 0 and 1 choices
|
||||||
numSuccessfulPolls [2]int
|
numSuccessfulPolls [2]int
|
||||||
|
|
||||||
// snowflake wraps the binary snowflake logic
|
|
||||||
snowflake binarySnowflake
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize implements the BinarySnowball interface
|
// Initialize implements the BinarySnowball interface
|
||||||
func (sb *binarySnowball) Initialize(beta, choice int) {
|
func (sb *binarySnowball) Initialize(beta, choice int) {
|
||||||
|
sb.binarySnowflake.Initialize(beta, choice)
|
||||||
sb.preference = choice
|
sb.preference = choice
|
||||||
sb.snowflake.Initialize(beta, choice)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preference implements the BinarySnowball interface
|
// Preference implements the BinarySnowball interface
|
||||||
|
@ -34,7 +34,7 @@ func (sb *binarySnowball) Preference() int {
|
||||||
// this case is handled for completion. Therefore, if snowflake is
|
// this case is handled for completion. Therefore, if snowflake is
|
||||||
// finalized, then our finalized snowflake choice should be preferred.
|
// finalized, then our finalized snowflake choice should be preferred.
|
||||||
if sb.Finalized() {
|
if sb.Finalized() {
|
||||||
return sb.snowflake.Preference()
|
return sb.binarySnowflake.Preference()
|
||||||
}
|
}
|
||||||
return sb.preference
|
return sb.preference
|
||||||
}
|
}
|
||||||
|
@ -45,20 +45,14 @@ func (sb *binarySnowball) RecordSuccessfulPoll(choice int) {
|
||||||
if sb.numSuccessfulPolls[choice] > sb.numSuccessfulPolls[1-choice] {
|
if sb.numSuccessfulPolls[choice] > sb.numSuccessfulPolls[1-choice] {
|
||||||
sb.preference = choice
|
sb.preference = choice
|
||||||
}
|
}
|
||||||
sb.snowflake.RecordSuccessfulPoll(choice)
|
sb.binarySnowflake.RecordSuccessfulPoll(choice)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordUnsuccessfulPoll implements the BinarySnowball interface
|
|
||||||
func (sb *binarySnowball) RecordUnsuccessfulPoll() { sb.snowflake.RecordUnsuccessfulPoll() }
|
|
||||||
|
|
||||||
// Finalized implements the BinarySnowball interface
|
|
||||||
func (sb *binarySnowball) Finalized() bool { return sb.snowflake.Finalized() }
|
|
||||||
|
|
||||||
func (sb *binarySnowball) String() string {
|
func (sb *binarySnowball) String() string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"SB(Preference = %d, NumSuccessfulPolls[0] = %d, NumSuccessfulPolls[1] = %d, SF = %s)",
|
"SB(Preference = %d, NumSuccessfulPolls[0] = %d, NumSuccessfulPolls[1] = %d, %s)",
|
||||||
sb.preference,
|
sb.preference,
|
||||||
sb.numSuccessfulPolls[0],
|
sb.numSuccessfulPolls[0],
|
||||||
sb.numSuccessfulPolls[1],
|
sb.numSuccessfulPolls[1],
|
||||||
&sb.snowflake)
|
&sb.binarySnowflake)
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ func TestBinarySnowballRecordUnsuccessfulPoll(t *testing.T) {
|
||||||
t.Fatalf("Finalized too late")
|
t.Fatalf("Finalized too late")
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 3, SF = SF(Preference = 1, Confidence = 2, Finalized = true))"
|
expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 3, SF(Confidence = 2, Finalized = true, SL(Preference = 1)))"
|
||||||
if str := sb.String(); str != expected {
|
if str := sb.String(); str != expected {
|
||||||
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ func TestBinarySnowballAcceptWeirdColor(t *testing.T) {
|
||||||
t.Fatalf("Finalized too late")
|
t.Fatalf("Finalized too late")
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 2, SF = SF(Preference = 1, Confidence = 2, Finalized = true))"
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 2, SF(Confidence = 2, Finalized = true, SL(Preference = 1)))"
|
||||||
if str := sb.String(); str != expected {
|
if str := sb.String(); str != expected {
|
||||||
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ func TestBinarySnowballLockColor(t *testing.T) {
|
||||||
t.Fatalf("Finalized too late")
|
t.Fatalf("Finalized too late")
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 2, SF = SF(Preference = 0, Confidence = 1, Finalized = true))"
|
expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 2, SF(Confidence = 1, Finalized = true, SL(Preference = 0)))"
|
||||||
if str := sb.String(); str != expected {
|
if str := sb.String(); str != expected {
|
||||||
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,8 @@ import (
|
||||||
|
|
||||||
// binarySnowflake is the implementation of a binary snowflake instance
|
// binarySnowflake is the implementation of a binary snowflake instance
|
||||||
type binarySnowflake struct {
|
type binarySnowflake struct {
|
||||||
// preference is the choice that last had a successful poll. Unless there
|
// wrap the binary slush logic
|
||||||
// hasn't been a successful poll, in which case it is the initially provided
|
binarySlush
|
||||||
// choice.
|
|
||||||
preference int
|
|
||||||
|
|
||||||
// confidence tracks the number of successful polls in a row that have
|
// confidence tracks the number of successful polls in a row that have
|
||||||
// returned the preference
|
// returned the preference
|
||||||
|
@ -29,29 +27,26 @@ type binarySnowflake struct {
|
||||||
|
|
||||||
// Initialize implements the BinarySnowflake interface
|
// Initialize implements the BinarySnowflake interface
|
||||||
func (sf *binarySnowflake) Initialize(beta, choice int) {
|
func (sf *binarySnowflake) Initialize(beta, choice int) {
|
||||||
|
sf.binarySlush.Initialize(choice)
|
||||||
sf.beta = beta
|
sf.beta = beta
|
||||||
sf.preference = choice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preference implements the BinarySnowflake interface
|
|
||||||
func (sf *binarySnowflake) Preference() int { return sf.preference }
|
|
||||||
|
|
||||||
// RecordSuccessfulPoll implements the BinarySnowflake interface
|
// RecordSuccessfulPoll implements the BinarySnowflake interface
|
||||||
func (sf *binarySnowflake) RecordSuccessfulPoll(choice int) {
|
func (sf *binarySnowflake) RecordSuccessfulPoll(choice int) {
|
||||||
if sf.Finalized() {
|
if sf.finalized {
|
||||||
return // This instace is already decided.
|
return // This instace is already decided.
|
||||||
}
|
}
|
||||||
|
|
||||||
if sf.preference == choice {
|
if preference := sf.Preference(); preference == choice {
|
||||||
sf.confidence++
|
sf.confidence++
|
||||||
} else {
|
} else {
|
||||||
// confidence is set to 1 because there has already been 1 successful
|
// confidence is set to 1 because there has already been 1 successful
|
||||||
// poll, namely this poll.
|
// poll, namely this poll.
|
||||||
sf.confidence = 1
|
sf.confidence = 1
|
||||||
sf.preference = choice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sf.finalized = sf.confidence >= sf.beta
|
sf.finalized = sf.confidence >= sf.beta
|
||||||
|
sf.binarySlush.RecordSuccessfulPoll(choice)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordUnsuccessfulPoll implements the BinarySnowflake interface
|
// RecordUnsuccessfulPoll implements the BinarySnowflake interface
|
||||||
|
@ -61,8 +56,8 @@ func (sf *binarySnowflake) RecordUnsuccessfulPoll() { sf.confidence = 0 }
|
||||||
func (sf *binarySnowflake) Finalized() bool { return sf.finalized }
|
func (sf *binarySnowflake) Finalized() bool { return sf.finalized }
|
||||||
|
|
||||||
func (sf *binarySnowflake) String() string {
|
func (sf *binarySnowflake) String() string {
|
||||||
return fmt.Sprintf("SF(Preference = %d, Confidence = %d, Finalized = %v)",
|
return fmt.Sprintf("SF(Confidence = %d, Finalized = %v, %s)",
|
||||||
sf.Preference(),
|
|
||||||
sf.confidence,
|
sf.confidence,
|
||||||
sf.Finalized())
|
sf.finalized,
|
||||||
|
&sf.binarySlush)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ type Byzantine struct {
|
||||||
|
|
||||||
// Initialize implements the Consensus interface
|
// Initialize implements the Consensus interface
|
||||||
func (b *Byzantine) Initialize(params Parameters, choice ids.ID) {
|
func (b *Byzantine) Initialize(params Parameters, choice ids.ID) {
|
||||||
|
b.params = params
|
||||||
b.preference = choice
|
b.preference = choice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package snowball
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestByzantine(t *testing.T) {
|
||||||
|
params := Parameters{
|
||||||
|
Metrics: prometheus.NewRegistry(),
|
||||||
|
K: 1, Alpha: 1, BetaVirtuous: 3, BetaRogue: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
byzFactory := ByzantineFactory{}
|
||||||
|
byz := byzFactory.New()
|
||||||
|
byz.Initialize(params, Blue)
|
||||||
|
|
||||||
|
if ret := byz.Parameters(); ret != params {
|
||||||
|
t.Fatalf("Should have returned the correct params")
|
||||||
|
}
|
||||||
|
|
||||||
|
byz.Add(Green)
|
||||||
|
|
||||||
|
if pref := byz.Preference(); !pref.Equals(Blue) {
|
||||||
|
t.Fatalf("Wrong preference, expected %s returned %s", Blue, pref)
|
||||||
|
}
|
||||||
|
|
||||||
|
oneGreen := ids.Bag{}
|
||||||
|
oneGreen.Add(Green)
|
||||||
|
byz.RecordPoll(oneGreen)
|
||||||
|
|
||||||
|
if pref := byz.Preference(); !pref.Equals(Blue) {
|
||||||
|
t.Fatalf("Wrong preference, expected %s returned %s", Blue, pref)
|
||||||
|
}
|
||||||
|
|
||||||
|
byz.RecordUnsuccessfulPoll()
|
||||||
|
|
||||||
|
if pref := byz.Preference(); !pref.Equals(Blue) {
|
||||||
|
t.Fatalf("Wrong preference, expected %s returned %s", Blue, pref)
|
||||||
|
}
|
||||||
|
|
||||||
|
if final := byz.Finalized(); !final {
|
||||||
|
t.Fatalf("Should be marked as accepted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if str := byz.String(); str != Blue.String() {
|
||||||
|
t.Fatalf("Wrong string, expected %s returned %s", Blue, str)
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,6 +69,23 @@ type NnarySnowflake interface {
|
||||||
Finalized() bool
|
Finalized() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NnarySlush is a slush instance deciding between an unbounded number of
|
||||||
|
// values. After performing a network sample of k nodes, if you have alpha
|
||||||
|
// votes for one of the choices, you should vote for that choice.
|
||||||
|
type NnarySlush interface {
|
||||||
|
fmt.Stringer
|
||||||
|
|
||||||
|
// Takes in the initial choice
|
||||||
|
Initialize(initialPreference ids.ID)
|
||||||
|
|
||||||
|
// Returns the currently preferred choice to be finalized
|
||||||
|
Preference() ids.ID
|
||||||
|
|
||||||
|
// RecordSuccessfulPoll records a successful poll towards finalizing the
|
||||||
|
// specified choice. Assumes the choice was previously added.
|
||||||
|
RecordSuccessfulPoll(choice ids.ID)
|
||||||
|
}
|
||||||
|
|
||||||
// BinarySnowball augments BinarySnowflake with a counter that tracks the total
|
// BinarySnowball augments BinarySnowflake with a counter that tracks the total
|
||||||
// number of positive responses from a network sample.
|
// number of positive responses from a network sample.
|
||||||
type BinarySnowball interface{ BinarySnowflake }
|
type BinarySnowball interface{ BinarySnowflake }
|
||||||
|
@ -97,6 +114,23 @@ type BinarySnowflake interface {
|
||||||
Finalized() bool
|
Finalized() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BinarySlush is a slush instance deciding between two values. After performing
|
||||||
|
// a network sample of k nodes, if you have alpha votes for one of the choices,
|
||||||
|
// you should vote for that choice.
|
||||||
|
type BinarySlush interface {
|
||||||
|
fmt.Stringer
|
||||||
|
|
||||||
|
// Takes in the initial choice
|
||||||
|
Initialize(initialPreference int)
|
||||||
|
|
||||||
|
// Returns the currently preferred choice to be finalized
|
||||||
|
Preference() int
|
||||||
|
|
||||||
|
// RecordSuccessfulPoll records a successful poll towards finalizing the
|
||||||
|
// specified choice
|
||||||
|
RecordSuccessfulPoll(choice int)
|
||||||
|
}
|
||||||
|
|
||||||
// UnarySnowball is a snowball instance deciding on one value. After performing
|
// UnarySnowball is a snowball instance deciding on one value. After performing
|
||||||
// a network sample of k nodes, if you have alpha votes for the choice, you
|
// a network sample of k nodes, if you have alpha votes for the choice, you
|
||||||
// should vote. Otherwise, you should reset.
|
// should vote. Otherwise, you should reset.
|
||||||
|
@ -122,3 +156,29 @@ type UnarySnowball interface {
|
||||||
// Returns a new unary snowball instance with the same state
|
// Returns a new unary snowball instance with the same state
|
||||||
Clone() UnarySnowball
|
Clone() UnarySnowball
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnarySnowflake is a snowflake instance deciding on one value. After
|
||||||
|
// performing a network sample of k nodes, if you have alpha votes for the
|
||||||
|
// choice, you should vote. Otherwise, you should reset.
|
||||||
|
type UnarySnowflake interface {
|
||||||
|
fmt.Stringer
|
||||||
|
|
||||||
|
// Takes in the beta value
|
||||||
|
Initialize(beta int)
|
||||||
|
|
||||||
|
// RecordSuccessfulPoll records a successful poll towards finalizing
|
||||||
|
RecordSuccessfulPoll()
|
||||||
|
|
||||||
|
// RecordUnsuccessfulPoll resets the snowflake counter of this instance
|
||||||
|
RecordUnsuccessfulPoll()
|
||||||
|
|
||||||
|
// Return whether a choice has been finalized
|
||||||
|
Finalized() bool
|
||||||
|
|
||||||
|
// Returns a new binary snowball instance with the agreement parameters
|
||||||
|
// transferred. Takes in the new beta value and the original choice
|
||||||
|
Extend(beta, originalPreference int) BinarySnowflake
|
||||||
|
|
||||||
|
// Returns a new unary snowflake instance with the same state
|
||||||
|
Clone() UnarySnowflake
|
||||||
|
}
|
||||||
|
|
|
@ -15,40 +15,27 @@ func (FlatFactory) New() Consensus { return &Flat{} }
|
||||||
|
|
||||||
// Flat is a naive implementation of a multi-choice snowball instance
|
// Flat is a naive implementation of a multi-choice snowball instance
|
||||||
type Flat struct {
|
type Flat struct {
|
||||||
|
// wraps the n-nary snowball logic
|
||||||
|
nnarySnowball
|
||||||
|
|
||||||
// params contains all the configurations of a snowball instance
|
// params contains all the configurations of a snowball instance
|
||||||
params Parameters
|
params Parameters
|
||||||
|
|
||||||
// snowball wraps the n-nary snowball logic
|
|
||||||
snowball nnarySnowball
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize implements the Consensus interface
|
// Initialize implements the Consensus interface
|
||||||
func (f *Flat) Initialize(params Parameters, choice ids.ID) {
|
func (f *Flat) Initialize(params Parameters, choice ids.ID) {
|
||||||
|
f.nnarySnowball.Initialize(params.BetaVirtuous, params.BetaRogue, choice)
|
||||||
f.params = params
|
f.params = params
|
||||||
f.snowball.Initialize(params.BetaVirtuous, params.BetaRogue, choice)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parameters implements the Consensus interface
|
// Parameters implements the Consensus interface
|
||||||
func (f *Flat) Parameters() Parameters { return f.params }
|
func (f *Flat) Parameters() Parameters { return f.params }
|
||||||
|
|
||||||
// Add implements the Consensus interface
|
|
||||||
func (f *Flat) Add(choice ids.ID) { f.snowball.Add(choice) }
|
|
||||||
|
|
||||||
// Preference implements the Consensus interface
|
|
||||||
func (f *Flat) Preference() ids.ID { return f.snowball.Preference() }
|
|
||||||
|
|
||||||
// RecordPoll implements the Consensus interface
|
// RecordPoll implements the Consensus interface
|
||||||
func (f *Flat) RecordPoll(votes ids.Bag) {
|
func (f *Flat) RecordPoll(votes ids.Bag) {
|
||||||
if pollMode, numVotes := votes.Mode(); numVotes >= f.params.Alpha {
|
if pollMode, numVotes := votes.Mode(); numVotes >= f.params.Alpha {
|
||||||
f.snowball.RecordSuccessfulPoll(pollMode)
|
f.nnarySnowball.RecordSuccessfulPoll(pollMode)
|
||||||
} else {
|
} else {
|
||||||
f.RecordUnsuccessfulPoll()
|
f.RecordUnsuccessfulPoll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordUnsuccessfulPoll implements the Consensus interface
|
|
||||||
func (f *Flat) RecordUnsuccessfulPoll() { f.snowball.RecordUnsuccessfulPoll() }
|
|
||||||
|
|
||||||
// Finalized implements the Consensus interface
|
|
||||||
func (f *Flat) Finalized() bool { return f.snowball.Finalized() }
|
|
||||||
func (f *Flat) String() string { return f.snowball.String() }
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ func TestFlat(t *testing.T) {
|
||||||
t.Fatalf("Finalized too late")
|
t.Fatalf("Finalized too late")
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF = SF(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, Confidence = 2, Finalized = true))"
|
expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF(Confidence = 2, Finalized = true, SL(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES)))"
|
||||||
if str := f.String(); str != expected {
|
if str := f.String(); str != expected {
|
||||||
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package snowball
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nnarySlush is the implementation of a slush instance with an unbounded number
|
||||||
|
// of choices
|
||||||
|
type nnarySlush struct {
|
||||||
|
// preference is the choice that last had a successful poll. Unless there
|
||||||
|
// hasn't been a successful poll, in which case it is the initially provided
|
||||||
|
// choice.
|
||||||
|
preference ids.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize implements the NnarySlush interface
|
||||||
|
func (sl *nnarySlush) Initialize(choice ids.ID) { sl.preference = choice }
|
||||||
|
|
||||||
|
// Preference implements the NnarySlush interface
|
||||||
|
func (sl *nnarySlush) Preference() ids.ID { return sl.preference }
|
||||||
|
|
||||||
|
// RecordSuccessfulPoll implements the NnarySlush interface
|
||||||
|
func (sl *nnarySlush) RecordSuccessfulPoll(choice ids.ID) { sl.preference = choice }
|
||||||
|
|
||||||
|
func (sl *nnarySlush) String() string { return fmt.Sprintf("SL(Preference = %s)", sl.preference) }
|
|
@ -11,6 +11,9 @@ import (
|
||||||
|
|
||||||
// nnarySnowball is a naive implementation of a multi-color snowball instance
|
// nnarySnowball is a naive implementation of a multi-color snowball instance
|
||||||
type nnarySnowball struct {
|
type nnarySnowball struct {
|
||||||
|
// wrap the n-nary snowflake logic
|
||||||
|
nnarySnowflake
|
||||||
|
|
||||||
// preference is the choice with the largest number of successful polls.
|
// preference is the choice with the largest number of successful polls.
|
||||||
// Ties are broken by switching choice lazily
|
// Ties are broken by switching choice lazily
|
||||||
preference ids.ID
|
preference ids.ID
|
||||||
|
@ -22,21 +25,15 @@ type nnarySnowball struct {
|
||||||
// numSuccessfulPolls tracks the total number of successful network polls of
|
// numSuccessfulPolls tracks the total number of successful network polls of
|
||||||
// the choices
|
// the choices
|
||||||
numSuccessfulPolls map[[32]byte]int
|
numSuccessfulPolls map[[32]byte]int
|
||||||
|
|
||||||
// snowflake wraps the n-nary snowflake logic
|
|
||||||
snowflake nnarySnowflake
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize implements the NnarySnowball interface
|
// Initialize implements the NnarySnowball interface
|
||||||
func (sb *nnarySnowball) Initialize(betaVirtuous, betaRogue int, choice ids.ID) {
|
func (sb *nnarySnowball) Initialize(betaVirtuous, betaRogue int, choice ids.ID) {
|
||||||
|
sb.nnarySnowflake.Initialize(betaVirtuous, betaRogue, choice)
|
||||||
sb.preference = choice
|
sb.preference = choice
|
||||||
sb.numSuccessfulPolls = make(map[[32]byte]int)
|
sb.numSuccessfulPolls = make(map[[32]byte]int)
|
||||||
sb.snowflake.Initialize(betaVirtuous, betaRogue, choice)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add implements the NnarySnowball interface
|
|
||||||
func (sb *nnarySnowball) Add(choice ids.ID) { sb.snowflake.Add(choice) }
|
|
||||||
|
|
||||||
// Preference implements the NnarySnowball interface
|
// Preference implements the NnarySnowball interface
|
||||||
func (sb *nnarySnowball) Preference() ids.ID {
|
func (sb *nnarySnowball) Preference() ids.ID {
|
||||||
// It is possible, with low probability, that the snowflake preference is
|
// It is possible, with low probability, that the snowflake preference is
|
||||||
|
@ -44,17 +41,13 @@ func (sb *nnarySnowball) Preference() ids.ID {
|
||||||
// this case is handled for completion. Therefore, if snowflake is
|
// this case is handled for completion. Therefore, if snowflake is
|
||||||
// finalized, then our finalized snowflake choice should be preferred.
|
// finalized, then our finalized snowflake choice should be preferred.
|
||||||
if sb.Finalized() {
|
if sb.Finalized() {
|
||||||
return sb.snowflake.Preference()
|
return sb.nnarySnowflake.Preference()
|
||||||
}
|
}
|
||||||
return sb.preference
|
return sb.preference
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordSuccessfulPoll implements the NnarySnowball interface
|
// RecordSuccessfulPoll implements the NnarySnowball interface
|
||||||
func (sb *nnarySnowball) RecordSuccessfulPoll(choice ids.ID) {
|
func (sb *nnarySnowball) RecordSuccessfulPoll(choice ids.ID) {
|
||||||
if sb.Finalized() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
key := choice.Key()
|
key := choice.Key()
|
||||||
numSuccessfulPolls := sb.numSuccessfulPolls[key] + 1
|
numSuccessfulPolls := sb.numSuccessfulPolls[key] + 1
|
||||||
sb.numSuccessfulPolls[key] = numSuccessfulPolls
|
sb.numSuccessfulPolls[key] = numSuccessfulPolls
|
||||||
|
@ -64,16 +57,10 @@ func (sb *nnarySnowball) RecordSuccessfulPoll(choice ids.ID) {
|
||||||
sb.maxSuccessfulPolls = numSuccessfulPolls
|
sb.maxSuccessfulPolls = numSuccessfulPolls
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.snowflake.RecordSuccessfulPoll(choice)
|
sb.nnarySnowflake.RecordSuccessfulPoll(choice)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordUnsuccessfulPoll implements the NnarySnowball interface
|
|
||||||
func (sb *nnarySnowball) RecordUnsuccessfulPoll() { sb.snowflake.RecordUnsuccessfulPoll() }
|
|
||||||
|
|
||||||
// Finalized implements the NnarySnowball interface
|
|
||||||
func (sb *nnarySnowball) Finalized() bool { return sb.snowflake.Finalized() }
|
|
||||||
|
|
||||||
func (sb *nnarySnowball) String() string {
|
func (sb *nnarySnowball) String() string {
|
||||||
return fmt.Sprintf("SB(Preference = %s, NumSuccessfulPolls = %d, SF = %s)",
|
return fmt.Sprintf("SB(Preference = %s, NumSuccessfulPolls = %d, %s)",
|
||||||
sb.preference, sb.maxSuccessfulPolls, &sb.snowflake)
|
sb.preference, sb.maxSuccessfulPolls, &sb.nnarySnowflake)
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ func TestNarySnowballRecordUnsuccessfulPoll(t *testing.T) {
|
||||||
t.Fatalf("Finalized too late")
|
t.Fatalf("Finalized too late")
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF = SF(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, Confidence = 2, Finalized = true))"
|
expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF(Confidence = 2, Finalized = true, SL(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES)))"
|
||||||
if str := sb.String(); str != expected {
|
if str := sb.String(); str != expected {
|
||||||
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ func TestNarySnowflakeColor(t *testing.T) {
|
||||||
|
|
||||||
sb.RecordSuccessfulPoll(Blue)
|
sb.RecordSuccessfulPoll(Blue)
|
||||||
|
|
||||||
if pref := sb.snowflake.Preference(); !Blue.Equals(pref) {
|
if pref := sb.nnarySnowflake.Preference(); !Blue.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ func TestNarySnowflakeColor(t *testing.T) {
|
||||||
|
|
||||||
if pref := sb.Preference(); !Blue.Equals(pref) {
|
if pref := sb.Preference(); !Blue.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
||||||
} else if pref := sb.snowflake.Preference(); !Red.Equals(pref) {
|
} else if pref := sb.nnarySnowflake.Preference(); !Red.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@ import (
|
||||||
// nnarySnowflake is the implementation of a snowflake instance with an
|
// nnarySnowflake is the implementation of a snowflake instance with an
|
||||||
// unbounded number of choices
|
// unbounded number of choices
|
||||||
type nnarySnowflake struct {
|
type nnarySnowflake struct {
|
||||||
|
// wrap the n-nary slush logic
|
||||||
|
nnarySlush
|
||||||
|
|
||||||
// betaVirtuous is the number of consecutive successful queries required for
|
// betaVirtuous is the number of consecutive successful queries required for
|
||||||
// finalization on a virtuous instance.
|
// finalization on a virtuous instance.
|
||||||
betaVirtuous int
|
betaVirtuous int
|
||||||
|
@ -24,11 +27,6 @@ type nnarySnowflake struct {
|
||||||
// returned the preference
|
// returned the preference
|
||||||
confidence int
|
confidence int
|
||||||
|
|
||||||
// preference is the choice that last had a successful poll. Unless there
|
|
||||||
// hasn't been a successful poll, in which case it is the initially provided
|
|
||||||
// choice.
|
|
||||||
preference ids.ID
|
|
||||||
|
|
||||||
// rogue tracks if this instance has multiple choices or only one
|
// rogue tracks if this instance has multiple choices or only one
|
||||||
rogue bool
|
rogue bool
|
||||||
|
|
||||||
|
@ -39,32 +37,31 @@ type nnarySnowflake struct {
|
||||||
|
|
||||||
// Initialize implements the NnarySnowflake interface
|
// Initialize implements the NnarySnowflake interface
|
||||||
func (sf *nnarySnowflake) Initialize(betaVirtuous, betaRogue int, choice ids.ID) {
|
func (sf *nnarySnowflake) Initialize(betaVirtuous, betaRogue int, choice ids.ID) {
|
||||||
|
sf.nnarySlush.Initialize(choice)
|
||||||
sf.betaVirtuous = betaVirtuous
|
sf.betaVirtuous = betaVirtuous
|
||||||
sf.betaRogue = betaRogue
|
sf.betaRogue = betaRogue
|
||||||
sf.preference = choice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add implements the NnarySnowflake interface
|
// Add implements the NnarySnowflake interface
|
||||||
func (sf *nnarySnowflake) Add(choice ids.ID) { sf.rogue = sf.rogue || !choice.Equals(sf.preference) }
|
func (sf *nnarySnowflake) Add(choice ids.ID) { sf.rogue = sf.rogue || !choice.Equals(sf.preference) }
|
||||||
|
|
||||||
// Preference implements the NnarySnowflake interface
|
|
||||||
func (sf *nnarySnowflake) Preference() ids.ID { return sf.preference }
|
|
||||||
|
|
||||||
// RecordSuccessfulPoll implements the NnarySnowflake interface
|
// RecordSuccessfulPoll implements the NnarySnowflake interface
|
||||||
func (sf *nnarySnowflake) RecordSuccessfulPoll(choice ids.ID) {
|
func (sf *nnarySnowflake) RecordSuccessfulPoll(choice ids.ID) {
|
||||||
if sf.Finalized() {
|
if sf.finalized {
|
||||||
return
|
return // This instace is already decided.
|
||||||
}
|
}
|
||||||
|
|
||||||
if sf.preference.Equals(choice) {
|
if preference := sf.nnarySlush.Preference(); preference.Equals(choice) {
|
||||||
sf.confidence++
|
sf.confidence++
|
||||||
} else {
|
} else {
|
||||||
|
// confidence is set to 1 because there has already been 1 successful
|
||||||
|
// poll, namely this poll.
|
||||||
sf.confidence = 1
|
sf.confidence = 1
|
||||||
sf.preference = choice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sf.finalized = (!sf.rogue && sf.confidence >= sf.betaVirtuous) ||
|
sf.finalized = (!sf.rogue && sf.confidence >= sf.betaVirtuous) ||
|
||||||
sf.confidence >= sf.betaRogue
|
sf.confidence >= sf.betaRogue
|
||||||
|
sf.nnarySlush.RecordSuccessfulPoll(choice)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordUnsuccessfulPoll implements the NnarySnowflake interface
|
// RecordUnsuccessfulPoll implements the NnarySnowflake interface
|
||||||
|
@ -74,8 +71,8 @@ func (sf *nnarySnowflake) RecordUnsuccessfulPoll() { sf.confidence = 0 }
|
||||||
func (sf *nnarySnowflake) Finalized() bool { return sf.finalized }
|
func (sf *nnarySnowflake) Finalized() bool { return sf.finalized }
|
||||||
|
|
||||||
func (sf *nnarySnowflake) String() string {
|
func (sf *nnarySnowflake) String() string {
|
||||||
return fmt.Sprintf("SF(Preference = %s, Confidence = %d, Finalized = %v)",
|
return fmt.Sprintf("SF(Confidence = %d, Finalized = %v, %s)",
|
||||||
sf.preference,
|
|
||||||
sf.confidence,
|
sf.confidence,
|
||||||
sf.Finalized())
|
sf.finalized,
|
||||||
|
&sf.nnarySlush)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ func (TreeFactory) New() Consensus { return &Tree{} }
|
||||||
|
|
||||||
// Tree implements the snowball interface by using a modified patricia tree.
|
// Tree implements the snowball interface by using a modified patricia tree.
|
||||||
type Tree struct {
|
type Tree struct {
|
||||||
|
// node is the root that represents the first snowball instance in the tree,
|
||||||
|
// and contains references to all the other snowball instances in the tree.
|
||||||
|
node
|
||||||
|
|
||||||
// params contains all the configurations of a snowball instance
|
// params contains all the configurations of a snowball instance
|
||||||
params Parameters
|
params Parameters
|
||||||
|
|
||||||
|
@ -31,10 +35,6 @@ type Tree struct {
|
||||||
// that any later traversal into this sub-tree should call
|
// that any later traversal into this sub-tree should call
|
||||||
// RecordUnsuccessfulPoll before performing any other action.
|
// RecordUnsuccessfulPoll before performing any other action.
|
||||||
shouldReset bool
|
shouldReset bool
|
||||||
|
|
||||||
// root is the node that represents the first snowball instance in the tree,
|
|
||||||
// and contains references to all the other snowball instances in the tree.
|
|
||||||
root node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize implements the Consensus interface
|
// Initialize implements the Consensus interface
|
||||||
|
@ -44,7 +44,7 @@ func (t *Tree) Initialize(params Parameters, choice ids.ID) {
|
||||||
snowball := &unarySnowball{}
|
snowball := &unarySnowball{}
|
||||||
snowball.Initialize(params.BetaVirtuous)
|
snowball.Initialize(params.BetaVirtuous)
|
||||||
|
|
||||||
t.root = &unaryNode{
|
t.node = &unaryNode{
|
||||||
tree: t,
|
tree: t,
|
||||||
preference: choice,
|
preference: choice,
|
||||||
commonPrefix: ids.NumBits, // The initial state has no conflicts
|
commonPrefix: ids.NumBits, // The initial state has no conflicts
|
||||||
|
@ -57,20 +57,17 @@ func (t *Tree) Parameters() Parameters { return t.params }
|
||||||
|
|
||||||
// Add implements the Consensus interface
|
// Add implements the Consensus interface
|
||||||
func (t *Tree) Add(choice ids.ID) {
|
func (t *Tree) Add(choice ids.ID) {
|
||||||
prefix := t.root.DecidedPrefix()
|
prefix := t.node.DecidedPrefix()
|
||||||
// Make sure that we haven't already decided against this new id
|
// Make sure that we haven't already decided against this new id
|
||||||
if ids.EqualSubset(0, prefix, t.Preference(), choice) {
|
if ids.EqualSubset(0, prefix, t.Preference(), choice) {
|
||||||
t.root = t.root.Add(choice)
|
t.node = t.node.Add(choice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preference implements the Consensus interface
|
|
||||||
func (t *Tree) Preference() ids.ID { return t.root.Preference() }
|
|
||||||
|
|
||||||
// RecordPoll implements the Consensus interface
|
// RecordPoll implements the Consensus interface
|
||||||
func (t *Tree) RecordPoll(votes ids.Bag) {
|
func (t *Tree) RecordPoll(votes ids.Bag) {
|
||||||
// Get the assumed decided prefix of the root node.
|
// Get the assumed decided prefix of the root node.
|
||||||
decidedPrefix := t.root.DecidedPrefix()
|
decidedPrefix := t.node.DecidedPrefix()
|
||||||
|
|
||||||
// If any of the bits differ from the preference in this prefix, the vote is
|
// If any of the bits differ from the preference in this prefix, the vote is
|
||||||
// for a rejected operation. So, we filter out these invalid votes.
|
// for a rejected operation. So, we filter out these invalid votes.
|
||||||
|
@ -78,7 +75,7 @@ func (t *Tree) RecordPoll(votes ids.Bag) {
|
||||||
|
|
||||||
// Now that the votes have been restricted to valid votes, pass them into
|
// Now that the votes have been restricted to valid votes, pass them into
|
||||||
// the first snowball instance
|
// the first snowball instance
|
||||||
t.root = t.root.RecordPoll(filteredVotes, t.shouldReset)
|
t.node = t.node.RecordPoll(filteredVotes, t.shouldReset)
|
||||||
|
|
||||||
// Because we just passed the reset into the snowball instance, we should no
|
// Because we just passed the reset into the snowball instance, we should no
|
||||||
// longer reset.
|
// longer reset.
|
||||||
|
@ -88,14 +85,11 @@ func (t *Tree) RecordPoll(votes ids.Bag) {
|
||||||
// RecordUnsuccessfulPoll implements the Consensus interface
|
// RecordUnsuccessfulPoll implements the Consensus interface
|
||||||
func (t *Tree) RecordUnsuccessfulPoll() { t.shouldReset = true }
|
func (t *Tree) RecordUnsuccessfulPoll() { t.shouldReset = true }
|
||||||
|
|
||||||
// Finalized implements the Consensus interface
|
|
||||||
func (t *Tree) Finalized() bool { return t.root.Finalized() }
|
|
||||||
|
|
||||||
func (t *Tree) String() string {
|
func (t *Tree) String() string {
|
||||||
builder := strings.Builder{}
|
builder := strings.Builder{}
|
||||||
|
|
||||||
prefixes := []string{""}
|
prefixes := []string{""}
|
||||||
nodes := []node{t.root}
|
nodes := []node{t.node}
|
||||||
|
|
||||||
for len(prefixes) > 0 {
|
for len(prefixes) > 0 {
|
||||||
newSize := len(prefixes) - 1
|
newSize := len(prefixes) - 1
|
||||||
|
|
|
@ -170,10 +170,10 @@ func TestSnowballLastBinary(t *testing.T) {
|
||||||
tree.Initialize(params, zero)
|
tree.Initialize(params, zero)
|
||||||
tree.Add(one)
|
tree.Add(one)
|
||||||
|
|
||||||
expected := "SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [0, 255)\n" +
|
expected := "SB(NumSuccessfulPolls = 0, SF(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"
|
" SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 255"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !zero.Equals(pref) {
|
} else if pref := tree.Preference(); !zero.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", zero, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", zero, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -378,9 +378,9 @@ func TestSnowballFineGrained(t *testing.T) {
|
||||||
tree := Tree{}
|
tree := Tree{}
|
||||||
tree.Initialize(params, c0000)
|
tree.Initialize(params, c0000)
|
||||||
{
|
{
|
||||||
expected := "SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [0, 256)"
|
expected := "SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 256)"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -390,11 +390,11 @@ func TestSnowballFineGrained(t *testing.T) {
|
||||||
|
|
||||||
tree.Add(c1100)
|
tree.Add(c1100)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 0\n" +
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -404,13 +404,13 @@ func TestSnowballFineGrained(t *testing.T) {
|
||||||
|
|
||||||
tree.Add(c1000)
|
tree.Add(c1000)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 0\n" +
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(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(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -420,16 +420,16 @@ func TestSnowballFineGrained(t *testing.T) {
|
||||||
|
|
||||||
tree.Add(c0010)
|
tree.Add(c0010)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 0\n" +
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 2)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(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(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(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(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -441,15 +441,15 @@ func TestSnowballFineGrained(t *testing.T) {
|
||||||
c0000Bag.Add(c0000)
|
c0000Bag.Add(c0000)
|
||||||
tree.RecordPoll(c0000Bag)
|
tree.RecordPoll(c0000Bag)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 1, Finalized = false)) Bit = 0\n" +
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n" +
|
||||||
" SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 1, Finalized = false)) Bit = 2\n" +
|
" SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n" +
|
||||||
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)\n" +
|
" SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(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(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 1))) Bit = 1\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)\n" +
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)\n" +
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [2, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [2, 256)"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -461,11 +461,11 @@ func TestSnowballFineGrained(t *testing.T) {
|
||||||
c0010Bag.Add(c0010)
|
c0010Bag.Add(c0010)
|
||||||
tree.RecordPoll(c0010Bag)
|
tree.RecordPoll(c0010Bag)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 1, SF = SF(Preference = 1, Confidence = 1, Finalized = false)) Bit = 2\n" +
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 1, SF(Confidence = 1, Finalized = false, SL(Preference = 1))) Bit = 2\n" +
|
||||||
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)\n" +
|
" SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n" +
|
||||||
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)"
|
" SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
} else if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -475,9 +475,9 @@ func TestSnowballFineGrained(t *testing.T) {
|
||||||
|
|
||||||
tree.RecordPoll(c0010Bag)
|
tree.RecordPoll(c0010Bag)
|
||||||
{
|
{
|
||||||
expected := "SB(NumSuccessfulPolls = 2, Confidence = 2, Finalized = true) Bits = [3, 256)"
|
expected := "SB(NumSuccessfulPolls = 2, SF(Confidence = 2, Finalized = true)) Bits = [3, 256)"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !c0010.Equals(pref) {
|
} else if pref := tree.Preference(); !c0010.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0010, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0010, pref)
|
||||||
} else if !tree.Finalized() {
|
} else if !tree.Finalized() {
|
||||||
|
@ -496,9 +496,9 @@ func TestSnowballDoubleAdd(t *testing.T) {
|
||||||
tree.Add(Red)
|
tree.Add(Red)
|
||||||
|
|
||||||
{
|
{
|
||||||
expected := "SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [0, 256)"
|
expected := "SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 256)"
|
||||||
if str := tree.String(); expected != str {
|
if str := tree.String(); expected != str {
|
||||||
t.Fatalf("Wrong string. Expected %s got %s", expected, str)
|
t.Fatalf("Wrong string. Expected:\n%s\ngot:\n%s", expected, str)
|
||||||
} else if pref := tree.Preference(); !Red.Equals(pref) {
|
} else if pref := tree.Preference(); !Red.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -547,7 +547,7 @@ func TestSnowballFilterBinaryChildren(t *testing.T) {
|
||||||
tree := Tree{}
|
tree := Tree{}
|
||||||
tree.Initialize(params, c0000)
|
tree.Initialize(params, c0000)
|
||||||
{
|
{
|
||||||
expected := "SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [0, 256)"
|
expected := "SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [0, 256)"
|
||||||
if pref := tree.Preference(); !c0000.Equals(pref) {
|
if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -559,9 +559,9 @@ func TestSnowballFilterBinaryChildren(t *testing.T) {
|
||||||
|
|
||||||
tree.Add(c1000)
|
tree.Add(c1000)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 0\n"+
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)\n"+
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)"
|
||||||
if pref := tree.Preference(); !c0000.Equals(pref) {
|
if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -573,12 +573,12 @@ func TestSnowballFilterBinaryChildren(t *testing.T) {
|
||||||
|
|
||||||
tree.Add(c0010)
|
tree.Add(c0010)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 0\n"+
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 0\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 2)\n"+
|
" SB(NumSuccessfulPolls = 0, SF(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(Preference = 0, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n"+
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n"+
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)"
|
||||||
if pref := tree.Preference(); !c0000.Equals(pref) {
|
if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -592,11 +592,11 @@ func TestSnowballFilterBinaryChildren(t *testing.T) {
|
||||||
c0000Bag.Add(c0000)
|
c0000Bag.Add(c0000)
|
||||||
tree.RecordPoll(c0000Bag)
|
tree.RecordPoll(c0000Bag)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 1, Finalized = false)) Bit = 0\n"+
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n"+
|
||||||
" SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 1, Finalized = false)) Bit = 2\n"+
|
" SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n"+
|
||||||
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)\n"+
|
" SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n"+
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)"
|
||||||
if pref := tree.Preference(); !c0000.Equals(pref) {
|
if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -608,11 +608,11 @@ func TestSnowballFilterBinaryChildren(t *testing.T) {
|
||||||
|
|
||||||
tree.Add(c0100)
|
tree.Add(c0100)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 1, Finalized = false)) Bit = 0\n"+
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 0\n"+
|
||||||
" SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 1, Finalized = false)) Bit = 2\n"+
|
" SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 1, Finalized = false, SL(Preference = 0))) Bit = 2\n"+
|
||||||
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)\n"+
|
" SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)\n"+
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [1, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [1, 256)"
|
||||||
if pref := tree.Preference(); !c0000.Equals(pref) {
|
if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
@ -626,9 +626,9 @@ func TestSnowballFilterBinaryChildren(t *testing.T) {
|
||||||
c0100Bag.Add(c0100)
|
c0100Bag.Add(c0100)
|
||||||
tree.RecordPoll(c0100Bag)
|
tree.RecordPoll(c0100Bag)
|
||||||
{
|
{
|
||||||
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF = SF(Preference = 0, Confidence = 0, Finalized = false)) Bit = 2\n"+
|
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 0, SF(Confidence = 0, Finalized = false, SL(Preference = 0))) Bit = 2\n"+
|
||||||
" SB(NumSuccessfulPolls = 1, Confidence = 1, Finalized = true) Bits = [3, 256)\n"+
|
" SB(NumSuccessfulPolls = 1, SF(Confidence = 1, Finalized = true)) Bits = [3, 256)\n"+
|
||||||
" SB(NumSuccessfulPolls = 0, Confidence = 0, Finalized = false) Bits = [3, 256)"
|
" SB(NumSuccessfulPolls = 0, SF(Confidence = 0, Finalized = false)) Bits = [3, 256)"
|
||||||
if pref := tree.Preference(); !c0000.Equals(pref) {
|
if pref := tree.Preference(); !c0000.Equals(pref) {
|
||||||
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
t.Fatalf("Wrong preference. Expected %s got %s", c0000, pref)
|
||||||
} else if tree.Finalized() {
|
} else if tree.Finalized() {
|
||||||
|
|
|
@ -9,64 +9,40 @@ import (
|
||||||
|
|
||||||
// unarySnowball is the implementation of a unary snowball instance
|
// unarySnowball is the implementation of a unary snowball instance
|
||||||
type unarySnowball struct {
|
type unarySnowball struct {
|
||||||
// beta is the number of consecutive successful queries required for
|
// wrap the unary snowflake logic
|
||||||
// finalization.
|
unarySnowflake
|
||||||
beta int
|
|
||||||
|
|
||||||
// confidence tracks the number of successful polls in a row that have
|
|
||||||
// returned the preference
|
|
||||||
confidence int
|
|
||||||
|
|
||||||
// numSuccessfulPolls tracks the total number of successful network polls
|
// numSuccessfulPolls tracks the total number of successful network polls
|
||||||
numSuccessfulPolls int
|
numSuccessfulPolls int
|
||||||
|
|
||||||
// finalized prevents the state from changing after the required number of
|
|
||||||
// consecutive polls has been reached
|
|
||||||
finalized bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize implements the UnarySnowball interface
|
|
||||||
func (sb *unarySnowball) Initialize(beta int) { sb.beta = beta }
|
|
||||||
|
|
||||||
// RecordSuccessfulPoll implements the UnarySnowball interface
|
// RecordSuccessfulPoll implements the UnarySnowball interface
|
||||||
func (sb *unarySnowball) RecordSuccessfulPoll() {
|
func (sb *unarySnowball) RecordSuccessfulPoll() {
|
||||||
sb.numSuccessfulPolls++
|
sb.numSuccessfulPolls++
|
||||||
sb.confidence++
|
sb.unarySnowflake.RecordSuccessfulPoll()
|
||||||
sb.finalized = sb.finalized || sb.confidence >= sb.beta
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordUnsuccessfulPoll implements the UnarySnowball interface
|
|
||||||
func (sb *unarySnowball) RecordUnsuccessfulPoll() { sb.confidence = 0 }
|
|
||||||
|
|
||||||
// Finalized implements the UnarySnowball interface
|
|
||||||
func (sb *unarySnowball) Finalized() bool { return sb.finalized }
|
|
||||||
|
|
||||||
// Extend implements the UnarySnowball interface
|
// Extend implements the UnarySnowball interface
|
||||||
func (sb *unarySnowball) Extend(beta int, choice int) BinarySnowball {
|
func (sb *unarySnowball) Extend(beta int, choice int) BinarySnowball {
|
||||||
bs := &binarySnowball{
|
bs := &binarySnowball{
|
||||||
preference: choice,
|
binarySnowflake: binarySnowflake{
|
||||||
snowflake: binarySnowflake{
|
binarySlush: binarySlush{preference: choice},
|
||||||
beta: beta,
|
beta: beta,
|
||||||
preference: choice,
|
|
||||||
finalized: sb.Finalized(),
|
finalized: sb.Finalized(),
|
||||||
},
|
},
|
||||||
|
preference: choice,
|
||||||
}
|
}
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone implements the UnarySnowball interface
|
// Clone implements the UnarySnowball interface
|
||||||
func (sb *unarySnowball) Clone() UnarySnowball {
|
func (sb *unarySnowball) Clone() UnarySnowball {
|
||||||
return &unarySnowball{
|
newSnowball := *sb
|
||||||
beta: sb.beta,
|
return &newSnowball
|
||||||
numSuccessfulPolls: sb.numSuccessfulPolls,
|
|
||||||
confidence: sb.confidence,
|
|
||||||
finalized: sb.Finalized(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *unarySnowball) String() string {
|
func (sb *unarySnowball) String() string {
|
||||||
return fmt.Sprintf("SB(NumSuccessfulPolls = %d, Confidence = %d, Finalized = %v)",
|
return fmt.Sprintf("SB(NumSuccessfulPolls = %d, %s)",
|
||||||
sb.numSuccessfulPolls,
|
sb.numSuccessfulPolls,
|
||||||
sb.confidence,
|
&sb.unarySnowflake)
|
||||||
sb.Finalized())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ func TestUnarySnowball(t *testing.T) {
|
||||||
sbCloneIntf := sb.Clone()
|
sbCloneIntf := sb.Clone()
|
||||||
sbClone, ok := sbCloneIntf.(*unarySnowball)
|
sbClone, ok := sbCloneIntf.(*unarySnowball)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("Unexpectedly clone type")
|
t.Fatalf("Unexpected clone type")
|
||||||
}
|
}
|
||||||
|
|
||||||
UnarySnowballStateTest(t, sbClone, 2, 1, false)
|
UnarySnowballStateTest(t, sbClone, 2, 1, false)
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package snowball
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// unarySnowflake is the implementation of a unary snowflake instance
|
||||||
|
type unarySnowflake struct {
|
||||||
|
// beta is the number of consecutive successful queries required for
|
||||||
|
// finalization.
|
||||||
|
beta int
|
||||||
|
|
||||||
|
// confidence tracks the number of successful polls in a row that have
|
||||||
|
// returned the preference
|
||||||
|
confidence int
|
||||||
|
|
||||||
|
// finalized prevents the state from changing after the required number of
|
||||||
|
// consecutive polls has been reached
|
||||||
|
finalized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize implements the UnarySnowflake interface
|
||||||
|
func (sf *unarySnowflake) Initialize(beta int) { sf.beta = beta }
|
||||||
|
|
||||||
|
// RecordSuccessfulPoll implements the UnarySnowflake interface
|
||||||
|
func (sf *unarySnowflake) RecordSuccessfulPoll() {
|
||||||
|
sf.confidence++
|
||||||
|
sf.finalized = sf.finalized || sf.confidence >= sf.beta
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordUnsuccessfulPoll implements the UnarySnowflake interface
|
||||||
|
func (sf *unarySnowflake) RecordUnsuccessfulPoll() { sf.confidence = 0 }
|
||||||
|
|
||||||
|
// Finalized implements the UnarySnowflake interface
|
||||||
|
func (sf *unarySnowflake) Finalized() bool { return sf.finalized }
|
||||||
|
|
||||||
|
// Extend implements the UnarySnowflake interface
|
||||||
|
func (sf *unarySnowflake) Extend(beta int, choice int) BinarySnowflake {
|
||||||
|
return &binarySnowflake{
|
||||||
|
binarySlush: binarySlush{preference: choice},
|
||||||
|
confidence: sf.confidence,
|
||||||
|
beta: beta,
|
||||||
|
finalized: sf.finalized,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone implements the UnarySnowflake interface
|
||||||
|
func (sf *unarySnowflake) Clone() UnarySnowflake {
|
||||||
|
newSnowflake := *sf
|
||||||
|
return &newSnowflake
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *unarySnowflake) String() string {
|
||||||
|
return fmt.Sprintf("SF(Confidence = %d, Finalized = %v)",
|
||||||
|
sf.confidence,
|
||||||
|
sf.finalized)
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
package snowball
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UnarySnowflakeStateTest(t *testing.T, sf *unarySnowflake, expectedConfidence int, expectedFinalized bool) {
|
||||||
|
if confidence := sf.confidence; confidence != expectedConfidence {
|
||||||
|
t.Fatalf("Wrong confidence. Expected %d got %d", expectedConfidence, confidence)
|
||||||
|
} else if finalized := sf.Finalized(); finalized != expectedFinalized {
|
||||||
|
t.Fatalf("Wrong finalized status. Expected %v got %v", expectedFinalized, finalized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnarySnowflake(t *testing.T) {
|
||||||
|
beta := 2
|
||||||
|
|
||||||
|
sf := &unarySnowflake{}
|
||||||
|
sf.Initialize(beta)
|
||||||
|
|
||||||
|
sf.RecordSuccessfulPoll()
|
||||||
|
UnarySnowflakeStateTest(t, sf, 1, false)
|
||||||
|
|
||||||
|
sf.RecordUnsuccessfulPoll()
|
||||||
|
UnarySnowflakeStateTest(t, sf, 0, false)
|
||||||
|
|
||||||
|
sf.RecordSuccessfulPoll()
|
||||||
|
UnarySnowflakeStateTest(t, sf, 1, false)
|
||||||
|
|
||||||
|
sfCloneIntf := sf.Clone()
|
||||||
|
sfClone, ok := sfCloneIntf.(*unarySnowflake)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Unexpected clone type")
|
||||||
|
}
|
||||||
|
|
||||||
|
UnarySnowflakeStateTest(t, sfClone, 1, false)
|
||||||
|
|
||||||
|
binarySnowflake := sfClone.Extend(beta, 0)
|
||||||
|
|
||||||
|
binarySnowflake.RecordUnsuccessfulPoll()
|
||||||
|
|
||||||
|
binarySnowflake.RecordSuccessfulPoll(1)
|
||||||
|
|
||||||
|
if binarySnowflake.Finalized() {
|
||||||
|
t.Fatalf("Should not have finalized")
|
||||||
|
}
|
||||||
|
|
||||||
|
binarySnowflake.RecordSuccessfulPoll(1)
|
||||||
|
|
||||||
|
if binarySnowflake.Preference() != 1 {
|
||||||
|
t.Fatalf("Wrong preference")
|
||||||
|
} else if !binarySnowflake.Finalized() {
|
||||||
|
t.Fatalf("Should have finalized")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue