mirror of https://github.com/poanetwork/gecko.git
properly weight bootstrapping validators by stake
This commit is contained in:
parent
90f7ba2d6a
commit
11ebe7c6b1
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/ava-labs/gecko/snow/triggers"
|
||||
"github.com/ava-labs/gecko/snow/validators"
|
||||
"github.com/ava-labs/gecko/utils/logging"
|
||||
"github.com/ava-labs/gecko/utils/math"
|
||||
"github.com/ava-labs/gecko/vms"
|
||||
|
||||
avacon "github.com/ava-labs/gecko/snow/consensus/avalanche"
|
||||
|
@ -390,13 +391,22 @@ func (m *manager) createAvalancheChain(
|
|||
},
|
||||
}
|
||||
|
||||
bootstrapWeight := uint64(0)
|
||||
for _, beacon := range beacons.List() {
|
||||
newWeight, err := math.Add64(bootstrapWeight, beacon.Weight())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bootstrapWeight = newWeight
|
||||
}
|
||||
|
||||
engine.Initialize(avaeng.Config{
|
||||
BootstrapConfig: avaeng.BootstrapConfig{
|
||||
Config: common.Config{
|
||||
Context: ctx,
|
||||
Validators: validators,
|
||||
Beacons: beacons,
|
||||
Alpha: beacons.Len()/2 + 1, // must be > 50%
|
||||
Alpha: bootstrapWeight/2 + 1, // must be > 50%
|
||||
Sender: &sender,
|
||||
},
|
||||
VtxBlocked: vtxBlocker,
|
||||
|
@ -417,6 +427,8 @@ func (m *manager) createAvalancheChain(
|
|||
go ctx.Log.RecoverAndPanic(handler.Dispatch)
|
||||
|
||||
awaiting := &networking.AwaitingConnections{
|
||||
Requested: beacons,
|
||||
WeightRequired: (3*bootstrapWeight + 3) / 4, // 75% must be connected to
|
||||
Finish: func() {
|
||||
ctx.Lock.Lock()
|
||||
defer ctx.Lock.Unlock()
|
||||
|
@ -424,10 +436,6 @@ func (m *manager) createAvalancheChain(
|
|||
engine.Startup()
|
||||
},
|
||||
}
|
||||
for _, vdr := range beacons.List() {
|
||||
awaiting.Requested.Add(vdr.ID())
|
||||
}
|
||||
awaiting.NumRequired = (3*awaiting.Requested.Len() + 3) / 4 // 75% must be connected to
|
||||
m.awaiter.AwaitConnections(awaiting)
|
||||
|
||||
return nil
|
||||
|
@ -468,6 +476,15 @@ func (m *manager) createSnowmanChain(
|
|||
sender := sender.Sender{}
|
||||
sender.Initialize(ctx, m.sender, m.chainRouter, m.timeoutManager)
|
||||
|
||||
bootstrapWeight := uint64(0)
|
||||
for _, beacon := range beacons.List() {
|
||||
newWeight, err := math.Add64(bootstrapWeight, beacon.Weight())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bootstrapWeight = newWeight
|
||||
}
|
||||
|
||||
// The engine handles consensus
|
||||
engine := smeng.Transitive{}
|
||||
engine.Initialize(smeng.Config{
|
||||
|
@ -476,7 +493,7 @@ func (m *manager) createSnowmanChain(
|
|||
Context: ctx,
|
||||
Validators: validators,
|
||||
Beacons: beacons,
|
||||
Alpha: beacons.Len()/2 + 1, // must be > 50%
|
||||
Alpha: bootstrapWeight/2 + 1, // must be > 50%
|
||||
Sender: &sender,
|
||||
},
|
||||
Blocked: blocked,
|
||||
|
@ -496,6 +513,8 @@ func (m *manager) createSnowmanChain(
|
|||
go ctx.Log.RecoverAndPanic(handler.Dispatch)
|
||||
|
||||
awaiting := &networking.AwaitingConnections{
|
||||
Requested: beacons,
|
||||
WeightRequired: (3*bootstrapWeight + 3) / 4, // 75% must be connected to
|
||||
Finish: func() {
|
||||
ctx.Lock.Lock()
|
||||
defer ctx.Lock.Unlock()
|
||||
|
@ -503,10 +522,6 @@ func (m *manager) createSnowmanChain(
|
|||
engine.Startup()
|
||||
},
|
||||
}
|
||||
for _, vdr := range beacons.List() {
|
||||
awaiting.Requested.Add(vdr.ID())
|
||||
}
|
||||
awaiting.NumRequired = (3*awaiting.Requested.Len() + 3) / 4 // 75% must be connected to
|
||||
m.awaiter.AwaitConnections(awaiting)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ func newConfig(t *testing.T) (BootstrapConfig, ids.ShortID, *common.SenderTest,
|
|||
Context: ctx,
|
||||
Validators: peers,
|
||||
Beacons: peers,
|
||||
Alpha: peers.Len()/2 + 1,
|
||||
Alpha: uint64(peers.Len()/2 + 1),
|
||||
Sender: sender,
|
||||
}
|
||||
return BootstrapConfig{
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
stdmath "math"
|
||||
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/utils/math"
|
||||
)
|
||||
|
||||
// Bootstrapper implements the Engine interface.
|
||||
|
@ -15,7 +18,7 @@ type Bootstrapper struct {
|
|||
acceptedFrontier ids.Set
|
||||
|
||||
pendingAccepted ids.ShortSet
|
||||
accepted ids.Bag
|
||||
acceptedVotes map[[32]byte]uint64
|
||||
|
||||
RequestID uint32
|
||||
}
|
||||
|
@ -30,7 +33,7 @@ func (b *Bootstrapper) Initialize(config Config) {
|
|||
b.pendingAccepted.Add(vdrID)
|
||||
}
|
||||
|
||||
b.accepted.SetThreshold(config.Alpha)
|
||||
b.acceptedVotes = make(map[[32]byte]uint64)
|
||||
}
|
||||
|
||||
// Startup implements the Engine interface.
|
||||
|
@ -95,10 +98,29 @@ func (b *Bootstrapper) Accepted(validatorID ids.ShortID, requestID uint32, conta
|
|||
}
|
||||
b.pendingAccepted.Remove(validatorID)
|
||||
|
||||
b.accepted.Add(containerIDs.List()...)
|
||||
weight := uint64(0)
|
||||
if vdr, ok := b.Validators.Get(validatorID); ok {
|
||||
weight = vdr.Weight()
|
||||
}
|
||||
|
||||
for _, containerID := range containerIDs.List() {
|
||||
key := containerID.Key()
|
||||
previousWeight := b.acceptedVotes[key]
|
||||
newWeight, err := math.Add64(weight, previousWeight)
|
||||
if err != nil {
|
||||
newWeight = stdmath.MaxUint64
|
||||
}
|
||||
b.acceptedVotes[key] = newWeight
|
||||
}
|
||||
|
||||
if b.pendingAccepted.Len() == 0 {
|
||||
accepted := b.accepted.Threshold()
|
||||
accepted := ids.Set{}
|
||||
for key, weight := range b.acceptedVotes {
|
||||
if weight >= b.Config.Alpha {
|
||||
accepted.Add(ids.NewID(key))
|
||||
}
|
||||
}
|
||||
|
||||
if size := accepted.Len(); size == 0 && b.Config.Beacons.Len() > 0 {
|
||||
b.Context.Log.Warn("Bootstrapping finished with no accepted frontier. This is likely a result of failing to be able to connect to the specified bootstraps, or no transactions have been issued on this network yet")
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,7 @@ type Config struct {
|
|||
Validators validators.Set
|
||||
Beacons validators.Set
|
||||
|
||||
Alpha int
|
||||
Alpha uint64
|
||||
Sender Sender
|
||||
Bootstrapable Bootstrapable
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ func newConfig(t *testing.T) (BootstrapConfig, ids.ShortID, *common.SenderTest,
|
|||
Context: ctx,
|
||||
Validators: peers,
|
||||
Beacons: peers,
|
||||
Alpha: peers.Len()/2 + 1,
|
||||
Alpha: uint64(peers.Len()/2 + 1),
|
||||
Sender: sender,
|
||||
}
|
||||
return BootstrapConfig{
|
||||
|
|
|
@ -4,31 +4,43 @@
|
|||
package networking
|
||||
|
||||
import (
|
||||
stdmath "math"
|
||||
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/snow/validators"
|
||||
"github.com/ava-labs/gecko/utils/math"
|
||||
)
|
||||
|
||||
// AwaitingConnections ...
|
||||
type AwaitingConnections struct {
|
||||
Requested ids.ShortSet
|
||||
NumRequired int
|
||||
Finish func()
|
||||
Requested validators.Set
|
||||
WeightRequired uint64
|
||||
Finish func()
|
||||
|
||||
connected ids.ShortSet
|
||||
weight uint64
|
||||
}
|
||||
|
||||
// Add ...
|
||||
func (aw *AwaitingConnections) Add(conn ids.ShortID) {
|
||||
if aw.Requested.Contains(conn) {
|
||||
aw.connected.Add(conn)
|
||||
vdr, ok := aw.Requested.Get(conn)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
weight, err := math.Add64(vdr.Weight(), aw.weight)
|
||||
if err != nil {
|
||||
weight = stdmath.MaxUint64
|
||||
}
|
||||
aw.weight = weight
|
||||
}
|
||||
|
||||
// Remove ...
|
||||
func (aw *AwaitingConnections) Remove(conn ids.ShortID) {
|
||||
aw.connected.Remove(conn)
|
||||
vdr, ok := aw.Requested.Get(conn)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
aw.weight -= vdr.Weight()
|
||||
}
|
||||
|
||||
// Ready ...
|
||||
func (aw *AwaitingConnections) Ready() bool {
|
||||
return aw.connected.Len() >= aw.NumRequired
|
||||
}
|
||||
func (aw *AwaitingConnections) Ready() bool { return aw.weight >= aw.WeightRequired }
|
||||
|
|
|
@ -24,6 +24,9 @@ type Set interface {
|
|||
// Add the provided validator to the set.
|
||||
Add(Validator)
|
||||
|
||||
// Get the validator from the set.
|
||||
Get(ids.ShortID) (Validator, bool)
|
||||
|
||||
// Remove the validator with the specified ID.
|
||||
Remove(ids.ShortID)
|
||||
|
||||
|
@ -102,6 +105,22 @@ func (s *set) add(vdr Validator) {
|
|||
s.sampler.Weights = append(s.sampler.Weights, w)
|
||||
}
|
||||
|
||||
// Get implements the Set interface.
|
||||
func (s *set) Get(vdrID ids.ShortID) (Validator, bool) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
return s.get(vdrID)
|
||||
}
|
||||
|
||||
func (s *set) get(vdrID ids.ShortID) (Validator, bool) {
|
||||
index, ok := s.vdrMap[vdrID.Key()]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return s.vdrSlice[index], true
|
||||
}
|
||||
|
||||
// Remove implements the Set interface.
|
||||
func (s *set) Remove(vdrID ids.ShortID) {
|
||||
s.lock.Lock()
|
||||
|
|
|
@ -86,7 +86,7 @@ func ConsensusLeader(numBlocks, numTxsPerBlock int, b *testing.B) {
|
|||
Context: ctx,
|
||||
Validators: vdrs,
|
||||
Beacons: beacons,
|
||||
Alpha: (beacons.Len() + 1) / 2,
|
||||
Alpha: uint64(beacons.Len()/2 + 1),
|
||||
Sender: &sender,
|
||||
},
|
||||
Blocked: blocked,
|
||||
|
@ -217,7 +217,7 @@ func ConsensusFollower(numBlocks, numTxsPerBlock int, b *testing.B) {
|
|||
Context: ctx,
|
||||
Validators: vdrs,
|
||||
Beacons: beacons,
|
||||
Alpha: (beacons.Len() + 1) / 2,
|
||||
Alpha: uint64(beacons.Len()/2 + 1),
|
||||
Sender: &sender,
|
||||
},
|
||||
Blocked: blocked,
|
||||
|
|
Loading…
Reference in New Issue