mirror of https://github.com/poanetwork/gecko.git
Added handling for if bootstrapping partially accepted a block pair
This commit is contained in:
parent
9580a3bf0f
commit
83c5bf39ae
|
@ -45,10 +45,24 @@ func (t *Transitive) Initialize(config Config) {
|
|||
}
|
||||
|
||||
func (t *Transitive) finishBootstrapping() {
|
||||
tail := t.Config.VM.LastAccepted()
|
||||
t.Config.VM.SetPreference(tail)
|
||||
t.Consensus.Initialize(t.Config.Context, t.Params, tail)
|
||||
t.bootstrapped = true
|
||||
tailID := t.Config.VM.LastAccepted()
|
||||
t.Consensus.Initialize(t.Config.Context, t.Params, tailID)
|
||||
|
||||
tail, err := t.Config.VM.GetBlock(tailID)
|
||||
if err != nil {
|
||||
t.Config.Context.Log.Error("Failed to get last accepted block due to: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch blk := tail.(type) {
|
||||
case OracleBlock:
|
||||
for _, blk := range blk.Options() {
|
||||
t.deliver(blk)
|
||||
}
|
||||
default:
|
||||
t.Config.VM.SetPreference(tailID)
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown implements the Engine interface
|
||||
|
|
|
@ -56,8 +56,17 @@ func setup(t *testing.T) (validators.Validator, validators.Set, *common.SenderTe
|
|||
te := &Transitive{}
|
||||
|
||||
te.Initialize(config)
|
||||
|
||||
vm.GetBlockF = func(blkID ids.ID) (snowman.Block, error) {
|
||||
if !blkID.Equals(gBlk.ID()) {
|
||||
t.Fatalf("Wrong block requested")
|
||||
}
|
||||
return gBlk, nil
|
||||
}
|
||||
|
||||
te.finishBootstrapping()
|
||||
|
||||
vm.GetBlockF = nil
|
||||
vm.LastAcceptedF = nil
|
||||
sender.CantGetAcceptedFrontier = true
|
||||
|
||||
|
@ -369,8 +378,17 @@ func TestEngineMultipleQuery(t *testing.T) {
|
|||
|
||||
te := &Transitive{}
|
||||
te.Initialize(config)
|
||||
|
||||
vm.GetBlockF = func(blkID ids.ID) (snowman.Block, error) {
|
||||
if !blkID.Equals(gBlk.ID()) {
|
||||
t.Fatalf("Wrong block requested")
|
||||
}
|
||||
return gBlk, nil
|
||||
}
|
||||
|
||||
te.finishBootstrapping()
|
||||
|
||||
vm.GetBlockF = nil
|
||||
vm.LastAcceptedF = nil
|
||||
sender.CantGetAcceptedFrontier = true
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ func (b *Block) Accept() {
|
|||
b.SetStatus(choices.Accepted) // Change state of this block
|
||||
b.VM.State.PutStatus(b.VM.DB, b.ID(), choices.Accepted) // Persist data
|
||||
b.VM.State.PutLastAccepted(b.VM.DB, b.ID())
|
||||
b.VM.lastAccepted = b.ID() // Change state of VM
|
||||
b.VM.LastAcceptedID = b.ID() // Change state of VM
|
||||
}
|
||||
|
||||
// Reject sets this block's status to Rejected and saves the status in state
|
||||
|
|
|
@ -45,7 +45,7 @@ type SnowmanVM struct {
|
|||
preferred ids.ID
|
||||
|
||||
// ID of the last accepted block
|
||||
lastAccepted ids.ID
|
||||
LastAcceptedID ids.ID
|
||||
|
||||
// unmarshals bytes to a block
|
||||
unmarshalBlockFunc func([]byte) (snowman.Block, error)
|
||||
|
@ -61,7 +61,7 @@ func (svm *SnowmanVM) SetPreference(ID ids.ID) { svm.preferred = ID }
|
|||
func (svm *SnowmanVM) Preferred() ids.ID { return svm.preferred }
|
||||
|
||||
// LastAccepted returns the block most recently accepted
|
||||
func (svm *SnowmanVM) LastAccepted() ids.ID { return svm.lastAccepted }
|
||||
func (svm *SnowmanVM) LastAccepted() ids.ID { return svm.LastAcceptedID }
|
||||
|
||||
// ParseBlock parses [bytes] to a block
|
||||
func (svm *SnowmanVM) ParseBlock(bytes []byte) (snowman.Block, error) {
|
||||
|
@ -161,10 +161,10 @@ func (svm *SnowmanVM) Initialize(
|
|||
}
|
||||
|
||||
if svm.DBInitialized() {
|
||||
if svm.lastAccepted, err = svm.State.GetLastAccepted(svm.DB); err != nil {
|
||||
if svm.LastAcceptedID, err = svm.State.GetLastAccepted(svm.DB); err != nil {
|
||||
return err
|
||||
}
|
||||
svm.preferred = svm.lastAccepted
|
||||
svm.preferred = svm.LastAcceptedID
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -43,7 +43,10 @@ type ProposalBlock struct {
|
|||
}
|
||||
|
||||
// Accept implements the snowman.Block interface
|
||||
func (pb *ProposalBlock) Accept() { pb.SetStatus(choices.Accepted) }
|
||||
func (pb *ProposalBlock) Accept() {
|
||||
pb.SetStatus(choices.Accepted)
|
||||
pb.VM.LastAcceptedID = pb.ID()
|
||||
}
|
||||
|
||||
// Initialize this block.
|
||||
// Sets [pb.vm] to [vm] and populates non-serialized fields
|
||||
|
|
|
@ -10,13 +10,22 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/ava-labs/gecko/chains"
|
||||
"github.com/ava-labs/gecko/chains/atomic"
|
||||
"github.com/ava-labs/gecko/database/memdb"
|
||||
"github.com/ava-labs/gecko/database/prefixdb"
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/snow"
|
||||
"github.com/ava-labs/gecko/snow/choices"
|
||||
"github.com/ava-labs/gecko/snow/consensus/snowball"
|
||||
"github.com/ava-labs/gecko/snow/engine/common"
|
||||
"github.com/ava-labs/gecko/snow/engine/common/queue"
|
||||
"github.com/ava-labs/gecko/snow/networking/handler"
|
||||
"github.com/ava-labs/gecko/snow/networking/router"
|
||||
"github.com/ava-labs/gecko/snow/networking/sender"
|
||||
"github.com/ava-labs/gecko/snow/networking/timeout"
|
||||
"github.com/ava-labs/gecko/snow/validators"
|
||||
"github.com/ava-labs/gecko/utils/crypto"
|
||||
"github.com/ava-labs/gecko/utils/formatting"
|
||||
|
@ -25,6 +34,9 @@ import (
|
|||
"github.com/ava-labs/gecko/vms/components/core"
|
||||
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||
"github.com/ava-labs/gecko/vms/timestampvm"
|
||||
|
||||
smcon "github.com/ava-labs/gecko/snow/consensus/snowman"
|
||||
smeng "github.com/ava-labs/gecko/snow/engine/snowman"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -1427,3 +1439,160 @@ func TestRestartFullyAccepted(t *testing.T) {
|
|||
t.Fatalf("Should have changed the genesis")
|
||||
}
|
||||
}
|
||||
|
||||
// test bootstrapping the node
|
||||
func TestBootstrapPartiallyAccepted(t *testing.T) {
|
||||
genesisAccounts := GenesisAccounts()
|
||||
genesisValidators := GenesisCurrentValidators()
|
||||
genesisChains := make([]*CreateChainTx, 0)
|
||||
|
||||
genesisState := Genesis{
|
||||
Accounts: genesisAccounts,
|
||||
Validators: genesisValidators,
|
||||
Chains: genesisChains,
|
||||
Timestamp: uint64(defaultGenesisTime.Unix()),
|
||||
}
|
||||
|
||||
genesisBytes, err := Codec.Marshal(genesisState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
db := memdb.New()
|
||||
vmDB := prefixdb.New([]byte("vm"), db)
|
||||
bootstrappingDB := prefixdb.New([]byte("bootstrapping"), db)
|
||||
|
||||
blocked, err := queue.New(bootstrappingDB)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vm := &VM{
|
||||
SnowmanVM: &core.SnowmanVM{},
|
||||
chainManager: chains.MockManager{},
|
||||
}
|
||||
defer vm.Shutdown()
|
||||
|
||||
defaultSubnet := validators.NewSet()
|
||||
vm.validators = validators.NewManager()
|
||||
vm.validators.PutValidatorSet(DefaultSubnetID, defaultSubnet)
|
||||
|
||||
vm.clock.Set(defaultGenesisTime)
|
||||
ctx := defaultContext()
|
||||
msgChan := make(chan common.Message, 1)
|
||||
|
||||
ctx.Lock.Lock()
|
||||
if err := vm.Initialize(ctx, vmDB, genesisBytes, msgChan, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
genesisID := vm.Preferred()
|
||||
|
||||
advanceTimeTx, err := vm.newAdvanceTimeTx(defaultGenesisTime.Add(time.Second))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
advanceTimeBlk, err := vm.newProposalBlock(vm.Preferred(), advanceTimeTx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
advanceTimeBlkID := advanceTimeBlk.ID()
|
||||
advanceTimeBlkBytes := advanceTimeBlk.Bytes()
|
||||
|
||||
advanceTimePreference := advanceTimeBlk.Options()[0]
|
||||
|
||||
vdrs := validators.NewSet()
|
||||
vdrs.Add(validators.NewValidator(ctx.NodeID, 1))
|
||||
beacons := vdrs
|
||||
|
||||
timeoutManager := timeout.Manager{}
|
||||
timeoutManager.Initialize(2 * time.Second)
|
||||
go timeoutManager.Dispatch()
|
||||
|
||||
router := &router.ChainRouter{}
|
||||
router.Initialize(logging.NoLog{}, &timeoutManager)
|
||||
|
||||
externalSender := &sender.ExternalSenderTest{T: t}
|
||||
externalSender.Default(true)
|
||||
|
||||
// Passes messages from the consensus engine to the network
|
||||
sender := sender.Sender{}
|
||||
|
||||
sender.Initialize(ctx, externalSender, router, &timeoutManager)
|
||||
|
||||
// The engine handles consensus
|
||||
engine := smeng.Transitive{}
|
||||
engine.Initialize(smeng.Config{
|
||||
BootstrapConfig: smeng.BootstrapConfig{
|
||||
Config: common.Config{
|
||||
Context: ctx,
|
||||
Validators: vdrs,
|
||||
Beacons: beacons,
|
||||
Alpha: uint64(beacons.Len()/2 + 1),
|
||||
Sender: &sender,
|
||||
},
|
||||
Blocked: blocked,
|
||||
VM: vm,
|
||||
},
|
||||
Params: snowball.Parameters{
|
||||
Metrics: prometheus.NewRegistry(),
|
||||
K: 1,
|
||||
Alpha: 1,
|
||||
BetaVirtuous: 20,
|
||||
BetaRogue: 20,
|
||||
ConcurrentRepolls: 1,
|
||||
},
|
||||
Consensus: &smcon.Topological{},
|
||||
})
|
||||
|
||||
// Asynchronously passes messages from the network to the consensus engine
|
||||
handler := &handler.Handler{}
|
||||
handler.Initialize(&engine, msgChan, 1000)
|
||||
|
||||
// Allow incoming messages to be routed to the new chain
|
||||
router.AddChain(handler)
|
||||
go ctx.Log.RecoverAndPanic(handler.Dispatch)
|
||||
|
||||
reqID := new(uint32)
|
||||
externalSender.GetAcceptedFrontierF = func(_ ids.ShortSet, _ ids.ID, requestID uint32) {
|
||||
*reqID = requestID
|
||||
}
|
||||
|
||||
engine.Startup()
|
||||
|
||||
externalSender.GetAcceptedFrontierF = nil
|
||||
externalSender.GetAcceptedF = func(_ ids.ShortSet, _ ids.ID, requestID uint32, _ ids.Set) {
|
||||
*reqID = requestID
|
||||
}
|
||||
|
||||
frontier := ids.Set{}
|
||||
frontier.Add(advanceTimeBlkID)
|
||||
engine.AcceptedFrontier(ctx.NodeID, *reqID, frontier)
|
||||
|
||||
externalSender.GetAcceptedF = nil
|
||||
externalSender.GetF = func(_ ids.ShortID, _ ids.ID, requestID uint32, containerID ids.ID) {
|
||||
*reqID = requestID
|
||||
if !containerID.Equals(advanceTimeBlkID) {
|
||||
t.Fatalf("wrong block requested")
|
||||
}
|
||||
}
|
||||
|
||||
engine.Accepted(ctx.NodeID, *reqID, frontier)
|
||||
|
||||
externalSender.GetF = nil
|
||||
externalSender.CantPushQuery = false
|
||||
|
||||
engine.Put(ctx.NodeID, *reqID, advanceTimeBlkID, advanceTimeBlkBytes)
|
||||
|
||||
externalSender.CantPushQuery = true
|
||||
|
||||
if pref := vm.Preferred(); !pref.Equals(advanceTimePreference.ID()) {
|
||||
t.Fatalf("wrong preference reported after bootstrapping to proposal block\nPreferred: %s\nExpected: %s\nGenesis: %s",
|
||||
pref,
|
||||
advanceTimePreference.ID(),
|
||||
genesisID)
|
||||
}
|
||||
ctx.Lock.Unlock()
|
||||
|
||||
router.Shutdown()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue