when a node joins a Subnet it creates all of the blockchains the Subnet is validating

This commit is contained in:
Dan Laine 2020-03-17 17:54:03 -04:00
parent eb5851431d
commit 1f871c097d
3 changed files with 46 additions and 14 deletions

View File

@ -7,6 +7,8 @@ import (
"fmt"
"time"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/database/versiondb"
)
@ -86,7 +88,7 @@ func (tx *advanceTimeTx) SemanticVerify(db database.Database) (*versiondb.Databa
return nil, nil, nil, nil, err
}
current, pending, err := tx.vm.calculateValidators(db, tx.Timestamp(), DefaultSubnetID)
current, pending, _, _, err := tx.vm.calculateValidators(db, tx.Timestamp(), DefaultSubnetID)
if err != nil {
return nil, nil, nil, nil, err
}
@ -98,29 +100,35 @@ func (tx *advanceTimeTx) SemanticVerify(db database.Database) (*versiondb.Databa
return nil, nil, nil, nil, err
}
// For each subnet, calculate what current and pending validator sets should be
// For each Subnet, calculate what current and pending validator sets should be
// given new timestamp
// Key: Subnet ID
// Value: IDs of validators that will have started validating this Subnet when
// timestamp is advanced to tx.Timestamp()
startedValidating := make(map[ids.ID]ids.ShortSet, 0)
subnets, err := tx.vm.getSubnets(db)
if err != nil {
return nil, nil, nil, nil, err
}
for _, subnet := range subnets {
current, pending, err := tx.vm.calculateValidators(db, tx.Timestamp(), subnet.id)
current, pending, started, _, err := tx.vm.calculateValidators(db, tx.Timestamp(), subnet.id)
if err != nil {
return nil, nil, nil, nil, err
}
if err := tx.vm.putCurrentValidators(onCommitDB, current, subnet.id); err != nil {
return nil, nil, nil, nil, err
}
if err := tx.vm.putPendingValidators(onCommitDB, pending, subnet.id); err != nil {
return nil, nil, nil, nil, err
}
startedValidating[subnet.ID()] = started
}
// If this block is committed, update the validator sets
// onAbortDB or onCommitDB should commit (flush to vm.DB) before this is called
updateValidators := func() {
onCommitFunc := func() {
// For each Subnet, update the node's validator manager to reflect current Subnet membership
subnets, err := tx.vm.getSubnets(tx.vm.DB)
if err != nil {
tx.vm.Ctx.Log.Error("failed to get subnets: %s", err)
@ -128,18 +136,35 @@ func (tx *advanceTimeTx) SemanticVerify(db database.Database) (*versiondb.Databa
}
for _, subnet := range subnets {
if err := tx.vm.updateValidators(subnet.id); err != nil {
tx.vm.Ctx.Log.Debug("failed to update validators on the default subnet: %s", err)
tx.vm.Ctx.Log.Debug("failed to update Subnet %s: %s", subnet.id, err)
}
}
if err := tx.vm.updateValidators(DefaultSubnetID); err != nil {
tx.vm.Ctx.Log.Fatal("failed to update validators on the default subnet: %s", err)
tx.vm.Ctx.Log.Fatal("failed to update Default Subnet: %s", err)
}
// If this node started validating a Subnet, create the blockchains that the Subnet validates
chains, err := tx.vm.getChains(tx.vm.DB) // all blockchains
if err != nil {
tx.vm.Ctx.Log.Error("couldn't get blockchains: %s", err)
return
}
for subnetID, validatorIDs := range startedValidating {
if !validatorIDs.Contains(tx.vm.Ctx.NodeID) {
continue
}
for _, chain := range chains {
if chain.SubnetID.Equals(subnetID) {
tx.vm.createChain(chain)
}
}
}
}
// Specify what the state of the chain will be if this proposal is aborted
onAbortDB := versiondb.New(db) // state doesn't change
return onCommitDB, onAbortDB, updateValidators, nil, nil
return onCommitDB, onAbortDB, onCommitFunc, nil, nil
}
// InitiallyPrefersCommit returns true if the proposed time isn't after the

View File

@ -194,7 +194,8 @@ func (tx *CreateChainTx) SemanticVerify(db database.Database) (func(), error) {
}
}
// If this proposal is committed, create the new blockchain using the chain manager
// If this proposal is committed and this node is a member of the
// subnet that validates the blockchain, create the blockchain
onAccept := func() {
tx.vm.createChain(tx)
}

View File

@ -291,7 +291,7 @@ func (vm *VM) initBlockchains() error {
return err
}
for _, chain := range blockchains { // Create each blockchain
for _, chain := range blockchains {
vm.createChain(chain)
}
return nil
@ -325,6 +325,7 @@ func (vm *VM) createChain(tx *CreateChainTx) {
validators, subnetExists := vm.Validators.GetValidatorSet(tx.SubnetID)
if !subnetExists {
vm.Ctx.Log.Error("blockchain %s validated by Subnet %s but couldn't get that Subnet. Blockchain not created")
return
}
if !validators.Contains(vm.Ctx.NodeID) { // This node doesn't validate this blockchain
return
@ -653,13 +654,16 @@ func (vm *VM) nextSubnetValidatorChangeTime(db database.Database, subnetID ids.I
// Returns:
// 1) The validator set of subnet with ID [subnetID] when timestamp is advanced to [timestamp]
// 2) The pending validator set of subnet with ID [subnetID] when timestamp is advanced to [timestamp]
// 3) The IDs of the validators that start validating [subnetID] between now and [timestamp]
// 4) The IDs of the validators that stop validating [subnetID] between now and [timestamp]
// Note that this method will not remove validators from the current validator set of the default subnet.
// That happens in reward blocks.
func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, subnetID ids.ID) (current, pending *EventHeap, err error) {
func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, subnetID ids.ID) (current,
pending *EventHeap, started, stopped ids.ShortSet, err error) {
// remove validators whose end time <= [timestamp]
current, err = vm.getCurrentValidators(db, subnetID)
if err != nil {
return nil, nil, err
return nil, nil, nil, nil, err
}
if !subnetID.Equals(DefaultSubnetID) { // validators of default subnet removed in rewardValidatorTxs, not here
for current.Len() > 0 {
@ -668,11 +672,12 @@ func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, sub
break
}
current.Remove()
stopped.Add(next.Vdr().ID())
}
}
pending, err = vm.getPendingValidators(db, subnetID)
if err != nil {
return nil, nil, err
return nil, nil, nil, nil, err
}
for pending.Len() > 0 {
nextTx := pending.Peek() // pending staker with earliest start time
@ -681,8 +686,9 @@ func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, sub
}
heap.Push(current, nextTx)
heap.Pop(pending)
started.Add(nextTx.Vdr().ID())
}
return current, pending, nil
return current, pending, started, stopped, nil
}
func (vm *VM) getValidators(validatorEvents *EventHeap) []validators.Validator {