diff --git a/chain/dev/config.toml b/chain/dev/config.toml index c8f686d79a..dc2abc035f 100644 --- a/chain/dev/config.toml +++ b/chain/dev/config.toml @@ -24,6 +24,7 @@ unlock = "" roles = 4 babe-authority = true grandpa-authority = true +babe-lead = true [network] port = 7001 diff --git a/chain/gssmr/config.toml b/chain/gssmr/config.toml index 532a14e565..3f12e89ac5 100644 --- a/chain/gssmr/config.toml +++ b/chain/gssmr/config.toml @@ -30,6 +30,7 @@ port = 7001 nobootstrap = false nomdns = false discovery-interval = 10 +min-peers = 1 [rpc] enabled = false diff --git a/chain/gssmr/defaults.go b/chain/gssmr/defaults.go index cee187b338..910891c4bb 100644 --- a/chain/gssmr/defaults.go +++ b/chain/gssmr/defaults.go @@ -81,6 +81,8 @@ var ( DefaultNoBootstrap = false // DefaultNoMDNS disables mDNS discovery DefaultNoMDNS = false + // DefaultMinPeers is the default minimum desired peer count + DefaultMinPeers = 1 // DefaultDiscoveryInterval is the default interval for searching for DHT peers DefaultDiscoveryInterval = time.Second * 10 diff --git a/cmd/gossamer/config.go b/cmd/gossamer/config.go index 647ffade5c..0f287244ce 100644 --- a/cmd/gossamer/config.go +++ b/cmd/gossamer/config.go @@ -555,6 +555,7 @@ func setDotCoreConfig(ctx *cli.Context, tomlCfg ctoml.CoreConfig, cfg *dot.CoreC cfg.Roles = tomlCfg.Roles cfg.BabeAuthority = tomlCfg.Roles == types.AuthorityRole cfg.GrandpaAuthority = tomlCfg.Roles == types.AuthorityRole + cfg.BABELead = ctx.GlobalBool(BABELeadFlag.Name) // check --roles flag and update node configuration if roles := ctx.GlobalString(RolesFlag.Name); roles != "" { diff --git a/cmd/gossamer/config_test.go b/cmd/gossamer/config_test.go index 010aeee3c9..a26cd9dc4e 100644 --- a/cmd/gossamer/config_test.go +++ b/cmd/gossamer/config_test.go @@ -390,6 +390,7 @@ func TestNetworkConfigFromFlags(t *testing.T) { NoBootstrap: testCfg.Network.NoBootstrap, NoMDNS: testCfg.Network.NoMDNS, DiscoveryInterval: time.Second * 10, + MinPeers: testCfg.Network.MinPeers, }, }, { @@ -403,6 +404,7 @@ func TestNetworkConfigFromFlags(t *testing.T) { NoBootstrap: testCfg.Network.NoBootstrap, NoMDNS: testCfg.Network.NoMDNS, DiscoveryInterval: time.Second * 10, + MinPeers: testCfg.Network.MinPeers, }, }, { @@ -416,6 +418,7 @@ func TestNetworkConfigFromFlags(t *testing.T) { NoBootstrap: testCfg.Network.NoBootstrap, NoMDNS: testCfg.Network.NoMDNS, DiscoveryInterval: time.Second * 10, + MinPeers: testCfg.Network.MinPeers, }, }, { @@ -429,6 +432,7 @@ func TestNetworkConfigFromFlags(t *testing.T) { NoBootstrap: true, NoMDNS: testCfg.Network.NoMDNS, DiscoveryInterval: time.Second * 10, + MinPeers: testCfg.Network.MinPeers, }, }, { @@ -442,6 +446,7 @@ func TestNetworkConfigFromFlags(t *testing.T) { NoBootstrap: testCfg.Network.NoBootstrap, NoMDNS: true, DiscoveryInterval: time.Second * 10, + MinPeers: testCfg.Network.MinPeers, }, }, } @@ -816,6 +821,7 @@ func TestUpdateConfigFromGenesisData(t *testing.T) { NoBootstrap: testCfg.Network.NoBootstrap, NoMDNS: testCfg.Network.NoMDNS, DiscoveryInterval: testCfg.Network.DiscoveryInterval, + MinPeers: testCfg.Network.MinPeers, }, RPC: testCfg.RPC, System: testCfg.System, diff --git a/cmd/gossamer/export.go b/cmd/gossamer/export.go index 6d8fbe3a3a..9724bd6c37 100644 --- a/cmd/gossamer/export.go +++ b/cmd/gossamer/export.go @@ -122,6 +122,8 @@ func dotConfigToToml(dcfg *dot.Config) *ctoml.Config { NoBootstrap: dcfg.Network.NoBootstrap, NoMDNS: dcfg.Network.NoMDNS, DiscoveryInterval: int(dcfg.Network.DiscoveryInterval / time.Second), + MinPeers: dcfg.Network.MinPeers, + MaxPeers: dcfg.Network.MaxPeers, } cfg.RPC = ctoml.RPCConfig{ diff --git a/cmd/gossamer/export_test.go b/cmd/gossamer/export_test.go index 4b999e473d..6414ccf9dd 100644 --- a/cmd/gossamer/export_test.go +++ b/cmd/gossamer/export_test.go @@ -87,6 +87,7 @@ func TestExportCommand(t *testing.T) { NoBootstrap: testCfg.Network.NoBootstrap, NoMDNS: testCfg.Network.NoMDNS, DiscoveryInterval: testCfg.Network.DiscoveryInterval, + MinPeers: testCfg.Network.MinPeers, }, RPC: testCfg.RPC, }, @@ -119,6 +120,7 @@ func TestExportCommand(t *testing.T) { NoBootstrap: testCfg.Network.NoBootstrap, NoMDNS: testCfg.Network.NoMDNS, DiscoveryInterval: testCfg.Network.DiscoveryInterval, + MinPeers: testCfg.Network.MinPeers, }, RPC: testCfg.RPC, }, @@ -151,6 +153,7 @@ func TestExportCommand(t *testing.T) { NoBootstrap: testCfg.Network.NoBootstrap, NoMDNS: testCfg.Network.NoMDNS, DiscoveryInterval: testCfg.Network.DiscoveryInterval, + MinPeers: testCfg.Network.MinPeers, }, RPC: testCfg.RPC, }, diff --git a/cmd/gossamer/flags.go b/cmd/gossamer/flags.go index 370cab4cbc..a8eb71666a 100644 --- a/cmd/gossamer/flags.go +++ b/cmd/gossamer/flags.go @@ -316,6 +316,14 @@ var ( } ) +// BABE flags +var ( + BABELeadFlag = cli.BoolFlag{ + Name: "babe-lead", + Usage: `specify whether node should build block 1 of the network. only used when starting a new network`, + } +) + // flag sets that are shared by multiple commands var ( // GlobalFlags are flags that are valid for use with the root command and all subcommands @@ -366,6 +374,9 @@ var ( // telemetry flags NoTelemetryFlag, + + // BABE flags + BABELeadFlag, } ) diff --git a/dot/config.go b/dot/config.go index 0a5f2462dc..2473ff9cba 100644 --- a/dot/config.go +++ b/dot/config.go @@ -98,6 +98,7 @@ type NetworkConfig struct { type CoreConfig struct { Roles byte BabeAuthority bool + BABELead bool GrandpaAuthority bool WasmInterpreter string } @@ -183,6 +184,7 @@ func GssmrConfig() *Config { NoBootstrap: gssmr.DefaultNoBootstrap, NoMDNS: gssmr.DefaultNoMDNS, DiscoveryInterval: gssmr.DefaultDiscoveryInterval, + MinPeers: gssmr.DefaultMinPeers, }, RPC: RPCConfig{ Port: gssmr.DefaultRPCHTTPPort, diff --git a/dot/config/toml/config.go b/dot/config/toml/config.go index 3a68175945..ed4656ec61 100644 --- a/dot/config/toml/config.go +++ b/dot/config/toml/config.go @@ -82,6 +82,7 @@ type CoreConfig struct { SlotDuration uint64 `toml:"slot-duration,omitempty"` EpochLength uint64 `toml:"epoch-length,omitempty"` WasmInterpreter string `toml:"wasm-interpreter,omitempty"` + BABELead bool `toml:"babe-lead,omitempty"` } // RPCConfig is to marshal/unmarshal toml RPC config vars diff --git a/dot/core/service.go b/dot/core/service.go index c0abf48c80..2705a4f251 100644 --- a/dot/core/service.go +++ b/dot/core/service.go @@ -248,12 +248,6 @@ func (s *Service) handleBlock(block *types.Block, state *rtstorage.TrieState) er return err } - // check if block production epoch transitioned - if err := s.handleCurrentSlot(&block.Header); err != nil { - logger.Warn("failed to handle epoch for block", "block", block.Header.Hash(), "error", err) - return err - } - go func() { s.Lock() defer s.Unlock() @@ -313,29 +307,6 @@ func (s *Service) handleCodeSubstitution(hash common.Hash, state *rtstorage.Trie return nil } -func (s *Service) handleCurrentSlot(header *types.Header) error { - head := s.blockState.BestBlockHash() - if header.Hash() != head { - return nil - } - - epoch, err := s.epochState.GetEpochForBlock(header) - if err != nil { - return err - } - - currEpoch, err := s.epochState.GetCurrentEpoch() - if err != nil { - return err - } - - if currEpoch == epoch { - return nil - } - - return s.epochState.SetCurrentEpoch(epoch) -} - // handleBlocksAsync handles a block asynchronously; the handling performed by this function // does not need to be completed before the next block can be imported. func (s *Service) handleBlocksAsync() { @@ -399,7 +370,7 @@ func (s *Service) handleChainReorg(prev, curr common.Hash) error { } for _, ext := range *body { - logger.Info("validating transaction on re-org chain", "extrinsic", ext) + logger.Trace("validating transaction on re-org chain", "extrinsic", ext) encExt, err := scale.Marshal(ext) if err != nil { return err diff --git a/dot/node.go b/dot/node.go index a8e3118ad7..6b30f4784c 100644 --- a/dot/node.go +++ b/dot/node.go @@ -282,12 +282,6 @@ func NewNode(cfg *Config, ks *keystore.GlobalKeystore, stopFunc func()) (*Node, } nodeSrvcs = append(nodeSrvcs, coreSrvc) - bp, err := createBABEService(cfg, stateSrvc, ks.Babe, coreSrvc) - if err != nil { - return nil, err - } - nodeSrvcs = append(nodeSrvcs, bp) - fg, err := createGRANDPAService(cfg, stateSrvc, dh, ks.Gran, networkSrvc) if err != nil { return nil, err @@ -305,6 +299,12 @@ func NewNode(cfg *Config, ks *keystore.GlobalKeystore, stopFunc func()) (*Node, } nodeSrvcs = append(nodeSrvcs, syncer) + bp, err := createBABEService(cfg, stateSrvc, ks.Babe, coreSrvc) + if err != nil { + return nil, err + } + nodeSrvcs = append(nodeSrvcs, bp) + sysSrvc, err := createSystemService(&cfg.System, stateSrvc) if err != nil { return nil, fmt.Errorf("failed to create system service: %s", err) diff --git a/dot/services.go b/dot/services.go index 0af544837f..4e124e5822 100644 --- a/dot/services.go +++ b/dot/services.go @@ -187,6 +187,7 @@ func createBABEService(cfg *Config, st *state.Service, ks keystore.Keystore, cs BlockImportHandler: cs, Authority: cfg.Core.BabeAuthority, IsDev: cfg.Global.ID == "dev", + Lead: cfg.Core.BABELead, } if cfg.Core.BabeAuthority { diff --git a/lib/babe/babe.go b/lib/babe/babe.go index 4a4171d095..c0e13592e7 100644 --- a/lib/babe/babe.go +++ b/lib/babe/babe.go @@ -28,13 +28,13 @@ import ( "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/crypto/sr25519" "github.com/ChainSafe/gossamer/lib/runtime" + log "github.com/ChainSafe/log15" ethmetrics "github.com/ethereum/go-ethereum/metrics" ) var ( - logger log.Logger - initialWaitTime time.Duration + logger log.Logger ) // Service contains the VRF keys for the validator, as well as BABE configuation data @@ -43,6 +43,10 @@ type Service struct { cancel context.CancelFunc authority bool dev bool + // lead is used when setting up a new network from genesis. + // the "lead" node is the node that is designated to build block 1, after which the rest of the nodes + // will sync block 1 and determine the first slot of the network based on it + lead bool // Storage interfaces blockState BlockState @@ -79,6 +83,7 @@ type ServiceConfig struct { AuthData []types.Authority IsDev bool Authority bool + Lead bool } // NewService returns a new Babe Service using the provided VRF keys and runtime @@ -119,6 +124,7 @@ func NewService(cfg *ServiceConfig) (*Service, error) { authority: cfg.Authority, dev: cfg.IsDev, blockImportHandler: cfg.BlockImportHandler, + lead: cfg.Lead, } epoch, err := cfg.EpochState.GetCurrentEpoch() @@ -126,13 +132,10 @@ func NewService(cfg *ServiceConfig) (*Service, error) { return nil, err } - err = babeService.setupParameters(cfg) - if err != nil { + if err = babeService.setupParameters(cfg); err != nil { return nil, err } - initialWaitTime = babeService.slotDuration * 5 - logger.Debug("created service", "epoch", epoch, "block producer", cfg.Authority, @@ -143,6 +146,11 @@ func NewService(cfg *ServiceConfig) (*Service, error) { "threshold", babeService.epochData.threshold, "randomness", babeService.epochData.randomness, ) + + if cfg.Lead { + logger.Debug("node designated to build block 1") + } + return babeService, nil } @@ -191,13 +199,51 @@ func (b *Service) Start() error { return nil } - // wait a bit to check if we need to sync before initiating - <-time.NewTimer(initialWaitTime).C + // if we aren't leading node, wait for first block + if !b.lead { + if err := b.waitForFirstBlock(); err != nil { + return err + } + } go b.initiate() return nil } +func (b *Service) waitForFirstBlock() error { + ch := b.blockState.GetImportedBlockNotifierChannel() + defer b.blockState.FreeImportedBlockNotifierChannel(ch) + + const firstBlockTimeout = time.Minute + timer := time.NewTimer(firstBlockTimeout) + cleanup := func() { + if !timer.Stop() { + <-timer.C + } + } + + // loop until block 1 + for { + select { + case block, ok := <-ch: + if !ok { + cleanup() + return errChannelClosed + } + + if ok && block.Header.Number.Int64() > 0 { + cleanup() + return nil + } + case <-timer.C: + return errFirstBlockTimeout + case <-b.ctx.Done(): + cleanup() + return b.ctx.Err() + } + } +} + // SlotDuration returns the current service slot duration in milliseconds func (b *Service) SlotDuration() uint64 { return uint64(b.slotDuration.Milliseconds()) @@ -327,6 +373,12 @@ func (b *Service) invokeBlockAuthoring() error { return err } + logger.Debug("initiated epoch", + "threshold", b.epochData.threshold, + "randomness", b.epochData.randomness, + "authorities", b.epochData.authorities, + ) + epochStartSlot, err := b.waitForEpochStart(epoch) if err != nil { logger.Error("failed to wait for epoch start", "epoch", epoch, "error", err) @@ -355,16 +407,35 @@ func (b *Service) invokeBlockAuthoring() error { logger.Info("current epoch", "epoch", epoch, "slots into epoch", intoEpoch) + // get start slot for current epoch + nextEpochStart, err := b.epochState.GetStartSlotForEpoch(epoch + 1) + if err != nil { + logger.Error("failed to get start slot for next epoch", "epoch", epoch, "error", err) + return err + } + + nextEpochStartTime := getSlotStartTime(nextEpochStart, b.slotDuration) + epochTimer := time.NewTimer(time.Until(nextEpochStartTime)) + cleanup := func() { + if !epochTimer.Stop() { + <-epochTimer.C + } + } + slotDone := make([]<-chan time.Time, b.epochLength-intoEpoch) for i := 0; i < int(b.epochLength-intoEpoch); i++ { slotDone[i] = time.After(b.getSlotDuration() * time.Duration(i)) } for i := 0; i < int(b.epochLength-intoEpoch); i++ { + done := false + select { case <-b.ctx.Done(): + cleanup() return nil case <-b.pause: + cleanup() return nil case <-slotDone[i]: slotNum := startSlot + uint64(i) @@ -380,6 +451,12 @@ func (b *Service) invokeBlockAuthoring() error { logger.Warn("failed to handle slot", "slot", slotNum, "error", err) continue } + case <-epochTimer.C: + done = true + } + + if done { + break } } @@ -489,7 +566,7 @@ func (b *Service) handleSlot(epoch, slotNum uint64) error { "epoch", epoch, "slot", slotNum, ) - logger.Debug("built block", + logger.Trace("built block", "header", block.Header, "body", block.Body, "parent", parent.Hash(), diff --git a/lib/babe/babe_test.go b/lib/babe/babe_test.go index 751c2bd395..9ab650638f 100644 --- a/lib/babe/babe_test.go +++ b/lib/babe/babe_test.go @@ -323,6 +323,7 @@ func TestService_SlotDuration(t *testing.T) { func TestService_ProducesBlocks(t *testing.T) { babeService := createTestService(t, nil) + babeService.lead = true babeService.epochData.authorityIndex = 0 babeService.epochData.authorities = []types.Authority{ diff --git a/lib/babe/epoch.go b/lib/babe/epoch.go index 4c311aa09c..19dc994e27 100644 --- a/lib/babe/epoch.go +++ b/lib/babe/epoch.go @@ -83,7 +83,7 @@ func (b *Service) initiateEpoch(epoch uint64) error { randomness: data.Randomness, authorities: data.Authorities, authorityIndex: idx, - threshold: b.epochData.threshold, + threshold: b.epochData.threshold, // TODO: threshold might change if authority count changes } } diff --git a/lib/babe/errors.go b/lib/babe/errors.go index 4c63cffa5f..d78a136e39 100644 --- a/lib/babe/errors.go +++ b/lib/babe/errors.go @@ -59,6 +59,8 @@ var ( errNilEpochState = errors.New("cannot have nil EpochState") errInvalidResult = errors.New("invalid error value") errNoEpochData = errors.New("no epoch data found for upcoming epoch") + errFirstBlockTimeout = errors.New("timed out waiting for first block") + errChannelClosed = errors.New("block notifier channel was closed") other Other invalidCustom InvalidCustom diff --git a/lib/babe/state.go b/lib/babe/state.go index 6008ff25bf..386f5bc758 100644 --- a/lib/babe/state.go +++ b/lib/babe/state.go @@ -48,6 +48,13 @@ type BlockState interface { NumberIsFinalised(num *big.Int) (bool, error) GetRuntime(*common.Hash) (runtime.Instance, error) StoreRuntime(common.Hash, runtime.Instance) + ImportedBlockNotifierManager +} + +// ImportedBlockNotifierManager is the interface for block notification channels +type ImportedBlockNotifierManager interface { + GetImportedBlockNotifierChannel() chan *types.Block + FreeImportedBlockNotifierChannel(ch chan *types.Block) } // StorageState interface for storage state methods diff --git a/tests/rpc/rpc_03-chain_test.go b/tests/rpc/rpc_03-chain_test.go index 10e6040654..28dc8852ee 100644 --- a/tests/rpc/rpc_03-chain_test.go +++ b/tests/rpc/rpc_03-chain_test.go @@ -75,7 +75,7 @@ func TestChainRPC(t *testing.T) { nodes, err := utils.InitializeAndStartNodes(t, 1, utils.GenesisDev, utils.ConfigDefault) require.Nil(t, err) - time.Sleep(time.Second) // give server a second to start + time.Sleep(time.Second * 5) // give server a few seconds to start chainBlockHeaderHash := "" for _, test := range testCases { diff --git a/tests/stress/grandpa_test.go b/tests/stress/grandpa_test.go index c06f5e83dd..79e2461d52 100644 --- a/tests/stress/grandpa_test.go +++ b/tests/stress/grandpa_test.go @@ -135,7 +135,7 @@ func TestStress_Grandpa_CatchUp(t *testing.T) { time.Sleep(time.Second * 70) // let some rounds run //nolint - node, err := utils.RunGossamer(t, numNodes-1, utils.TestDir(t, utils.KeyList[numNodes-1]), utils.GenesisSixAuths, utils.ConfigDefault, false) + node, err := utils.RunGossamer(t, numNodes-1, utils.TestDir(t, utils.KeyList[numNodes-1]), utils.GenesisSixAuths, utils.ConfigDefault, false, false) require.NoError(t, err) nodes = append(nodes, node) diff --git a/tests/stress/stress_test.go b/tests/stress/stress_test.go index 3a66367fc0..aa04cbaff4 100644 --- a/tests/stress/stress_test.go +++ b/tests/stress/stress_test.go @@ -102,7 +102,7 @@ func TestSync_SingleBlockProducer(t *testing.T) { // start block producing node first //nolint - node, err := utils.RunGossamer(t, numNodes-1, utils.TestDir(t, utils.KeyList[numNodes-1]), utils.GenesisDev, utils.ConfigNoGrandpa, false) + node, err := utils.RunGossamer(t, numNodes-1, utils.TestDir(t, utils.KeyList[numNodes-1]), utils.GenesisDev, utils.ConfigNoGrandpa, false, true) require.NoError(t, err) // wait and start rest of nodes - if they all start at the same time the first round usually doesn't complete since @@ -188,12 +188,12 @@ func TestSync_SingleSyncingNode(t *testing.T) { utils.SetLogLevel(log.LvlInfo) // start block producing node - alice, err := utils.RunGossamer(t, 0, utils.TestDir(t, utils.KeyList[0]), utils.GenesisDev, utils.ConfigDefault, false) + alice, err := utils.RunGossamer(t, 0, utils.TestDir(t, utils.KeyList[0]), utils.GenesisDev, utils.ConfigDefault, false, true) require.NoError(t, err) time.Sleep(time.Second * 15) // start syncing node - bob, err := utils.RunGossamer(t, 1, utils.TestDir(t, utils.KeyList[1]), utils.GenesisDev, utils.ConfigNoBABE, false) + bob, err := utils.RunGossamer(t, 1, utils.TestDir(t, utils.KeyList[1]), utils.GenesisDev, utils.ConfigNoBABE, false, false) require.NoError(t, err) nodes := []*utils.Node{alice, bob} @@ -215,7 +215,7 @@ func TestSync_Bench(t *testing.T) { numBlocks := 64 // start block producing node - alice, err := utils.RunGossamer(t, 0, utils.TestDir(t, utils.KeyList[1]), utils.GenesisDev, utils.ConfigNoGrandpa, false) + alice, err := utils.RunGossamer(t, 0, utils.TestDir(t, utils.KeyList[1]), utils.GenesisDev, utils.ConfigNoGrandpa, false, true) require.NoError(t, err) for { @@ -236,7 +236,7 @@ func TestSync_Bench(t *testing.T) { t.Log("BABE paused") // start syncing node - bob, err := utils.RunGossamer(t, 1, utils.TestDir(t, utils.KeyList[0]), utils.GenesisDev, utils.ConfigNotAuthority, false) + bob, err := utils.RunGossamer(t, 1, utils.TestDir(t, utils.KeyList[0]), utils.GenesisDev, utils.ConfigNotAuthority, false, true) require.NoError(t, err) nodes := []*utils.Node{alice, bob} @@ -290,7 +290,7 @@ func TestSync_Restart(t *testing.T) { // start block producing node first //nolint - node, err := utils.RunGossamer(t, numNodes-1, utils.TestDir(t, utils.KeyList[numNodes-1]), utils.GenesisDefault, utils.ConfigDefault, false) + node, err := utils.RunGossamer(t, numNodes-1, utils.TestDir(t, utils.KeyList[numNodes-1]), utils.GenesisDefault, utils.ConfigDefault, false, true) require.NoError(t, err) // wait and start rest of nodes @@ -343,15 +343,15 @@ func TestSync_SubmitExtrinsic(t *testing.T) { idx := 0 // TODO: randomise this // start block producing node first - node, err := utils.RunGossamer(t, 0, utils.TestDir(t, utils.KeyList[0]), utils.GenesisDev, utils.ConfigNoGrandpa, false) + node, err := utils.RunGossamer(t, 0, utils.TestDir(t, utils.KeyList[0]), utils.GenesisDev, utils.ConfigNoGrandpa, false, true) require.NoError(t, err) nodes := []*utils.Node{node} // Start rest of nodes - node, err = utils.RunGossamer(t, 1, utils.TestDir(t, utils.KeyList[1]), utils.GenesisDev, utils.ConfigNotAuthority, false) + node, err = utils.RunGossamer(t, 1, utils.TestDir(t, utils.KeyList[1]), utils.GenesisDev, utils.ConfigNotAuthority, false, false) require.NoError(t, err) nodes = append(nodes, node) - node, err = utils.RunGossamer(t, 2, utils.TestDir(t, utils.KeyList[2]), utils.GenesisDev, utils.ConfigNotAuthority, false) + node, err = utils.RunGossamer(t, 2, utils.TestDir(t, utils.KeyList[2]), utils.GenesisDev, utils.ConfigNotAuthority, false, false) require.NoError(t, err) nodes = append(nodes, node) diff --git a/tests/utils/gossamer_utils.go b/tests/utils/gossamer_utils.go index 69c130a54c..44adcb1b19 100644 --- a/tests/utils/gossamer_utils.go +++ b/tests/utils/gossamer_utils.go @@ -91,6 +91,7 @@ type Node struct { basePath string config string WSPort string + BABELead bool } // InitGossamer initialises given node number and returns node reference @@ -132,6 +133,10 @@ func StartGossamer(t *testing.T, node *Node, websocket bool) error { "--rpc", "--log", "info"} + if node.BABELead { + params = append(params, "--babe-lead") + } + if node.Idx >= len(KeyList) { params = append(params, "--roles", "1") } else { @@ -215,13 +220,17 @@ func StartGossamer(t *testing.T, node *Node, websocket bool) error { } // RunGossamer will initialise and start a gossamer instance -func RunGossamer(t *testing.T, idx int, basepath, genesis, config string, websocket bool) (*Node, error) { +func RunGossamer(t *testing.T, idx int, basepath, genesis, config string, websocket, babeLead bool) (*Node, error) { node, err := InitGossamer(idx, basepath, genesis, config) if err != nil { logger.Crit("could not initialise gossamer", "error", err) os.Exit(1) } + if idx == 0 || babeLead { + node.BABELead = true + } + err = StartGossamer(t, node, websocket) if err != nil { logger.Crit("could not start gossamer", "error", err) @@ -307,7 +316,7 @@ func InitializeAndStartNodes(t *testing.T, num int, genesis, config string) ([]* if i < len(KeyList) { name = KeyList[i] } - node, err := RunGossamer(t, i, TestDir(t, name), genesis, config, false) + node, err := RunGossamer(t, i, TestDir(t, name), genesis, config, false, false) if err != nil { logger.Error("failed to run gossamer", "i", i) } @@ -337,7 +346,7 @@ func InitializeAndStartNodesWebsocket(t *testing.T, num int, genesis, config str if i < len(KeyList) { name = KeyList[i] } - node, err := RunGossamer(t, i, TestDir(t, name), genesis, config, true) + node, err := RunGossamer(t, i, TestDir(t, name), genesis, config, true, false) if err != nil { logger.Error("failed to run gossamer", "i", i) } @@ -501,6 +510,7 @@ func CreateConfigNoBabe() { func generateConfigNoGrandpa() *ctoml.Config { cfg := generateDefaultConfig() cfg.Core.GrandpaAuthority = false + cfg.Core.BABELead = true return cfg }