diff options
39 files changed, 483 insertions, 706 deletions
diff --git a/common/event.go b/common/event.go index 6c6bf49..4e4e23b 100644 --- a/common/event.go +++ b/common/event.go @@ -20,26 +20,25 @@ package common import ( "container/heap" "sync" - "time" ) -type timeEventFn func(time.Time) +type heightEventFn func(uint64) -type timeEvent struct { - t time.Time - fn timeEventFn +type heightEvent struct { + h uint64 + fn heightEventFn } -// timeEvents implements a Min-Heap structure. -type timeEvents []timeEvent +// heightEvents implements a Min-Heap structure. +type heightEvents []heightEvent -func (h timeEvents) Len() int { return len(h) } -func (h timeEvents) Less(i, j int) bool { return h[i].t.Before(h[j].t) } -func (h timeEvents) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h *timeEvents) Push(x interface{}) { - *h = append(*h, x.(timeEvent)) +func (h heightEvents) Len() int { return len(h) } +func (h heightEvents) Less(i, j int) bool { return h[i].h < h[j].h } +func (h heightEvents) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *heightEvents) Push(x interface{}) { + *h = append(*h, x.(heightEvent)) } -func (h *timeEvents) Pop() interface{} { +func (h *heightEvents) Pop() interface{} { old := *h n := len(old) x := old[n-1] @@ -49,54 +48,54 @@ func (h *timeEvents) Pop() interface{} { // Event implements the Observer pattern. type Event struct { - timeEvents timeEvents - timeEventsLock sync.Mutex + heightEvents heightEvents + heightEventsLock sync.Mutex } // NewEvent creates a new event instance. func NewEvent() *Event { - te := timeEvents{} - heap.Init(&te) + he := heightEvents{} + heap.Init(&he) return &Event{ - timeEvents: te, + heightEvents: he, } } -// RegisterTime to get notified on and after specific time. -func (e *Event) RegisterTime(t time.Time, fn timeEventFn) { - e.timeEventsLock.Lock() - defer e.timeEventsLock.Unlock() - heap.Push(&e.timeEvents, timeEvent{ - t: t, +// RegisterHeight to get notified on a specific height. +func (e *Event) RegisterHeight(h uint64, fn heightEventFn) { + e.heightEventsLock.Lock() + defer e.heightEventsLock.Unlock() + heap.Push(&e.heightEvents, heightEvent{ + h: h, fn: fn, }) } -// NotifyTime and trigger function callback. -func (e *Event) NotifyTime(t time.Time) { - fns := func() (fns []timeEventFn) { - e.timeEventsLock.Lock() - defer e.timeEventsLock.Unlock() - if len(e.timeEvents) == 0 { +// NotifyHeight and trigger function callback. +func (e *Event) NotifyHeight(h uint64) { + fns := func() (fns []heightEventFn) { + e.heightEventsLock.Lock() + defer e.heightEventsLock.Unlock() + if len(e.heightEvents) == 0 { return } - for !t.Before(e.timeEvents[0].t) { - te := heap.Pop(&e.timeEvents).(timeEvent) - fns = append(fns, te.fn) - if len(e.timeEvents) == 0 { + for h >= e.heightEvents[0].h { + he := heap.Pop(&e.heightEvents).(heightEvent) + fns = append(fns, he.fn) + if len(e.heightEvents) == 0 { return } } return }() for _, fn := range fns { - fn(t) + fn(h) } } // Reset clears all pending event func (e *Event) Reset() { - e.timeEventsLock.Lock() - defer e.timeEventsLock.Unlock() - e.timeEvents = timeEvents{} + e.heightEventsLock.Lock() + defer e.heightEventsLock.Unlock() + e.heightEvents = heightEvents{} } diff --git a/common/event_test.go b/common/event_test.go index f357972..86c4971 100644 --- a/common/event_test.go +++ b/common/event_test.go @@ -20,7 +20,6 @@ package common import ( "math/rand" "testing" - "time" "github.com/stretchr/testify/suite" ) @@ -29,37 +28,35 @@ type EventTestSuite struct { suite.Suite } -func (s *EventTestSuite) TestTimeEvent() { +func (s *EventTestSuite) TestHeightEvent() { event := NewEvent() - now := time.Now() triggered := make(chan int, 100) - trigger := func(id int) func(t time.Time) { - return func(t time.Time) { + trigger := func(id int) func(uint64) { + return func(uint64) { triggered <- id } } - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.NotifyTime(now) + event.RegisterHeight(100, trigger(0)) + event.NotifyHeight(0) s.Len(triggered, 0) - event.NotifyTime(now.Add(150 * time.Millisecond)) + event.NotifyHeight(150) s.Len(triggered, 1) triggered = make(chan int, 100) - event.NotifyTime(now.Add(150 * time.Millisecond)) + event.NotifyHeight(150) s.Len(triggered, 0) - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.NotifyTime(now.Add(150 * time.Millisecond)) + event.RegisterHeight(100, trigger(0)) + event.RegisterHeight(100, trigger(0)) + event.RegisterHeight(100, trigger(0)) + event.RegisterHeight(100, trigger(0)) + event.NotifyHeight(150) s.Len(triggered, 4) triggered = make(chan int, 100) for i := 0; i < 10; i++ { - event.RegisterTime(now.Add(time.Duration(100+i*10)*time.Millisecond), - trigger(i)) + event.RegisterHeight(uint64(100+i*10), trigger(i)) } - event.NotifyTime(now.Add(130 * time.Millisecond)) + event.NotifyHeight(130) s.Require().Len(triggered, 4) for i := 0; i < 4; i++ { j := <-triggered @@ -76,10 +73,9 @@ func (s *EventTestSuite) TestTimeEvent() { nums[i], nums[j] = nums[j], nums[i] }) for _, i := range nums { - event.RegisterTime(now.Add(time.Duration(100+i*10)*time.Millisecond), - trigger(i)) + event.RegisterHeight(uint64(100+i*10), trigger(i)) } - event.NotifyTime(now.Add(130 * time.Millisecond)) + event.NotifyHeight(130) s.Require().Len(triggered, 4) for i := 0; i < 4; i++ { j := <-triggered @@ -89,20 +85,19 @@ func (s *EventTestSuite) TestTimeEvent() { func (s *EventTestSuite) TestReset() { event := NewEvent() - now := time.Now() triggered := make(chan int, 100) - trigger := func(id int) func(t time.Time) { - return func(t time.Time) { + trigger := func(id int) func(h uint64) { + return func(uint64) { triggered <- id } } - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) - event.RegisterTime(now.Add(100*time.Millisecond), trigger(0)) + event.RegisterHeight(100, trigger(0)) + event.RegisterHeight(100, trigger(0)) + event.RegisterHeight(100, trigger(0)) + event.RegisterHeight(100, trigger(0)) + event.RegisterHeight(100, trigger(0)) event.Reset() - event.NotifyTime(now.Add(150 * time.Millisecond)) + event.NotifyHeight(150) s.Len(triggered, 0) } diff --git a/core/agreement-mgr.go b/core/agreement-mgr.go index 5f5b9ae..88cc432 100644 --- a/core/agreement-mgr.go +++ b/core/agreement-mgr.go @@ -65,13 +65,29 @@ func genValidLeader( } type agreementMgrConfig struct { - beginTime time.Time - roundInterval time.Duration + roundBasedConfig + notarySetSize uint32 lambdaBA time.Duration crs common.Hash } +func (c *agreementMgrConfig) from( + round uint64, config *types.Config, crs common.Hash) { + c.notarySetSize = config.NotarySetSize + c.lambdaBA = config.LambdaBA + c.crs = crs + c.setupRoundBasedFields(round, config) +} + +func newAgreementMgrConfig(prev agreementMgrConfig, config *types.Config, + crs common.Hash) (c agreementMgrConfig) { + c = agreementMgrConfig{} + c.from(prev.roundID+1, config, crs) + c.setRoundBeginHeight(prev.roundEndHeight) + return +} + type baRoundSetting struct { notarySet map[types.NodeID]struct{} agr *agreement @@ -92,9 +108,8 @@ type agreementMgr struct { signer *utils.Signer bcModule *blockChain ctx context.Context - lastEndTime time.Time initRound uint64 - configs []*agreementMgrConfig + configs []agreementMgrConfig baModule *agreement processedBAResult map[types.Position]struct{} voteFilter *utils.VoteFilter @@ -104,8 +119,8 @@ type agreementMgr struct { } func newAgreementMgr(con *Consensus, initRound uint64, - initRoundBeginTime time.Time) *agreementMgr { - return &agreementMgr{ + initConfig agreementMgrConfig) (mgr *agreementMgr, err error) { + mgr = &agreementMgr{ con: con, ID: con.ID, app: con.app, @@ -117,9 +132,33 @@ func newAgreementMgr(con *Consensus, initRound uint64, bcModule: con.bcModule, ctx: con.ctx, initRound: initRound, - lastEndTime: initRoundBeginTime, processedBAResult: make(map[types.Position]struct{}, maxResultCache), + configs: []agreementMgrConfig{initConfig}, + voteFilter: utils.NewVoteFilter(), } + recv := &consensusBAReceiver{ + consensus: con, + restartNotary: make(chan types.Position, 1), + roundValue: &atomic.Value{}, + } + recv.roundValue.Store(uint64(0)) + agr := newAgreement( + mgr.ID, + recv, + newLeaderSelector(genValidLeader(mgr), mgr.logger), + mgr.signer, + mgr.logger) + // Hacky way to initialize first notarySet. + nodes, err := mgr.cache.GetNodeSet(initRound) + if err != nil { + return + } + agr.notarySet = nodes.GetSubSet( + int(initConfig.notarySetSize), types.NewNotarySetTarget(initConfig.crs)) + // Hacky way to make agreement module self contained. + recv.agreementModule = agr + mgr.baModule = agr + return } func (mgr *agreementMgr) run() { @@ -136,7 +175,7 @@ func (mgr *agreementMgr) run() { }() } -func (mgr *agreementMgr) getConfig(round uint64) *agreementMgrConfig { +func (mgr *agreementMgr) config(round uint64) *agreementMgrConfig { mgr.lock.RLock() defer mgr.lock.RUnlock() if round < mgr.initRound { @@ -146,7 +185,7 @@ func (mgr *agreementMgr) getConfig(round uint64) *agreementMgrConfig { if roundIndex >= uint64(len(mgr.configs)) { return nil } - return mgr.configs[roundIndex] + return &mgr.configs[roundIndex] } func (mgr *agreementMgr) appendConfig( @@ -156,52 +195,12 @@ func (mgr *agreementMgr) appendConfig( if round != uint64(len(mgr.configs))+mgr.initRound { return ErrRoundNotIncreasing } - newConfig := &agreementMgrConfig{ - beginTime: mgr.lastEndTime, - roundInterval: config.RoundInterval, - notarySetSize: config.NotarySetSize, - lambdaBA: config.LambdaBA, - crs: crs, - } - mgr.configs = append(mgr.configs, newConfig) - mgr.lastEndTime = mgr.lastEndTime.Add(config.RoundInterval) - // Prepare modules. - if mgr.baModule != nil { - return nil - } - recv := &consensusBAReceiver{ - consensus: mgr.con, - restartNotary: make(chan types.Position, 1), - roundValue: &atomic.Value{}, - } - recv.roundValue.Store(uint64(0)) - agrModule := newAgreement( - mgr.con.ID, - recv, - newLeaderSelector(genValidLeader(mgr), mgr.logger), - mgr.signer, - mgr.logger) - // Hacky way to initialize first notarySet. - nodes, err := mgr.cache.GetNodeSet(round) - if err != nil { - return err - } - agrModule.notarySet = nodes.GetSubSet( - int(config.NotarySetSize), types.NewNotarySetTarget(crs)) - // Hacky way to make agreement module self contained. - recv.agreementModule = agrModule - mgr.baModule = agrModule - mgr.voteFilter = utils.NewVoteFilter() + mgr.configs = append(mgr.configs, newAgreementMgrConfig( + mgr.configs[len(mgr.configs)-1], config, crs)) return nil } func (mgr *agreementMgr) processVote(v *types.Vote) (err error) { - if v.Position.ChainID > 0 { - mgr.logger.Error("Process vote for unknown chain to BA", - "position", v.Position, - "initRound", mgr.initRound) - return utils.ErrInvalidChainID - } if mgr.voteFilter.Filter(v) { return nil } @@ -212,13 +211,6 @@ func (mgr *agreementMgr) processVote(v *types.Vote) (err error) { } func (mgr *agreementMgr) processBlock(b *types.Block) error { - if b.Position.ChainID > 0 { - mgr.logger.Error("Process block for unknown chain to BA", - "position", b.Position, - "baRound", len(mgr.configs), - "initRound", mgr.initRound) - return utils.ErrInvalidChainID - } return mgr.baModule.processBlock(b) } @@ -247,13 +239,6 @@ func (mgr *agreementMgr) untouchAgreementResult( func (mgr *agreementMgr) processAgreementResult( result *types.AgreementResult) error { - if result.Position.ChainID > 0 { - mgr.logger.Error("Process unknown result for unknown chain to BA", - "position", result.Position, - "baRound", len(mgr.configs), - "initRound", mgr.initRound) - return utils.ErrInvalidChainID - } aID := mgr.baModule.agreementID() if isStop(aID) { return nil @@ -310,13 +295,12 @@ func (mgr *agreementMgr) runBA(initRound uint64) { var ( currentRound uint64 nextRound = initRound + curConfig = mgr.config(initRound) setting = baRoundSetting{ agr: mgr.baModule, recv: mgr.baModule.data.recv.(*consensusBAReceiver), } - roundBeginTime time.Time - roundEndTime time.Time - tickDuration time.Duration + tickDuration time.Duration ) // Check if this routine needs to awake in this round and prepare essential @@ -327,24 +311,20 @@ func (mgr *agreementMgr) runBA(initRound uint64) { nextRound++ }() // Wait until the configuartion for next round is ready. - var config *agreementMgrConfig for { - if config = mgr.getConfig(nextRound); config != nil { + if curConfig = mgr.config(nextRound); curConfig != nil { break } else { mgr.logger.Debug("round is not ready", "round", nextRound) time.Sleep(1 * time.Second) } } - // Set next checkpoint. - roundBeginTime = config.beginTime - roundEndTime = config.beginTime.Add(config.roundInterval) // Check if this node in notary set of this chain in this round. - notarySet, err := mgr.cache.GetNotarySet(nextRound, 0) + notarySet, err := mgr.cache.GetNotarySet(nextRound) if err != nil { panic(err) } - setting.crs = config.crs + setting.crs = curConfig.crs setting.notarySet = notarySet _, isNotary = setting.notarySet[mgr.ID] if isNotary { @@ -357,12 +337,12 @@ func (mgr *agreementMgr) runBA(initRound uint64) { "round", nextRound) } // Setup ticker - if tickDuration != config.lambdaBA { + if tickDuration != curConfig.lambdaBA { if setting.ticker != nil { setting.ticker.Stop() } setting.ticker = newTicker(mgr.gov, nextRound, TickerBA) - tickDuration = config.lambdaBA + tickDuration = curConfig.lambdaBA } return } @@ -373,29 +353,13 @@ Loop: break Loop default: } - now := time.Now().UTC() setting.recv.isNotary = checkRound() - // Sleep until round begin. Here a biased round begin time would be - // used instead of the one in config. The reason it to disperse the load - // of fullnodes to verify confirmed blocks from each chain. - if now.Before(pickBiasedTime(roundBeginTime, 4*tickDuration)) { - select { - case <-mgr.ctx.Done(): - break Loop - case <-time.After(roundBeginTime.Sub(now)): - } - // Clean the tick channel after awake: the tick would be queued in - // channel, thus the first few ticks would not tick on expected - // interval. - <-setting.ticker.Tick() - <-setting.ticker.Tick() - } // Run BA for this round. setting.recv.roundValue.Store(currentRound) - setting.recv.changeNotaryTime = roundEndTime + setting.recv.changeNotaryHeight = curConfig.roundEndHeight setting.recv.restartNotary <- types.Position{ - Round: setting.recv.round(), - ChainID: math.MaxUint32, + Round: setting.recv.round(), + Height: math.MaxUint64, } mgr.voteFilter = utils.NewVoteFilter() if err := mgr.baRoutineForOneRound(&setting); err != nil { @@ -450,7 +414,7 @@ func (mgr *agreementMgr) baRoutineForOneRound( if isStop(oldPos) && nextHeight == 0 { break } - if isStop(restartPos) && nextHeight == 0 { + if isStop(restartPos) { break } if nextHeight > restartPos.Height { diff --git a/core/agreement.go b/core/agreement.go index 579cea8..43fddd0 100644 --- a/core/agreement.go +++ b/core/agreement.go @@ -254,12 +254,12 @@ func (a *agreement) restart( func (a *agreement) stop() { a.restart(make(map[types.NodeID]struct{}), types.Position{ - ChainID: math.MaxUint32, + Height: math.MaxUint64, }, types.NodeID{}, common.Hash{}) } func isStop(aID types.Position) bool { - return aID.ChainID == math.MaxUint32 + return aID.Height == math.MaxUint64 } // clocks returns how many time this state is required. diff --git a/core/blockchain.go b/core/blockchain.go index d1aa644..001892e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -110,7 +110,7 @@ func newBlockChainConfig(prev blockChainConfig, config *types.Config) ( c blockChainConfig) { c = blockChainConfig{} c.fromConfig(prev.roundID+1, config) - c.setRoundBeginTime(prev.roundEndTime) + c.setRoundBeginHeight(prev.roundEndHeight) return } @@ -131,9 +131,10 @@ type blockChain struct { configs []blockChainConfig pendingBlocks pendingBlockRecords confirmedBlocks types.BlocksByPosition + dMoment time.Time } -func newBlockChain(nID types.NodeID, initBlock *types.Block, +func newBlockChain(nID types.NodeID, dMoment time.Time, initBlock *types.Block, initConfig blockChainConfig, app Application, vGetter tsigVerifierGetter, signer *utils.Signer, logger common.Logger) *blockChain { if initBlock != nil { @@ -156,6 +157,7 @@ func newBlockChain(nID types.NodeID, initBlock *types.Block, app: app, logger: logger, configs: []blockChainConfig{initConfig}, + dMoment: dMoment, pendingRandomnesses: make( map[types.Position]*types.BlockRandomnessResult), } @@ -203,9 +205,6 @@ func (bc *blockChain) extractBlocks() (ret []*types.Block) { } func (bc *blockChain) sanityCheck(b *types.Block) error { - if b.Position.ChainID != 0 { - panic(fmt.Errorf("attempt to process block from non-zero chainID")) - } if b.IsEmpty() { panic(fmt.Errorf("pass empty block to sanity check: %s", b)) } @@ -228,7 +227,7 @@ func (bc *blockChain) sanityCheck(b *types.Block) error { } return ErrInvalidBlockHeight } - tipConfig := bc.getTipConfig() + tipConfig := bc.tipConfig() if tipConfig.isLastBlock(bc.lastConfirmed) { if b.Position.Round != bc.lastConfirmed.Position.Round+1 { return ErrRoundNotSwitch @@ -250,9 +249,6 @@ func (bc *blockChain) sanityCheck(b *types.Block) error { // addEmptyBlock is called when an empty block is confirmed by BA. func (bc *blockChain) addEmptyBlock(position types.Position) ( *types.Block, error) { - if position.ChainID != 0 { - panic(fmt.Errorf("attempt to process block from non-zero chainID")) - } bc.lock.Lock() defer bc.lock.Unlock() add := func() *types.Block { @@ -286,9 +282,6 @@ func (bc *blockChain) addEmptyBlock(position types.Position) ( // addBlock should be called when the block is confirmed by BA, we won't perform // sanity check against this block, it's ok to add block with skipping height. func (bc *blockChain) addBlock(b *types.Block) error { - if b.Position.ChainID != 0 { - panic(fmt.Errorf("attempt to process block from non-zero chainID")) - } bc.lock.Lock() defer bc.lock.Unlock() confirmed := false @@ -314,9 +307,6 @@ func (bc *blockChain) addBlock(b *types.Block) error { } func (bc *blockChain) addRandomness(r *types.BlockRandomnessResult) error { - if r.Position.ChainID != 0 { - panic(fmt.Errorf("attempt to process block from non-zero chainID")) - } if func() bool { bc.lock.RLock() defer bc.lock.RUnlock() @@ -361,8 +351,8 @@ func (bc *blockChain) tipRound() uint64 { if bc.lastConfirmed == nil { return 0 } - offset := uint64(0) - if bc.lastConfirmed.Timestamp.After(bc.getTipConfig().roundEndTime) { + offset, tipConfig := uint64(0), bc.tipConfig() + if tipConfig.isLastBlock(bc.lastConfirmed) { offset++ } return bc.lastConfirmed.Position.Round + offset @@ -392,7 +382,7 @@ func (bc *blockChain) nextBlock() (uint64, time.Time) { // lastConfirmed block in the scenario of "nextBlock" method. tip, config := bc.lastConfirmed, bc.configs[0] if tip == nil { - return 0, config.roundBeginTime + return 0, bc.dMoment } return tip.Position.Height + 1, tip.Timestamp.Add(config.minBlockInterval) } @@ -528,26 +518,31 @@ func (bc *blockChain) prepareBlock(position types.Position, b = &types.Block{Position: position, Timestamp: proposeTime} tip := bc.lastConfirmed // Make sure we can propose a block at expected position for callers. - expectedPosition := types.Position{} if tip == nil { // The case for genesis block. - if !position.Equal(expectedPosition) { + if !position.Equal(types.Position{}) { b, err = nil, ErrNotGenesisBlock + return } else if empty { - b.Timestamp = bc.configs[0].roundBeginTime + b.Timestamp = bc.dMoment } } else { - expectedPosition.Height = tip.Position.Height + 1 - tipConfig := bc.getTipConfig() - if tipConfig.isLastBlock(tip) { - expectedPosition.Round = tip.Position.Round + 1 - } else { - expectedPosition.Round = tip.Position.Round - } - if !expectedPosition.Equal(position) { + tipConfig := bc.tipConfig() + if tip.Position.Height+1 != position.Height { b, err = nil, ErrNotFollowTipPosition return } + if tipConfig.isLastBlock(tip) { + if tip.Position.Round+1 != position.Round { + b, err = nil, ErrRoundNotSwitch + return + } + } else { + if tip.Position.Round != position.Round { + b, err = nil, ErrInvalidRoundID + return + } + } b.ParentHash = tip.Hash if !empty { bc.logger.Debug("Calling Application.PreparePayload", @@ -564,7 +559,6 @@ func (bc *blockChain) prepareBlock(position types.Position, if !b.Timestamp.After(tip.Timestamp) { b.Timestamp = tip.Timestamp.Add(tipConfig.minBlockInterval) } - } else { b.Witness.Height = tip.Witness.Height b.Witness.Data = make([]byte, len(tip.Witness.Data)) @@ -585,7 +579,7 @@ func (bc *blockChain) prepareBlock(position types.Position, return } -func (bc *blockChain) getTipConfig() blockChainConfig { +func (bc *blockChain) tipConfig() blockChainConfig { if bc.lastConfirmed == nil { panic(fmt.Errorf("attempting to access config without tip")) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 908b04f..382ccd7 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -51,7 +51,6 @@ type BlockChainTestSuite struct { signer *utils.Signer dMoment time.Time blockInterval time.Duration - roundInterval time.Duration } func (s *BlockChainTestSuite) SetupSuite() { @@ -61,7 +60,6 @@ func (s *BlockChainTestSuite) SetupSuite() { s.signer = utils.NewSigner(prvKeys[0]) s.dMoment = time.Now().UTC() s.blockInterval = 1 * time.Millisecond - s.roundInterval = 10 * time.Second } func (s *BlockChainTestSuite) newBlocks(c uint64, initBlock *types.Block) ( @@ -129,7 +127,8 @@ func (s *BlockChainTestSuite) newRandomnessFromBlock( } } -func (s *BlockChainTestSuite) newBlockChain(initB *types.Block) *blockChain { +func (s *BlockChainTestSuite) newBlockChain(initB *types.Block, + roundInterval uint64) *blockChain { initRound := uint64(0) if initB != nil { initRound = initB.Position.Round @@ -137,11 +136,16 @@ func (s *BlockChainTestSuite) newBlockChain(initB *types.Block) *blockChain { initConfig := blockChainConfig{} initConfig.fromConfig(initRound, &types.Config{ MinBlockInterval: s.blockInterval, - RoundInterval: s.roundInterval, + RoundInterval: roundInterval, }) - initConfig.setRoundBeginTime(s.dMoment) - return newBlockChain(s.nID, initB, initConfig, test.NewApp(0, nil), - &testTSigVerifierGetter{}, s.signer, &common.NullLogger{}) + if initB != nil { + initConfig.setRoundBeginHeight(initB.Position.Height) + } else { + initConfig.setRoundBeginHeight(0) + } + return newBlockChain(s.nID, s.dMoment, initB, initConfig, + test.NewApp(0, nil), &testTSigVerifierGetter{}, s.signer, + &common.NullLogger{}) } func (s *BlockChainTestSuite) newRoundOneInitBlock() *types.Block { @@ -157,7 +161,7 @@ func (s *BlockChainTestSuite) newRoundOneInitBlock() *types.Block { func (s *BlockChainTestSuite) baseConcurrentAceessTest(initBlock *types.Block, blocks []*types.Block, rands []*types.BlockRandomnessResult) { var ( - bc = s.newBlockChain(initBlock) + bc = s.newBlockChain(initBlock, uint64(len(blocks)+1)) start = make(chan struct{}) newNotif = make(chan struct{}, 1) delivered []*types.Block @@ -214,7 +218,7 @@ func (s *BlockChainTestSuite) baseConcurrentAceessTest(initBlock *types.Block, func (s *BlockChainTestSuite) TestBasicUsage() { initBlock := s.newRoundOneInitBlock() - bc := s.newBlockChain(initBlock) + bc := s.newBlockChain(initBlock, 10) // test scenario: block, empty block, randomness can be added in any order // of position. blocks := s.newBlocks(4, initBlock) @@ -273,11 +277,7 @@ func (s *BlockChainTestSuite) TestConcurrentAccess() { } func (s *BlockChainTestSuite) TestSanityCheck() { - bc := s.newBlockChain(nil) - // Non-zero chainID is not allowed. - s.Require().Panics(func() { - bc.sanityCheck(&types.Block{Position: types.Position{ChainID: 1}}) - }) + bc := s.newBlockChain(nil, 4) // Empty block is not allowed. s.Require().Panics(func() { bc.sanityCheck(&types.Block{}) @@ -331,7 +331,7 @@ func (s *BlockChainTestSuite) TestSanityCheck() { } func (s *BlockChainTestSuite) TestAppendConfig() { - bc := s.newBlockChain(nil) + bc := s.newBlockChain(nil, 10) s.Require().Equal(ErrRoundNotIncreasing.Error(), bc.appendConfig(0, &types.Config{}).Error()) s.Require().Equal(ErrRoundNotIncreasing.Error(), @@ -340,7 +340,7 @@ func (s *BlockChainTestSuite) TestAppendConfig() { } func (s *BlockChainTestSuite) TestConfirmed() { - bc := s.newBlockChain(nil) + bc := s.newBlockChain(nil, 10) blocks := s.newBlocks(3, nil) // Add a confirmed block. s.Require().NoError(bc.addBlock(blocks[0])) @@ -351,12 +351,17 @@ func (s *BlockChainTestSuite) TestConfirmed() { s.Require().True(bc.confirmed(2)) } -func (s *BlockChainTestSuite) TestNextBlock() { - bc := s.newBlockChain(nil) +func (s *BlockChainTestSuite) TestNextBlockAndTipRound() { + var roundInterval uint64 = 3 + bc := s.newBlockChain(nil, roundInterval) + s.Require().NoError(bc.appendConfig(1, &types.Config{ + MinBlockInterval: s.blockInterval, + RoundInterval: roundInterval, + })) blocks := s.newBlocks(3, nil) nextH, nextT := bc.nextBlock() s.Require().Equal(nextH, uint64(0)) - s.Require().Equal(nextT, bc.configs[0].roundBeginTime) + s.Require().Equal(nextT, s.dMoment) // Add one block. s.Require().NoError(bc.addBlock(blocks[0])) nextH, nextT = bc.nextBlock() @@ -368,11 +373,17 @@ func (s *BlockChainTestSuite) TestNextBlock() { nextH2, nextT2 := bc.nextBlock() s.Require().Equal(nextH, nextH2) s.Require().Equal(nextT, nextT2) + // Add a block, which is the last block of this round. + b3 := s.newBlock(blocks[2], 1, 1*time.Second) + s.Require().NoError(bc.addBlock(blocks[1])) + s.Require().NoError(bc.sanityCheck(b3)) + s.Require().NoError(bc.addBlock(b3)) + s.Require().Equal(bc.tipRound(), uint64(1)) } func (s *BlockChainTestSuite) TestPendingBlocksWithoutRandomness() { initBlock := s.newRoundOneInitBlock() - bc := s.newBlockChain(initBlock) + bc := s.newBlockChain(initBlock, 10) blocks := s.newBlocks(4, initBlock) s.Require().NoError(bc.addBlock(blocks[0])) s.Require().NoError(bc.addBlock(blocks[1])) @@ -386,7 +397,7 @@ func (s *BlockChainTestSuite) TestPendingBlocksWithoutRandomness() { func (s *BlockChainTestSuite) TestLastXBlock() { initBlock := s.newRoundOneInitBlock() - bc := s.newBlockChain(initBlock) + bc := s.newBlockChain(initBlock, 10) s.Require().Nil(bc.lastPendingBlock()) s.Require().True(bc.lastDeliveredBlock() == initBlock) blocks := s.newBlocks(2, initBlock) @@ -422,7 +433,7 @@ func (s *BlockChainTestSuite) TestPendingBlockRecords() { } func (s *BlockChainTestSuite) TestFindPendingBlock() { - bc := s.newBlockChain(nil) + bc := s.newBlockChain(nil, 10) blocks := s.newBlocks(7, nil) s.Require().NoError(bc.addBlock(blocks[6])) s.Require().NoError(bc.addBlock(blocks[5])) @@ -440,7 +451,7 @@ func (s *BlockChainTestSuite) TestFindPendingBlock() { } func (s *BlockChainTestSuite) TestAddEmptyBlockDirectly() { - bc := s.newBlockChain(nil) + bc := s.newBlockChain(nil, 10) blocks := s.newBlocks(1, nil) s.Require().NoError(bc.addBlock(blocks[0])) // Add an empty block after a normal block. diff --git a/core/consensus.go b/core/consensus.go index f4c0a37..b3fd312 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -58,12 +58,12 @@ var ( // consensusBAReceiver implements agreementReceiver. type consensusBAReceiver struct { // TODO(mission): consensus would be replaced by blockChain and network. - consensus *Consensus - agreementModule *agreement - changeNotaryTime time.Time - roundValue *atomic.Value - isNotary bool - restartNotary chan types.Position + consensus *Consensus + agreementModule *agreement + changeNotaryHeight uint64 + roundValue *atomic.Value + isNotary bool + restartNotary chan types.Position } func (recv *consensusBAReceiver) round() uint64 { @@ -241,10 +241,17 @@ CleanChannelLoop: } } newPos := block.Position - if block.Timestamp.After(recv.changeNotaryTime) { + if block.Position.Height+1 == recv.changeNotaryHeight { newPos.Round++ recv.roundValue.Store(newPos.Round) } + currentRound := recv.round() + if block.Position.Height > recv.changeNotaryHeight && + block.Position.Round <= currentRound { + panic(fmt.Errorf( + "round not switch when confirmig: %s, %d, should switch at %d", + block, currentRound, recv.changeNotaryHeight)) + } recv.restartNotary <- newPos } @@ -383,7 +390,6 @@ type Consensus struct { bcModule *blockChain dMoment time.Time nodeSetCache *utils.NodeSetCache - round uint64 roundForNewConfig uint64 lock sync.RWMutex ctx context.Context @@ -412,7 +418,7 @@ func NewConsensus( prv crypto.PrivateKey, logger common.Logger) *Consensus { return newConsensusForRound( - nil, dMoment, app, gov, db, network, prv, logger, true) + nil, 0, dMoment, app, gov, db, network, prv, logger, true) } // NewConsensusForSimulation creates an instance of Consensus for simulation, @@ -426,7 +432,7 @@ func NewConsensusForSimulation( prv crypto.PrivateKey, logger common.Logger) *Consensus { return newConsensusForRound( - nil, dMoment, app, gov, db, network, prv, logger, false) + nil, 0, dMoment, app, gov, db, network, prv, logger, false) } // NewConsensusFromSyncer constructs an Consensus instance from information @@ -440,7 +446,8 @@ func NewConsensusForSimulation( // their positions, in ascending order. func NewConsensusFromSyncer( initBlock *types.Block, - initRoundBeginTime time.Time, + initRoundBeginHeight uint64, + dMoment time.Time, app Application, gov Governance, db db.Database, @@ -451,8 +458,8 @@ func NewConsensusFromSyncer( cachedMessages []interface{}, logger common.Logger) (*Consensus, error) { // Setup Consensus instance. - con := newConsensusForRound(initBlock, initRoundBeginTime, app, gov, db, - networkModule, prv, logger, true) + con := newConsensusForRound(initBlock, initRoundBeginHeight, dMoment, app, + gov, db, networkModule, prv, logger, true) // Launch a dummy receiver before we start receiving from network module. con.dummyMsgBuffer = cachedMessages con.dummyCancel, con.dummyFinished = utils.LaunchDummyReceiver( @@ -486,9 +493,11 @@ func NewConsensusFromSyncer( } // newConsensusForRound creates a Consensus instance. +// TODO(mission): remove dMoment, it's no longer one part of consensus. func newConsensusForRound( initBlock *types.Block, - initRoundBeginTime time.Time, + initRoundBeginHeight uint64, + dMoment time.Time, app Application, gov Governance, db db.Database, @@ -511,6 +520,7 @@ func newConsensusForRound( initRound = initBlock.Position.Round } initConfig := utils.GetConfigWithPanic(gov, initRound, logger) + initCRS := utils.GetCRSWithPanic(gov, initRound, logger) // Init configuration chain. ID := types.NewNodeID(prv.PublicKey()) recv := &consensusDKGReceiver{ @@ -529,8 +539,8 @@ func newConsensusForRound( } bcConfig := blockChainConfig{} bcConfig.fromConfig(initRound, initConfig) - bcConfig.setRoundBeginTime(initRoundBeginTime) - bcModule := newBlockChain(ID, initBlock, bcConfig, appModule, + bcConfig.setRoundBeginHeight(initRoundBeginHeight) + bcModule := newBlockChain(ID, dMoment, initBlock, bcConfig, appModule, NewTSigVerifierCache(gov, 7), signer, logger) // Construct Consensus instance. con := &Consensus{ @@ -544,7 +554,7 @@ func newConsensusForRound( dkgReady: sync.NewCond(&sync.Mutex{}), cfgModule: cfgModule, bcModule: bcModule, - dMoment: initRoundBeginTime, + dMoment: dMoment, nodeSetCache: nodeSetCache, signer: signer, event: common.NewEvent(), @@ -555,8 +565,15 @@ func newConsensusForRound( processBlockChan: make(chan *types.Block, 1024), } con.ctx, con.ctxCancel = context.WithCancel(context.Background()) - con.baMgr = newAgreementMgr(con, initRound, initRoundBeginTime) - if err := con.prepare(initBlock); err != nil { + baConfig := agreementMgrConfig{} + baConfig.from(initRound, initConfig, initCRS) + baConfig.setRoundBeginHeight(initRoundBeginHeight) + var err error + con.baMgr, err = newAgreementMgr(con, initRound, baConfig) + if err != nil { + panic(err) + } + if err = con.prepare(initRoundBeginHeight, initBlock); err != nil { panic(err) } return con @@ -566,26 +583,17 @@ func newConsensusForRound( // 'initBlock' could be either: // - nil // - the last finalized block -func (con *Consensus) prepare(initBlock *types.Block) (err error) { +func (con *Consensus) prepare( + initRoundBeginHeight uint64, initBlock *types.Block) (err error) { // The block past from full node should be delivered already or known by // full node. We don't have to notify it. initRound := uint64(0) if initBlock != nil { initRound = initBlock.Position.Round } + // Setup blockChain module. con.roundForNewConfig = initRound + 1 initConfig := utils.GetConfigWithPanic(con.gov, initRound, con.logger) - // Setup context. - con.logger.Debug("Calling Governance.CRS", "round", initRound) - initCRS := con.gov.CRS(initRound) - if (initCRS == common.Hash{}) { - err = ErrCRSNotReady - return - } - if err = con.baMgr.appendConfig(initRound, initConfig, initCRS); err != nil { - return - } - // Setup blockChain module. initPlusOneCfg := utils.GetConfigWithPanic(con.gov, initRound+1, con.logger) if err = con.bcModule.appendConfig(initRound+1, initPlusOneCfg); err != nil { return @@ -604,15 +612,16 @@ func (con *Consensus) prepare(initBlock *types.Block) (err error) { // DKG would success. Three is a magic number. time.Sleep(initConfig.MinBlockInterval * 3) con.cfgModule.registerDKG(initRound, getDKGThreshold(initConfig)) - con.event.RegisterTime(con.dMoment.Add(initConfig.RoundInterval/4), - func(time.Time) { + con.event.RegisterHeight( + initConfig.RoundInterval/4, + func(uint64) { con.runDKG(initRound, initConfig) }) }() } } // Register events. - con.initialRound(con.dMoment, initRound, initConfig) + con.initialRound(initRoundBeginHeight, initRound, initConfig) return } @@ -672,18 +681,11 @@ func (con *Consensus) runDKG(round uint64, config *types.Config) { } con.dkgRunning = 1 go func() { - startTime := time.Now().UTC() defer func() { con.dkgReady.L.Lock() defer con.dkgReady.L.Unlock() con.dkgReady.Broadcast() con.dkgRunning = 2 - DKGTime := time.Now().Sub(startTime) - if DKGTime.Nanoseconds() >= - config.RoundInterval.Nanoseconds()/2 { - con.logger.Warn("Your computer cannot finish DKG on time!", - "nodeID", con.ID.String()) - } }() if err := con.cfgModule.runDKG(round); err != nil { con.logger.Error("Failed to runDKG", "error", err) @@ -739,7 +741,7 @@ func (con *Consensus) runCRS(round uint64) { } func (con *Consensus) initialRound( - startTime time.Time, round uint64, config *types.Config) { + startHeight uint64, round uint64, config *types.Config) { select { case <-con.ctx.Done(): return @@ -752,8 +754,9 @@ func (con *Consensus) initialRound( } // Initiate CRS routine. if _, exist := curDkgSet[con.ID]; exist { - con.event.RegisterTime(startTime.Add(config.RoundInterval/2), - func(time.Time) { + con.event.RegisterHeight( + startHeight+config.RoundInterval/2, + func(uint64) { go func() { con.runCRS(round) }() @@ -774,76 +777,71 @@ func (con *Consensus) initialRound( } } // Initiate BA modules. - con.event.RegisterTime( - startTime.Add(config.RoundInterval/2+config.LambdaDKG), - func(time.Time) { - go func(nextRound uint64) { - if !checkWithCancel( - con.ctx, 500*time.Millisecond, checkCRS(nextRound)) { - con.logger.Debug("unable to prepare CRS for baMgr", - "round", nextRound) - return - } - // Notify BA for new round. - nextConfig := utils.GetConfigWithPanic( - con.gov, nextRound, con.logger) - nextCRS := utils.GetCRSWithPanic( - con.gov, nextRound, con.logger) - con.logger.Info("appendConfig for baMgr", "round", nextRound) - if err := con.baMgr.appendConfig( - nextRound, nextConfig, nextCRS); err != nil { - panic(err) - } - }(round + 1) - }) + con.event.RegisterHeight(startHeight+config.RoundInterval/2, func(uint64) { + go func(nextRound uint64) { + if !checkWithCancel( + con.ctx, 500*time.Millisecond, checkCRS(nextRound)) { + con.logger.Debug("unable to prepare CRS for baMgr", + "round", nextRound) + return + } + // Notify BA for new round. + nextConfig := utils.GetConfigWithPanic( + con.gov, nextRound, con.logger) + nextCRS := utils.GetCRSWithPanic( + con.gov, nextRound, con.logger) + con.logger.Info("appendConfig for baMgr", "round", nextRound) + if err := con.baMgr.appendConfig( + nextRound, nextConfig, nextCRS); err != nil { + panic(err) + } + }(round + 1) + }) // Initiate DKG for this round. - con.event.RegisterTime(startTime.Add(config.RoundInterval/2+config.LambdaDKG), - func(time.Time) { - go func(nextRound uint64) { - // Normally, gov.CRS would return non-nil. Use this for in case of - // unexpected network fluctuation and ensure the robustness. - if !checkWithCancel( - con.ctx, 500*time.Millisecond, checkCRS(nextRound)) { - con.logger.Debug("unable to prepare CRS for DKG set", - "round", nextRound) - return - } - nextDkgSet, err := con.nodeSetCache.GetDKGSet(nextRound) - if err != nil { - con.logger.Error("Error getting DKG set", - "round", nextRound, - "error", err) - return - } - if _, exist := nextDkgSet[con.ID]; !exist { - return - } - con.logger.Info("Selected as DKG set", "round", nextRound) - con.cfgModule.registerDKG(nextRound, getDKGThreshold(config)) - con.event.RegisterTime( - startTime.Add(config.RoundInterval*2/3), - func(time.Time) { - func() { - con.dkgReady.L.Lock() - defer con.dkgReady.L.Unlock() - con.dkgRunning = 0 - }() - nextConfig := utils.GetConfigWithPanic( - con.gov, nextRound, con.logger) - con.runDKG(nextRound, nextConfig) - }) - }(round + 1) - }) + con.event.RegisterHeight(startHeight+config.RoundInterval/2, func(uint64) { + go func(nextRound uint64) { + // Normally, gov.CRS would return non-nil. Use this for in case of + // unexpected network fluctuation and ensure the robustness. + if !checkWithCancel( + con.ctx, 500*time.Millisecond, checkCRS(nextRound)) { + con.logger.Debug("unable to prepare CRS for DKG set", + "round", nextRound) + return + } + nextDkgSet, err := con.nodeSetCache.GetDKGSet(nextRound) + if err != nil { + con.logger.Error("Error getting DKG set", + "round", nextRound, + "error", err) + return + } + if _, exist := nextDkgSet[con.ID]; !exist { + return + } + con.logger.Info("Selected as DKG set", "round", nextRound) + con.cfgModule.registerDKG(nextRound, getDKGThreshold(config)) + con.event.RegisterHeight(startHeight+config.RoundInterval*2/3, + func(uint64) { + func() { + con.dkgReady.L.Lock() + defer con.dkgReady.L.Unlock() + con.dkgRunning = 0 + }() + nextConfig := utils.GetConfigWithPanic( + con.gov, nextRound, con.logger) + con.runDKG(nextRound, nextConfig) + }) + }(round + 1) + }) // Prepare blockChain module for next round and next "initialRound" routine. - con.event.RegisterTime(startTime.Add(config.RoundInterval), - func(time.Time) { - // Change round. - // Get configuration for next round. - nextRound := round + 1 - nextConfig := utils.GetConfigWithPanic(con.gov, nextRound, con.logger) - con.initialRound( - startTime.Add(config.RoundInterval), nextRound, nextConfig) - }) + con.event.RegisterHeight(startHeight+config.RoundInterval, func(uint64) { + // Change round. + // Get configuration for next round. + nextRound := round + 1 + nextConfig := utils.GetConfigWithPanic(con.gov, nextRound, con.logger) + con.initialRound( + startHeight+config.RoundInterval, nextRound, nextConfig) + }) } // Stop the Consensus core. @@ -1194,7 +1192,7 @@ func (con *Consensus) deliverFinalizedBlocksWithoutLock() (err error) { "pending", con.bcModule.lastPendingBlock()) for _, b := range deliveredBlocks { con.deliverBlock(b) - go con.event.NotifyTime(b.Finalization.Timestamp) + go con.event.NotifyHeight(b.Finalization.Height) } return } diff --git a/core/consensus_test.go b/core/consensus_test.go index fe28320..ca619df 100644 --- a/core/consensus_test.go +++ b/core/consensus_test.go @@ -203,16 +203,6 @@ func (s *ConsensusTestSuite) prepareConsensus( return app, con } -func (s *ConsensusTestSuite) prepareAgreementMgrWithoutRunning( - con *Consensus, numChains uint32) { - // This is a workaround to setup agreementMgr. - con.baMgr.appendConfig(0, &types.Config{ - NumChains: numChains, - RoundInterval: time.Hour, - LambdaBA: 50 * time.Millisecond, - }, common.NewRandomHash()) -} - func (s *ConsensusTestSuite) TestDKGCRS() { n := 21 lambda := 200 * time.Millisecond @@ -229,7 +219,7 @@ func (s *ConsensusTestSuite) TestDKGCRS() { gov, err := test.NewGovernance(test.NewState( pubKeys, lambda, &common.NullLogger{}, true), ConfigRoundShift) s.Require().NoError(err) - gov.State().RequestChange(test.StateChangeRoundInterval, 200*lambda) + gov.State().RequestChange(test.StateChangeRoundInterval, uint64(200)) cons := map[types.NodeID]*Consensus{} dMoment := time.Now().UTC() for _, key := range prvKeys { @@ -281,9 +271,8 @@ func (s *ConsensusTestSuite) TestSyncBA() { signers = append(signers, utils.NewSigner(prvKey)) } pos := types.Position{ - Round: 0, - ChainID: 0, - Height: 20, + Round: 0, + Height: 20, } baResult := &types.AgreementResult{ BlockHash: hash, diff --git a/core/round-based-config.go b/core/round-based-config.go index 67779a6..f2cfc82 100644 --- a/core/round-based-config.go +++ b/core/round-based-config.go @@ -18,20 +18,16 @@ package core import ( - "time" + "fmt" "github.com/dexon-foundation/dexon-consensus/core/types" ) type roundBasedConfig struct { - roundID uint64 - - // roundBeginTime is the beginning of round, as local time. - roundBeginTime time.Time - roundInterval time.Duration - - // roundEndTime is a cache for begin + interval. - roundEndTime time.Time + roundID uint64 + roundBeginHeight uint64 + roundEndHeight uint64 + roundInterval uint64 } func (config *roundBasedConfig) setupRoundBasedFields( @@ -40,13 +36,16 @@ func (config *roundBasedConfig) setupRoundBasedFields( config.roundInterval = cfg.RoundInterval } -func (config *roundBasedConfig) setRoundBeginTime(begin time.Time) { - config.roundBeginTime = begin - config.roundEndTime = begin.Add(config.roundInterval) +func (config *roundBasedConfig) setRoundBeginHeight(begin uint64) { + config.roundBeginHeight = begin + config.roundEndHeight = begin + config.roundInterval } // isLastBlock checks if a block is the last block of this round. func (config *roundBasedConfig) isLastBlock(b *types.Block) bool { - return b.Position.Round == config.roundID && - b.Timestamp.After(config.roundEndTime) + if b.Position.Round != config.roundID { + panic(fmt.Errorf("attempt to compare by different round: %s, %d", + b, config.roundID)) + } + return b.Position.Height+1 == config.roundEndHeight } diff --git a/core/syncer/consensus.go b/core/syncer/consensus.go index 618d90e..538913f 100644 --- a/core/syncer/consensus.go +++ b/core/syncer/consensus.go @@ -67,7 +67,7 @@ type Consensus struct { blocks types.BlocksByPosition agreementModule *agreement configs []*types.Config - roundBeginTimes []time.Time + roundBeginHeights []uint64 agreementRoundCut uint64 // lock for accessing all fields. @@ -109,7 +109,7 @@ func NewConsensus( configs: []*types.Config{ utils.GetConfigWithPanic(gov, 0, logger), }, - roundBeginTimes: []time.Time{dMoment}, + roundBeginHeights: []uint64{0}, receiveChan: make(chan *types.Block, 1000), pullChan: make(chan common.Hash, 1000), randomnessResults: make(map[common.Hash]*types.BlockRandomnessResult), @@ -280,7 +280,8 @@ func (con *Consensus) GetSyncedConsensus() (*core.Consensus, error) { var err error con.syncedConsensus, err = core.NewConsensusFromSyncer( con.syncedLastBlock, - con.roundBeginTimes[con.syncedLastBlock.Position.Round], + con.roundBeginHeights[con.syncedLastBlock.Position.Round], + con.dMoment, con.app, con.gov, con.db, @@ -368,9 +369,9 @@ func (con *Consensus) setupConfigsUntilRound(round uint64) { for r := uint64(len(con.configs)); r <= round; r++ { cfg := utils.GetConfigWithPanic(con.gov, r, con.logger) con.configs = append(con.configs, cfg) - con.roundBeginTimes = append( - con.roundBeginTimes, - con.roundBeginTimes[r-1].Add(con.configs[r-1].RoundInterval)) + con.roundBeginHeights = append( + con.roundBeginHeights, + con.roundBeginHeights[r-1]+con.configs[r-1].RoundInterval) } } @@ -453,41 +454,22 @@ func (con *Consensus) startNetwork() { con.moduleWaitGroup.Add(1) go func() { defer con.moduleWaitGroup.Done() - Loop: + loop: for { select { case val := <-con.network.ReceiveChan(): - var pos types.Position switch v := val.(type) { case *types.Block: - pos = v.Position case *types.AgreementResult: - pos = v.Position case *types.BlockRandomnessResult: con.cacheRandomnessResult(v) - continue Loop + continue loop default: - continue Loop - } - if func() bool { - con.lock.RLock() - defer con.lock.RUnlock() - if pos.ChainID > 0 { - // This error might be easily encountered when the - // "latest" parameter of SyncBlocks is turned on too - // early. - con.logger.Error( - "Unknown chainID message received (syncer)", - "position", pos, - ) - return false - } - return true - }() { - con.agreementModule.inputChan <- val + continue loop } + con.agreementModule.inputChan <- val case <-con.ctx.Done(): - return + break loop } } }() diff --git a/core/test/app.go b/core/test/app.go index 1ce5b84..516974c 100644 --- a/core/test/app.go +++ b/core/test/app.go @@ -77,7 +77,7 @@ type AppDeliveredRecord struct { // App implements Application interface for testing purpose. type App struct { Confirmed map[common.Hash]*types.Block - LastConfirmedHeights map[uint32]uint64 + LastConfirmedHeight uint64 confirmedLock sync.RWMutex Delivered map[common.Hash]*AppDeliveredRecord DeliverSequence common.Hashes @@ -92,12 +92,11 @@ type App struct { // NewApp constructs a TestApp instance. func NewApp(initRound uint64, gov *Governance) (app *App) { app = &App{ - Confirmed: make(map[common.Hash]*types.Block), - LastConfirmedHeights: make(map[uint32]uint64), - Delivered: make(map[common.Hash]*AppDeliveredRecord), - DeliverSequence: common.Hashes{}, - gov: gov, - roundToNotify: initRound, + Confirmed: make(map[common.Hash]*types.Block), + Delivered: make(map[common.Hash]*AppDeliveredRecord), + DeliverSequence: common.Hashes{}, + gov: gov, + roundToNotify: initRound, } if gov != nil { app.state = gov.State() @@ -171,8 +170,7 @@ func (app *App) VerifyBlock(block *types.Block) types.BlockVerifyStatus { // verify the next block in a given chain. app.confirmedLock.RLock() defer app.confirmedLock.RUnlock() - if app.LastConfirmedHeights[block.Position.ChainID]+1 != - block.Position.Height { + if app.LastConfirmedHeight+1 != block.Position.Height { return types.VerifyRetryLater } } @@ -185,13 +183,11 @@ func (app *App) BlockConfirmed(b types.Block) { defer app.confirmedLock.Unlock() app.Confirmed[b.Hash] = &b if b.Position.Height != 0 { - if h, exists := app.LastConfirmedHeights[b.Position.ChainID]; exists { - if h+1 != b.Position.Height { - panic(ErrConfirmedHeightNotIncreasing) - } + if app.LastConfirmedHeight+1 != b.Position.Height { + panic(ErrConfirmedHeightNotIncreasing) } } - app.LastConfirmedHeights[b.Position.ChainID] = b.Position.Height + app.LastConfirmedHeight = b.Position.Height } // BlockDelivered implements Application interface. diff --git a/core/test/governance.go b/core/test/governance.go index 81ced54..d540280 100644 --- a/core/test/governance.go +++ b/core/test/governance.go @@ -382,7 +382,7 @@ func (g *Governance) Equal(other *Governance, checkState bool) bool { // NOTE: this function should be called before running. func (g *Governance) RegisterConfigChange( round uint64, t StateChangeType, v interface{}) (err error) { - if t < StateChangeNumChains || t > StateChangeDKGSetSize { + if t < StateAddCRS || t > StateChangeDKGSetSize { return fmt.Errorf("state changes to register is not supported: %v", t) } if round < 2 { diff --git a/core/test/governance_test.go b/core/test/governance_test.go index cef2aea..e0a2365 100644 --- a/core/test/governance_test.go +++ b/core/test/governance_test.go @@ -75,16 +75,16 @@ func (s *GovernanceTestSuite) TestRegisterChange() { genesisNodes, 100*time.Millisecond, &common.NullLogger{}, true), 2) req.NoError(err) // Unable to register change for genesis round. - req.Error(g.RegisterConfigChange(0, StateChangeNumChains, uint32(32))) + req.Error(g.RegisterConfigChange(0, StateChangeDKGSetSize, uint32(32))) // Make some round prepared. g.CatchUpWithRound(4) - req.Equal(g.Configuration(4).NumChains, uint32(20)) + req.Equal(g.Configuration(4).DKGSetSize, uint32(20)) // Unable to register change for prepared round. - req.Error(g.RegisterConfigChange(4, StateChangeNumChains, uint32(32))) + req.Error(g.RegisterConfigChange(4, StateChangeDKGSetSize, uint32(32))) // It's ok to make some change when condition is met. - req.NoError(g.RegisterConfigChange(5, StateChangeNumChains, uint32(32))) - req.NoError(g.RegisterConfigChange(6, StateChangeNumChains, uint32(32))) - req.NoError(g.RegisterConfigChange(7, StateChangeNumChains, uint32(40))) + req.NoError(g.RegisterConfigChange(5, StateChangeDKGSetSize, uint32(32))) + req.NoError(g.RegisterConfigChange(6, StateChangeDKGSetSize, uint32(32))) + req.NoError(g.RegisterConfigChange(7, StateChangeDKGSetSize, uint32(40))) // In local mode, state for round 6 would be ready after notified with // round 2. g.NotifyRound(2) @@ -94,8 +94,8 @@ func (s *GovernanceTestSuite) TestRegisterChange() { g.NotifyRound(4) // Notify governance to take a snapshot for round 7's configuration. g.NotifyRound(5) - req.Equal(g.Configuration(6).NumChains, uint32(32)) - req.Equal(g.Configuration(7).NumChains, uint32(40)) + req.Equal(g.Configuration(6).DKGSetSize, uint32(32)) + req.Equal(g.Configuration(7).DKGSetSize, uint32(40)) } func TestGovernance(t *testing.T) { diff --git a/core/test/network.go b/core/test/network.go index f5d1c6e..0bbb12e 100644 --- a/core/test/network.go +++ b/core/test/network.go @@ -735,7 +735,7 @@ func (n *Network) getNotarySet(round uint64) map[types.NodeID]struct{} { set, exists := n.notarySetCaches[round] if !exists { var err error - set, err = n.cache.GetNotarySet(round, 0) + set, err = n.cache.GetNotarySet(round) if err != nil { panic(err) } diff --git a/core/test/network_test.go b/core/test/network_test.go index fd5f97f..22c31a8 100644 --- a/core/test/network_test.go +++ b/core/test/network_test.go @@ -90,9 +90,8 @@ func (s *NetworkTestSuite) TestPullRequestMarshaling() { Requester: GenerateRandomNodeIDs(1)[0], Type: "vote", Identity: types.Position{ - Round: 1, - ChainID: 2, - Height: 3, + Round: 1, + Height: 3, }} b, err = json.Marshal(req) s.Require().NoError(err) @@ -102,8 +101,6 @@ func (s *NetworkTestSuite) TestPullRequestMarshaling() { s.Require().Equal(req.Type, req2.Type) s.Require().Equal(req.Identity.(types.Position).Round, req.Identity.(types.Position).Round) - s.Require().Equal(req.Identity.(types.Position).ChainID, - req.Identity.(types.Position).ChainID) s.Require().Equal(req.Identity.(types.Position).Height, req.Identity.(types.Position).Height) } @@ -197,9 +194,8 @@ func (s *NetworkTestSuite) TestPullVotes() { v := types.NewVote( types.VoteInit, common.NewRandomHash(), randObj.Uint64()) v.Position = types.Position{ - ChainID: randObj.Uint32(), - Height: randObj.Uint64(), - Round: uint64(randObj.Intn(int(maxRound + 1))), + Height: randObj.Uint64(), + Round: uint64(randObj.Intn(int(maxRound + 1))), } req.NoError(master.trans.Send(n.ID, v)) votes[v.VoteHeader] = v @@ -262,7 +258,7 @@ func (s *NetworkTestSuite) TestBroadcastToSet() { dkgSet, err := cache.GetDKGSet(0) req.NoError(err) req.Len(dkgSet, 1) - notarySet, err := cache.GetNotarySet(0, 0) + notarySet, err := cache.GetNotarySet(0) req.NoError(err) req.Len(notarySet, 1) var ( diff --git a/core/test/state-change-request.go b/core/test/state-change-request.go index 21e623b..5b19859 100644 --- a/core/test/state-change-request.go +++ b/core/test/state-change-request.go @@ -19,7 +19,6 @@ package test import ( "fmt" - "math" "time" "github.com/dexon-foundation/dexon-consensus/common" @@ -42,13 +41,10 @@ const ( StateAddDKGMPKReady StateAddDKGFinal // Configuration related. - StateChangeNumChains StateChangeLambdaBA StateChangeLambdaDKG StateChangeRoundInterval StateChangeMinBlockInterval - StateChangeK - StateChangePhiRatio StateChangeNotarySetSize StateChangeDKGSetSize // Node set related. @@ -69,8 +65,6 @@ func (t StateChangeType) String() string { return "AddDKGMPKReady" case StateAddDKGFinal: return "AddDKGFinal" - case StateChangeNumChains: - return "ChangeNumChains" case StateChangeLambdaBA: return "ChangeLambdaBA" case StateChangeLambdaDKG: @@ -79,10 +73,6 @@ func (t StateChangeType) String() string { return "ChangeRoundInterval" case StateChangeMinBlockInterval: return "ChangeMinBlockInterval" - case StateChangeK: - return "ChangeK" - case StateChangePhiRatio: - return "ChangePhiRatio" case StateChangeNotarySetSize: return "ChangeNotarySetSize" case StateChangeDKGSetSize: @@ -194,8 +184,6 @@ func (req *StateChangeRequest) String() (ret string) { ret += fmt.Sprintf("%s", req.Payload.(*typesDKG.MPKReady)) case StateAddDKGFinal: ret += fmt.Sprintf("%s", req.Payload.(*typesDKG.Finalize)) - case StateChangeNumChains: - ret += fmt.Sprintf("%v", req.Payload.(uint32)) case StateChangeLambdaBA: ret += fmt.Sprintf("%v", time.Duration(req.Payload.(uint64))) case StateChangeLambdaDKG: @@ -204,10 +192,6 @@ func (req *StateChangeRequest) String() (ret string) { ret += fmt.Sprintf("%v", time.Duration(req.Payload.(uint64))) case StateChangeMinBlockInterval: ret += fmt.Sprintf("%v", time.Duration(req.Payload.(uint64))) - case StateChangeK: - ret += fmt.Sprintf("%v", req.Payload.(uint64)) - case StateChangePhiRatio: - ret += fmt.Sprintf("%v", math.Float32frombits(req.Payload.(uint32))) case StateChangeNotarySetSize: ret += fmt.Sprintf("%v", req.Payload.(uint32)) case StateChangeDKGSetSize: diff --git a/core/test/state-change-request_test.go b/core/test/state-change-request_test.go index 658a9fb..eeba4c4 100644 --- a/core/test/state-change-request_test.go +++ b/core/test/state-change-request_test.go @@ -30,8 +30,8 @@ type StateChangeRequestTestSuite struct { func (s *StateChangeRequestTestSuite) TestEqual() { // Basically, only the cloned one would be equal. - st00 := NewStateChangeRequest(StateChangeNumChains, uint32(4)) - st01 := NewStateChangeRequest(StateChangeNumChains, uint32(4)) + st00 := NewStateChangeRequest(StateChangeNotarySetSize, uint32(4)) + st01 := NewStateChangeRequest(StateChangeNotarySetSize, uint32(4)) s.Error(ErrStatePendingChangesNotEqual, st00.Equal(st01)) // Even with identical payload, they would be different. mKey := typesDKG.NewMasterPublicKey() @@ -42,7 +42,7 @@ func (s *StateChangeRequestTestSuite) TestEqual() { func (s *StateChangeRequestTestSuite) TestClone() { // The cloned one should be no error when compared with 'Equal' method. - st00 := NewStateChangeRequest(StateChangeNumChains, uint32(7)) + st00 := NewStateChangeRequest(StateChangeDKGSetSize, uint32(7)) s.NoError(st00.Equal(st00.Clone())) st10 := NewStateChangeRequest( StateAddDKGMasterPublicKey, typesDKG.NewMasterPublicKey()) diff --git a/core/test/state.go b/core/test/state.go index a5a285b..27ff87a 100644 --- a/core/test/state.go +++ b/core/test/state.go @@ -20,7 +20,6 @@ package test import ( "bytes" "errors" - "math" "sort" "sync" "time" @@ -86,14 +85,11 @@ type crsAdditionRequest struct { // State emulates what the global state in governace contract on a fullnode. type State struct { // Configuration related. - numChains uint32 lambdaBA time.Duration lambdaDKG time.Duration - k int - phiRatio float32 notarySetSize uint32 dkgSetSize uint32 - roundInterval time.Duration + roundInterval uint64 minBlockInterval time.Duration // Nodes nodes map[types.NodeID]crypto.PublicKey @@ -129,15 +125,12 @@ func NewState( return &State{ local: local, logger: logger, - numChains: uint32(len(nodes)), lambdaBA: lambda, lambdaDKG: lambda * 10, - roundInterval: lambda * 10000, + roundInterval: 1000, minBlockInterval: 4 * lambda, crs: []common.Hash{genesisCRS}, nodes: nodes, - phiRatio: 0.667, - k: 0, notarySetSize: uint32(len(nodes)), dkgSetSize: uint32(len(nodes)), ownRequests: make(map[common.Hash]*StateChangeRequest), @@ -173,11 +166,8 @@ func (s *State) Snapshot() (*types.Config, []crypto.PublicKey) { nodes = append(nodes, key) } cfg := &types.Config{ - NumChains: s.numChains, LambdaBA: s.lambdaBA, LambdaDKG: s.lambdaDKG, - K: s.k, - PhiRatio: s.phiRatio, NotarySetSize: s.notarySetSize, DKGSetSize: s.dkgSetSize, RoundInterval: s.roundInterval, @@ -210,10 +200,6 @@ func (s *State) unpackPayload( case StateAddDKGFinal: v = &typesDKG.Finalize{} err = rlp.DecodeBytes(raw.Payload, v) - case StateChangeNumChains: - var tmp uint32 - err = rlp.DecodeBytes(raw.Payload, &tmp) - v = tmp case StateChangeLambdaBA: var tmp uint64 err = rlp.DecodeBytes(raw.Payload, &tmp) @@ -230,14 +216,6 @@ func (s *State) unpackPayload( var tmp uint64 err = rlp.DecodeBytes(raw.Payload, &tmp) v = tmp - case StateChangeK: - var tmp uint64 - err = rlp.DecodeBytes(raw.Payload, &tmp) - v = tmp - case StateChangePhiRatio: - var tmp uint32 - err = rlp.DecodeBytes(raw.Payload, &tmp) - v = tmp case StateChangeNotarySetSize: var tmp uint32 err = rlp.DecodeBytes(raw.Payload, &tmp) @@ -284,11 +262,8 @@ func (s *State) unpackRequests( // Equal checks equality between State instance. func (s *State) Equal(other *State) error { // Check configuration part. - configEqual := s.numChains == other.numChains && - s.lambdaBA == other.lambdaBA && + configEqual := s.lambdaBA == other.lambdaBA && s.lambdaDKG == other.lambdaDKG && - s.k == other.k && - s.phiRatio == other.phiRatio && s.notarySetSize == other.notarySetSize && s.dkgSetSize == other.dkgSetSize && s.roundInterval == other.roundInterval && @@ -447,11 +422,8 @@ func (s *State) Equal(other *State) error { func (s *State) Clone() (copied *State) { // Clone configuration parts. copied = &State{ - numChains: s.numChains, lambdaBA: s.lambdaBA, lambdaDKG: s.lambdaDKG, - k: s.k, - phiRatio: s.phiRatio, notarySetSize: s.notarySetSize, dkgSetSize: s.dkgSetSize, roundInterval: s.roundInterval, @@ -730,20 +702,14 @@ func (s *State) applyRequest(req *StateChangeRequest) error { s.dkgFinals[final.Round] = make(map[types.NodeID]*typesDKG.Finalize) } s.dkgFinals[final.Round][final.ProposerID] = final - case StateChangeNumChains: - s.numChains = req.Payload.(uint32) case StateChangeLambdaBA: s.lambdaBA = time.Duration(req.Payload.(uint64)) case StateChangeLambdaDKG: s.lambdaDKG = time.Duration(req.Payload.(uint64)) case StateChangeRoundInterval: - s.roundInterval = time.Duration(req.Payload.(uint64)) + s.roundInterval = req.Payload.(uint64) case StateChangeMinBlockInterval: s.minBlockInterval = time.Duration(req.Payload.(uint64)) - case StateChangeK: - s.k = int(req.Payload.(uint64)) - case StateChangePhiRatio: - s.phiRatio = math.Float32frombits(req.Payload.(uint32)) case StateChangeNotarySetSize: s.notarySetSize = req.Payload.(uint32) case StateChangeDKGSetSize: @@ -773,13 +739,8 @@ func (s *State) RequestChange( payload = payload.(crypto.PublicKey).Bytes() case StateChangeLambdaBA, StateChangeLambdaDKG, - StateChangeRoundInterval, StateChangeMinBlockInterval: payload = uint64(payload.(time.Duration)) - case StateChangeK: - payload = uint64(payload.(int)) - case StateChangePhiRatio: - payload = math.Float32bits(payload.(float32)) // These cases for for type assertion, make sure callers pass expected types. case StateAddCRS: payload = payload.(*crsAdditionRequest) diff --git a/core/test/state_test.go b/core/test/state_test.go index 79a7a85..d92a8c1 100644 --- a/core/test/state_test.go +++ b/core/test/state_test.go @@ -135,26 +135,20 @@ func (s *StateTestSuite) makeDKGChanges( } func (s *StateTestSuite) makeConfigChanges(st *State) { - st.RequestChange(StateChangeNumChains, uint32(7)) st.RequestChange(StateChangeLambdaBA, time.Nanosecond) st.RequestChange(StateChangeLambdaDKG, time.Millisecond) - st.RequestChange(StateChangeRoundInterval, time.Hour) + st.RequestChange(StateChangeRoundInterval, uint64(1001)) st.RequestChange(StateChangeMinBlockInterval, time.Second) - st.RequestChange(StateChangeK, 1) - st.RequestChange(StateChangePhiRatio, float32(0.5)) st.RequestChange(StateChangeNotarySetSize, uint32(5)) st.RequestChange(StateChangeDKGSetSize, uint32(6)) } func (s *StateTestSuite) checkConfigChanges(config *types.Config) { req := s.Require() - req.Equal(config.NumChains, uint32(7)) req.Equal(config.LambdaBA, time.Nanosecond) req.Equal(config.LambdaDKG, time.Millisecond) - req.Equal(config.RoundInterval, time.Hour) + req.Equal(config.RoundInterval, uint64(1001)) req.Equal(config.MinBlockInterval, time.Second) - req.Equal(config.K, 1) - req.Equal(config.PhiRatio, float32(0.5)) req.Equal(config.NotarySetSize, uint32(5)) req.Equal(config.DKGSetSize, uint32(6)) } @@ -210,7 +204,7 @@ func (s *StateTestSuite) TestEqual() { // Switch to remote mode. st.SwitchToRemoteMode() // Make some change. - req.NoError(st.RequestChange(StateChangeK, int(5))) + req.NoError(st.RequestChange(StateChangeNotarySetSize, uint32(100))) st6 := st.Clone() req.NoError(st.Equal(st6)) // Remove the pending change, should not be equal. @@ -254,14 +248,11 @@ func (s *StateTestSuite) TestLocalMode() { config1, nodes1 := st.Snapshot() req.True(s.compareNodes(genesisNodes, nodes1)) // Check settings of config1 affected by genesisNodes and lambda. - req.Equal(config1.NumChains, uint32(len(genesisNodes))) req.Equal(config1.LambdaBA, lambda) req.Equal(config1.LambdaDKG, lambda*10) - req.Equal(config1.RoundInterval, lambda*10000) + req.Equal(config1.RoundInterval, uint64(1000)) req.Equal(config1.NotarySetSize, uint32(len(genesisNodes))) req.Equal(config1.DKGSetSize, uint32(len(genesisNodes))) - req.Equal(config1.K, 0) - req.Equal(config1.PhiRatio, float32(0.667)) // Request some changes, every fields for config should be affected. s.makeConfigChanges(st) // Add new node. diff --git a/core/ticker.go b/core/ticker.go index ffd5ab4..636fb8c 100644 --- a/core/ticker.go +++ b/core/ticker.go @@ -18,6 +18,9 @@ package core import ( + "context" + "fmt" + "sync" "time" "github.com/dexon-foundation/dexon-consensus/core/utils" @@ -36,32 +39,65 @@ const ( // defaultTicker is a wrapper to implement ticker interface based on // time.Ticker. type defaultTicker struct { - ticker *time.Ticker - duration time.Duration + ticker *time.Ticker + tickerChan chan time.Time + duration time.Duration + ctx context.Context + ctxCancel context.CancelFunc + waitGroup sync.WaitGroup } // newDefaultTicker constructs an defaultTicker instance by giving an interval. func newDefaultTicker(lambda time.Duration) *defaultTicker { - return &defaultTicker{ - ticker: time.NewTicker(lambda), - duration: lambda, - } + ticker := &defaultTicker{duration: lambda} + ticker.init() + return ticker } // Tick implements Tick method of ticker interface. func (t *defaultTicker) Tick() <-chan time.Time { - return t.ticker.C + return t.tickerChan } // Stop implements Stop method of ticker interface. func (t *defaultTicker) Stop() { t.ticker.Stop() + t.ctxCancel() + t.waitGroup.Wait() + t.ctx = nil + t.ctxCancel = nil + close(t.tickerChan) + t.tickerChan = nil } // Restart implements Stop method of ticker interface. func (t *defaultTicker) Restart() { - t.ticker.Stop() + t.Stop() + t.init() +} + +func (t *defaultTicker) init() { t.ticker = time.NewTicker(t.duration) + t.tickerChan = make(chan time.Time) + t.ctx, t.ctxCancel = context.WithCancel(context.Background()) + t.waitGroup.Add(1) + go t.monitor() +} + +func (t *defaultTicker) monitor() { + defer t.waitGroup.Done() +loop: + for { + select { + case <-t.ctx.Done(): + break loop + case v := <-t.ticker.C: + select { + case t.tickerChan <- v: + default: + } + } + } } // newTicker is a helper to setup a ticker by giving an Governance. If @@ -82,8 +118,8 @@ func newTicker(gov Governance, round uint64, tickerType TickerType) (t Ticker) { duration = utils.GetConfigWithPanic(gov, round, nil).LambdaBA case TickerDKG: duration = utils.GetConfigWithPanic(gov, round, nil).LambdaDKG - case TickerCRS: - duration = utils.GetConfigWithPanic(gov, round, nil).RoundInterval / 2 + default: + panic(fmt.Errorf("unknown ticker type: %d", tickerType)) } t = newDefaultTicker(duration) } diff --git a/core/types/block.go b/core/types/block.go index a2b697c..8c3e510 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -208,7 +208,6 @@ func (b *Block) Clone() (bcopy *Block) { bcopy.ParentHash = b.ParentHash bcopy.Hash = b.Hash bcopy.Position.Round = b.Position.Round - bcopy.Position.ChainID = b.Position.ChainID bcopy.Position.Height = b.Position.Height bcopy.Signature = b.Signature.Clone() bcopy.CRSSignature = b.CRSSignature.Clone() diff --git a/core/types/block_test.go b/core/types/block_test.go index d47096f..1dd83a9 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -67,9 +67,8 @@ func (s *BlockTestSuite) createRandomBlock() *Block { ParentHash: common.NewRandomHash(), Hash: common.NewRandomHash(), Position: Position{ - Round: rand.Uint64(), - ChainID: rand.Uint32(), - Height: rand.Uint64(), + Round: rand.Uint64(), + Height: rand.Uint64(), }, Acks: common.NewSortedHashes(common.Hashes{ common.NewRandomHash(), diff --git a/core/types/config.go b/core/types/config.go index c9d31f8..56f0175 100644 --- a/core/types/config.go +++ b/core/types/config.go @@ -19,40 +19,29 @@ package types import ( "encoding/binary" - "math" "time" ) // Config stands for Current Configuration Parameters. type Config struct { - // Network related. - NumChains uint32 - // Lambda related. LambdaBA time.Duration LambdaDKG time.Duration - // Total ordering related. - K int - PhiRatio float32 - // Set related. NotarySetSize uint32 DKGSetSize uint32 // Time related. - RoundInterval time.Duration + RoundInterval uint64 MinBlockInterval time.Duration } // Clone return a copied configuration. func (c *Config) Clone() *Config { return &Config{ - NumChains: c.NumChains, LambdaBA: c.LambdaBA, LambdaDKG: c.LambdaDKG, - K: c.K, - PhiRatio: c.PhiRatio, NotarySetSize: c.NotarySetSize, DKGSetSize: c.DKGSetSize, RoundInterval: c.RoundInterval, @@ -62,9 +51,6 @@ func (c *Config) Clone() *Config { // Bytes returns []byte representation of Config. func (c *Config) Bytes() []byte { - binaryNumChains := make([]byte, 4) - binary.LittleEndian.PutUint32(binaryNumChains, c.NumChains) - binaryLambdaBA := make([]byte, 8) binary.LittleEndian.PutUint64( binaryLambdaBA, uint64(c.LambdaBA.Nanoseconds())) @@ -72,29 +58,20 @@ func (c *Config) Bytes() []byte { binary.LittleEndian.PutUint64( binaryLambdaDKG, uint64(c.LambdaDKG.Nanoseconds())) - binaryK := make([]byte, 4) - binary.LittleEndian.PutUint32(binaryK, uint32(c.K)) - binaryPhiRatio := make([]byte, 4) - binary.LittleEndian.PutUint32(binaryPhiRatio, math.Float32bits(c.PhiRatio)) - binaryNotarySetSize := make([]byte, 4) binary.LittleEndian.PutUint32(binaryNotarySetSize, c.NotarySetSize) binaryDKGSetSize := make([]byte, 4) binary.LittleEndian.PutUint32(binaryDKGSetSize, c.DKGSetSize) binaryRoundInterval := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRoundInterval, - uint64(c.RoundInterval.Nanoseconds())) + binary.LittleEndian.PutUint64(binaryRoundInterval, c.RoundInterval) binaryMinBlockInterval := make([]byte, 8) binary.LittleEndian.PutUint64(binaryMinBlockInterval, uint64(c.MinBlockInterval.Nanoseconds())) enc := make([]byte, 0, 40) - enc = append(enc, binaryNumChains...) enc = append(enc, binaryLambdaBA...) enc = append(enc, binaryLambdaDKG...) - enc = append(enc, binaryK...) - enc = append(enc, binaryPhiRatio...) enc = append(enc, binaryNotarySetSize...) enc = append(enc, binaryDKGSetSize...) enc = append(enc, binaryRoundInterval...) diff --git a/core/types/config_test.go b/core/types/config_test.go index bf6e422..6029479 100644 --- a/core/types/config_test.go +++ b/core/types/config_test.go @@ -30,13 +30,11 @@ type ConfigTestSuite struct { func (s *ConfigTestSuite) TestClone() { c := &Config{ - NumChains: 2, LambdaBA: 1 * time.Millisecond, LambdaDKG: 2 * time.Hour, - K: 4, NotarySetSize: 5, DKGSetSize: 6, - RoundInterval: 3 * time.Second, + RoundInterval: 1000, MinBlockInterval: 7 * time.Nanosecond, } s.Require().Equal(c, c.Clone()) diff --git a/core/types/position.go b/core/types/position.go index 902a55f..81d23c2 100644 --- a/core/types/position.go +++ b/core/types/position.go @@ -23,33 +23,22 @@ import ( // Position describes the position in the block lattice of an entity. type Position struct { - ChainID uint32 `json:"chain_id"` - Round uint64 `json:"round"` - Height uint64 `json:"height"` + Round uint64 `json:"round"` + Height uint64 `json:"height"` } func (pos Position) String() string { - return fmt.Sprintf("Position{Round:%d Chain:%d Height:%d}", - pos.Round, pos.ChainID, pos.Height) + return fmt.Sprintf("Position{Round:%d Height:%d}", pos.Round, pos.Height) } -// Equal checks if two positions are equal, it panics when their chainIDs -// are different. +// Equal checks if two positions are equal. func (pos Position) Equal(other Position) bool { - if pos.ChainID != other.ChainID { - panic(fmt.Errorf("unexpected chainID %d, should be %d", - other.ChainID, pos.ChainID)) - } return pos.Round == other.Round && pos.Height == other.Height } // Newer checks if one block is newer than another one on the same chain. // If two blocks on different chain compared by this function, it would panic. func (pos Position) Newer(other Position) bool { - if pos.ChainID != other.ChainID { - panic(fmt.Errorf("unexpected chainID %d, should be %d", - other.ChainID, pos.ChainID)) - } return pos.Round > other.Round || (pos.Round == other.Round && pos.Height > other.Height) } @@ -57,10 +46,6 @@ func (pos Position) Newer(other Position) bool { // Older checks if one block is older than another one on the same chain. // If two blocks on different chain compared by this function, it would panic. func (pos Position) Older(other Position) bool { - if pos.ChainID != other.ChainID { - panic(fmt.Errorf("unexpected chainID %d, should be %d", - other.ChainID, pos.ChainID)) - } return pos.Round < other.Round || (pos.Round == other.Round && pos.Height < other.Height) } diff --git a/core/types/position_test.go b/core/types/position_test.go index 213c15f..d2f4165 100644 --- a/core/types/position_test.go +++ b/core/types/position_test.go @@ -30,63 +30,47 @@ type PositionTestSuite struct { func (s *PositionTestSuite) TestNewer() { pos := Position{ - Round: 1, - ChainID: 1, - Height: 1, + Round: 1, + Height: 1, } - s.Panics(func() { - pos.Newer(Position{ChainID: 2}) - }) s.False(pos.Newer(Position{ - Round: 2, - ChainID: 1, - Height: 0, + Round: 2, + Height: 0, })) s.False(pos.Newer(Position{ - Round: 1, - ChainID: 1, - Height: 2, + Round: 1, + Height: 2, })) s.True(pos.Newer(Position{ - Round: 0, - ChainID: 1, - Height: 100, + Round: 0, + Height: 100, })) s.True(pos.Newer(Position{ - Round: 1, - ChainID: 1, - Height: 0, + Round: 1, + Height: 0, })) } func (s *PositionTestSuite) TestOlder() { pos := Position{ - Round: 1, - ChainID: 1, - Height: 1, + Round: 1, + Height: 1, } - s.Panics(func() { - pos.Older(Position{ChainID: 2}) - }) s.False(pos.Older(Position{ - Round: 0, - ChainID: 1, - Height: 0, + Round: 0, + Height: 0, })) s.False(pos.Older(Position{ - Round: 1, - ChainID: 1, - Height: 0, + Round: 1, + Height: 0, })) s.True(pos.Older(Position{ - Round: 2, - ChainID: 1, - Height: 0, + Round: 2, + Height: 0, })) s.True(pos.Older(Position{ - Round: 1, - ChainID: 1, - Height: 100, + Round: 1, + Height: 100, })) } @@ -116,9 +100,6 @@ func (s *PositionTestSuite) TestSearchInAsendingOrder() { func (s *PositionTestSuite) TestEqual() { pos := Position{} - s.Panics(func() { - pos.Equal(Position{ChainID: 1}) - }) s.True(pos.Equal(Position{})) s.False(pos.Equal(Position{Round: 1})) s.False(pos.Equal(Position{Height: 1})) diff --git a/core/utils.go b/core/utils.go index 14780e7..46aa77a 100644 --- a/core/utils.go +++ b/core/utils.go @@ -21,7 +21,6 @@ import ( "context" "errors" "fmt" - "math/rand" "os" "sort" "time" @@ -130,11 +129,6 @@ func removeFromSortedUint32Slice(xs []uint32, x uint32) []uint32 { return append(xs[:indexToRemove], xs[indexToRemove+1:]...) } -// pickBiasedTime returns a biased time based on a given range. -func pickBiasedTime(base time.Time, biasedRange time.Duration) time.Time { - return base.Add(time.Duration(rand.Intn(int(biasedRange)))) -} - // HashConfigurationBlock returns the hash value of configuration block. func HashConfigurationBlock( notarySet map[types.NodeID]struct{}, @@ -165,8 +159,7 @@ func HashConfigurationBlock( // instance. func VerifyAgreementResult( res *types.AgreementResult, cache *utils.NodeSetCache) error { - notarySet, err := cache.GetNotarySet( - res.Position.Round, res.Position.ChainID) + notarySet, err := cache.GetNotarySet(res.Position.Round) if err != nil { return err } diff --git a/core/utils/crypto.go b/core/utils/crypto.go index 43bbde1..fe67a95 100644 --- a/core/utils/crypto.go +++ b/core/utils/crypto.go @@ -140,9 +140,6 @@ func VerifyCRSSignature(block *types.Block, crs common.Hash) ( } func hashPosition(position types.Position) common.Hash { - binaryChainID := make([]byte, 4) - binary.LittleEndian.PutUint32(binaryChainID, position.ChainID) - binaryRound := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRound, position.Round) @@ -150,7 +147,6 @@ func hashPosition(position types.Position) common.Hash { binary.LittleEndian.PutUint64(binaryHeight, position.Height) return crypto.Keccak256Hash( - binaryChainID, binaryRound, binaryHeight, ) diff --git a/core/utils/nodeset-cache.go b/core/utils/nodeset-cache.go index 8354128..3ff5196 100644 --- a/core/utils/nodeset-cache.go +++ b/core/utils/nodeset-cache.go @@ -19,7 +19,6 @@ package utils import ( "errors" - "fmt" "sync" "github.com/dexon-foundation/dexon-consensus/common" @@ -34,8 +33,6 @@ var ( ErrCRSNotReady = errors.New("crs is not ready") // ErrConfigurationNotReady means we go nil configuration. ErrConfigurationNotReady = errors.New("configuration is not ready") - // ErrInvalidChainID means the chain ID is unexpected. - ErrInvalidChainID = errors.New("invalid chain id") ) type sets struct { @@ -125,12 +122,8 @@ func (cache *NodeSetCache) GetNodeSet(round uint64) (*types.NodeSet, error) { } // GetNotarySet returns of notary set of this round. -// TODO(mission): remove chainID parameter. func (cache *NodeSetCache) GetNotarySet( - round uint64, chainID uint32) (map[types.NodeID]struct{}, error) { - if chainID != 0 { - panic(fmt.Errorf("non-zero chainID found: %d", chainID)) - } + round uint64) (map[types.NodeID]struct{}, error) { IDs, err := cache.getOrUpdate(round) if err != nil { return nil, err @@ -196,12 +189,9 @@ func (cache *NodeSetCache) getOrUpdate(round uint64) (nIDs *sets, err error) { // // This cache would maintain 10 rounds before the updated round and purge // rounds not in this range. -func (cache *NodeSetCache) update( - round uint64) (nIDs *sets, err error) { - +func (cache *NodeSetCache) update(round uint64) (nIDs *sets, err error) { cache.lock.Lock() defer cache.lock.Unlock() - // Get information for the requested round. keySet := cache.nsIntf.NodeSet(round) if keySet == nil { @@ -232,14 +222,13 @@ func (cache *NodeSetCache) update( err = ErrConfigurationNotReady return } - nodesPerChain := cfg.RoundInterval / cfg.MinBlockInterval nIDs = &sets{ crs: crs, nodeSet: nodeSet, notarySet: make(map[types.NodeID]struct{}), dkgSet: nodeSet.GetSubSet( int(cfg.DKGSetSize), types.NewDKGSetTarget(crs)), - leaderNode: make(map[uint64]types.NodeID, nodesPerChain), + leaderNode: make(map[uint64]types.NodeID, cfg.RoundInterval), } nIDs.notarySet = nodeSet.GetSubSet( int(cfg.NotarySetSize), types.NewNotarySetTarget(crs)) @@ -261,12 +250,9 @@ func (cache *NodeSetCache) update( return } -func (cache *NodeSetCache) get( - round uint64) (nIDs *sets, exists bool) { - +func (cache *NodeSetCache) get(round uint64) (nIDs *sets, exists bool) { cache.lock.RLock() defer cache.lock.RUnlock() - nIDs, exists = cache.rounds[round] return } diff --git a/core/utils/nodeset-cache_test.go b/core/utils/nodeset-cache_test.go index eb6008d..52036b5 100644 --- a/core/utils/nodeset-cache_test.go +++ b/core/utils/nodeset-cache_test.go @@ -38,9 +38,8 @@ func (g *nsIntf) Configuration(round uint64) (cfg *types.Config) { return &types.Config{ NotarySetSize: 7, DKGSetSize: 7, - NumChains: 4, + RoundInterval: 60, LambdaBA: 250 * time.Millisecond, - RoundInterval: 60 * time.Second, MinBlockInterval: 1 * time.Second, } } @@ -89,16 +88,15 @@ func (s *NodeSetCacheTestSuite) TestBasicUsage() { nodeSet0, err := cache.GetNodeSet(0) req.NoError(err) chk(cache, 0, nodeSet0.IDs) - notarySet, err := cache.GetNotarySet(0, 0) + notarySet, err := cache.GetNotarySet(0) req.NoError(err) chk(cache, 0, notarySet) dkgSet, err := cache.GetDKGSet(0) req.NoError(err) chk(cache, 0, dkgSet) leaderNode, err := cache.GetLeaderNode(types.Position{ - Round: uint64(0), - ChainID: uint32(0), - Height: uint64(10), + Round: uint64(0), + Height: uint64(10), }) req.NoError(err) chk(cache, 0, map[types.NodeID]struct{}{ diff --git a/core/utils/signer_test.go b/core/utils/signer_test.go index 8e34b98..3905352 100644 --- a/core/utils/signer_test.go +++ b/core/utils/signer_test.go @@ -42,8 +42,8 @@ func (s *SignerTestSuite) TestBlock() { b := &types.Block{ ParentHash: common.NewRandomHash(), Position: types.Position{ - ChainID: 2, - Height: 3, + Round: 2, + Height: 3, }, Timestamp: time.Now().UTC(), } @@ -55,8 +55,8 @@ func (s *SignerTestSuite) TestVote() { k := s.setupSigner() v := types.NewVote(types.VoteCom, common.NewRandomHash(), 123) v.Position = types.Position{ - ChainID: 4, - Height: 6, + Round: 4, + Height: 6, } v.ProposerID = types.NodeID{Hash: common.NewRandomHash()} s.NoError(k.SignVote(v)) @@ -70,8 +70,8 @@ func (s *SignerTestSuite) TestCRS() { b := &types.Block{ ParentHash: common.NewRandomHash(), Position: types.Position{ - ChainID: 8, - Height: 9, + Round: 8, + Height: 9, }, Timestamp: time.Now().UTC(), } diff --git a/core/utils_test.go b/core/utils_test.go index fa5d260..c53a38f 100644 --- a/core/utils_test.go +++ b/core/utils_test.go @@ -58,9 +58,8 @@ func (s *UtilsTestSuite) TestVerifyAgreementResult() { signers = append(signers, utils.NewSigner(prvKey)) } pos := types.Position{ - Round: 0, - ChainID: 0, - Height: 20, + Round: 0, + Height: 20, } baResult := &types.AgreementResult{ BlockHash: hash, diff --git a/integration_test/byzantine_test.go b/integration_test/byzantine_test.go index fac8c0a..027b6e7 100644 --- a/integration_test/byzantine_test.go +++ b/integration_test/byzantine_test.go @@ -18,6 +18,7 @@ package integration import ( + "context" "fmt" "sync" "testing" @@ -143,7 +144,7 @@ func (s *ByzantineTestSuite) TestOneSlowNodeOneDeadNode() { core.ConfigRoundShift) req.NoError(err) req.NoError(seedGov.State().RequestChange( - test.StateChangeRoundInterval, 100*time.Second)) + test.StateChangeRoundInterval, uint64(60))) slowNodeID := types.NewNodeID(pubKeys[0]) deadNodeID := types.NewNodeID(pubKeys[1]) s.directLatencyModel[slowNodeID] = &test.FixedLatencyModel{ @@ -157,6 +158,11 @@ func (s *ByzantineTestSuite) TestOneSlowNodeOneDeadNode() { go n.con.Run() defer n.con.Stop() } + // Clean deadNode's network receive channel, or it might exceed the limit + // and block other go routines. + dummyReceiverCtxCancel, _ := utils.LaunchDummyReceiver( + context.Background(), nodes[deadNodeID].network.ReceiveChan(), nil) + defer dummyReceiverCtxCancel() Loop: for { <-time.After(5 * time.Second) diff --git a/integration_test/consensus_test.go b/integration_test/consensus_test.go index 454ed1e..b55ceac 100644 --- a/integration_test/consensus_test.go +++ b/integration_test/consensus_test.go @@ -215,7 +215,7 @@ func (s *ConsensusTestSuite) TestSimple() { core.ConfigRoundShift) req.NoError(err) req.NoError(seedGov.State().RequestChange( - test.StateChangeRoundInterval, 50*time.Second)) + test.StateChangeRoundInterval, uint64(60))) // A short round interval. nodes := s.setupNodes(dMoment, prvKeys, seedGov) for _, n := range nodes { @@ -255,12 +255,11 @@ func (s *ConsensusTestSuite) TestSetSizeChange() { req.NoError(err) // Setup seed governance instance. seedGov, err := test.NewGovernance( - test.NewState( - pubKeys, 100*time.Millisecond, &common.NullLogger{}, true), + test.NewState(pubKeys, 100*time.Millisecond, &common.NullLogger{}, true), core.ConfigRoundShift) req.NoError(err) req.NoError(seedGov.State().RequestChange( - test.StateChangeRoundInterval, 45*time.Second)) + test.StateChangeRoundInterval, uint64(60))) req.NoError(seedGov.State().RequestChange( test.StateChangeNotarySetSize, uint32(4))) req.NoError(seedGov.State().RequestChange( @@ -268,7 +267,7 @@ func (s *ConsensusTestSuite) TestSetSizeChange() { seedGov.CatchUpWithRound(0) // Setup configuration for round 0 and round 1. req.NoError(seedGov.State().RequestChange( - test.StateChangeRoundInterval, 55*time.Second)) + test.StateChangeRoundInterval, uint64(85))) req.NoError(seedGov.State().RequestChange( test.StateChangeNotarySetSize, uint32(5))) req.NoError(seedGov.State().RequestChange( @@ -276,7 +275,7 @@ func (s *ConsensusTestSuite) TestSetSizeChange() { seedGov.CatchUpWithRound(1) // Setup configuration for round 2. req.NoError(seedGov.State().RequestChange( - test.StateChangeRoundInterval, 55*time.Second)) + test.StateChangeRoundInterval, uint64(85))) req.NoError(seedGov.State().RequestChange( test.StateChangeNotarySetSize, uint32(6))) req.NoError(seedGov.State().RequestChange( @@ -284,7 +283,7 @@ func (s *ConsensusTestSuite) TestSetSizeChange() { seedGov.CatchUpWithRound(2) // Setup configuration for round 3. req.NoError(seedGov.State().RequestChange( - test.StateChangeRoundInterval, 75*time.Second)) + test.StateChangeRoundInterval, uint64(60))) req.NoError(seedGov.State().RequestChange( test.StateChangeNotarySetSize, uint32(4))) req.NoError(seedGov.State().RequestChange( @@ -299,18 +298,18 @@ func (s *ConsensusTestSuite) TestSetSizeChange() { } // Register configuration changes for round 4. req.NoError(pickedNode.gov.RegisterConfigChange( - 4, test.StateChangeRoundInterval, 45*time.Second)) - req.NoError(seedGov.State().RequestChange( - test.StateChangeNotarySetSize, uint32(5))) - req.NoError(seedGov.State().RequestChange( - test.StateChangeDKGSetSize, uint32(5))) + 4, test.StateChangeRoundInterval, uint64(80))) + req.NoError(pickedNode.gov.RegisterConfigChange( + 4, test.StateChangeNotarySetSize, uint32(5))) + req.NoError(pickedNode.gov.RegisterConfigChange( + 4, test.StateChangeDKGSetSize, uint32(5))) // Register configuration changes for round 5. req.NoError(pickedNode.gov.RegisterConfigChange( - 5, test.StateChangeRoundInterval, 55*time.Second)) - req.NoError(seedGov.State().RequestChange( - test.StateChangeNotarySetSize, uint32(4))) - req.NoError(seedGov.State().RequestChange( - test.StateChangeDKGSetSize, uint32(4))) + 5, test.StateChangeRoundInterval, uint64(60))) + req.NoError(pickedNode.gov.RegisterConfigChange( + 5, test.StateChangeNotarySetSize, uint32(4))) + req.NoError(pickedNode.gov.RegisterConfigChange( + 5, test.StateChangeDKGSetSize, uint32(4))) // Run test. for _, n := range nodes { go n.con.Run() @@ -356,12 +355,8 @@ func (s *ConsensusTestSuite) TestSync() { core.ConfigRoundShift) req.NoError(err) req.NoError(seedGov.State().RequestChange( - test.StateChangeRoundInterval, 55*time.Second)) - req.NoError(seedGov.State().RequestChange( - test.StateChangeNumChains, uint32(5))) + test.StateChangeRoundInterval, uint64(60))) seedGov.CatchUpWithRound(0) - req.NoError(seedGov.State().RequestChange( - test.StateChangeNumChains, uint32(4))) seedGov.CatchUpWithRound(1) // A short round interval. nodes := s.setupNodes(dMoment, prvKeys, seedGov) diff --git a/simulation/config/config.go b/simulation/config/config.go index 428b128..0ee2109 100644 --- a/simulation/config/config.go +++ b/simulation/config/config.go @@ -29,9 +29,6 @@ import ( // Consensus settings. type Consensus struct { - PhiRatio float32 - K int - NumChains uint32 GenesisCRS string `toml:"genesis_crs"` LambdaBA int `toml:"lambda_ba"` LambdaDKG int `toml:"lambda_dkg"` @@ -114,13 +111,10 @@ func GenerateDefault(path string) error { Title: "DEXON Consensus Simulation Config", Node: Node{ Consensus: Consensus{ - PhiRatio: float32(2) / 3, - K: 0, - NumChains: 7, GenesisCRS: "In DEXON we trust.", LambdaBA: 250, LambdaDKG: 1000, - RoundInterval: 30 * 1000, + RoundInterval: 1000, NotarySetSize: 7, DKGSetSize: 7, MinBlockInterval: 750, diff --git a/simulation/config/utils.go b/simulation/config/utils.go index 9d97fbd..f8f1eec 100644 --- a/simulation/config/utils.go +++ b/simulation/config/utils.go @@ -27,8 +27,6 @@ import ( // StateChangeTypeFromString convert a string to test.StateChangeType. func StateChangeTypeFromString(s string) test.StateChangeType { switch s { - case "num_chains": - return test.StateChangeNumChains case "lambda_ba": return test.StateChangeLambdaBA case "lambda_dkg": @@ -37,10 +35,6 @@ func StateChangeTypeFromString(s string) test.StateChangeType { return test.StateChangeRoundInterval case "min_block_interval": return test.StateChangeMinBlockInterval - case "k": - return test.StateChangeK - case "phi_ratio": - return test.StateChangePhiRatio case "notary_set_size": return test.StateChangeNotarySetSize case "dkg_set_size": @@ -54,27 +48,19 @@ func StateChangeTypeFromString(s string) test.StateChangeType { func StateChangeValueFromString( t test.StateChangeType, v string) interface{} { switch t { - case test.StateChangeNumChains, test.StateChangeNotarySetSize, - test.StateChangeDKGSetSize: + case test.StateChangeNotarySetSize, test.StateChangeDKGSetSize: ret, err := strconv.ParseUint(v, 10, 32) if err != nil { panic(err) } return uint32(ret) case test.StateChangeLambdaBA, test.StateChangeLambdaDKG, - test.StateChangeRoundInterval, test.StateChangeMinBlockInterval, - test.StateChangeK: + test.StateChangeRoundInterval, test.StateChangeMinBlockInterval: ret, err := strconv.ParseInt(v, 10, 32) if err != nil { panic(err) } return int(ret) - case test.StateChangePhiRatio: - ret, err := strconv.ParseFloat(v, 32) - if err != nil { - panic(err) - } - return float32(ret) } panic(fmt.Errorf("unsupported state change type %s", t)) } diff --git a/simulation/node.go b/simulation/node.go index 7c02991..7688c25 100644 --- a/simulation/node.go +++ b/simulation/node.go @@ -204,9 +204,6 @@ MainLoop: func (n *node) prepareConfigs() { // Prepare configurations. cConfig := n.cfg.Node.Consensus - n.gov.State().RequestChange(test.StateChangeK, cConfig.K) // #nosec G104 - n.gov.State().RequestChange(test.StateChangePhiRatio, cConfig.PhiRatio) // #nosec G104 - n.gov.State().RequestChange(test.StateChangeNumChains, cConfig.NumChains) // #nosec G104 n.gov.State().RequestChange( test.StateChangeNotarySetSize, cConfig.NotarySetSize) // #nosec G104 n.gov.State().RequestChange(test.StateChangeDKGSetSize, cConfig.DKGSetSize) // #nosec G104 @@ -214,8 +211,7 @@ func (n *node) prepareConfigs() { cConfig.LambdaBA)*time.Millisecond) // #nosec G104 n.gov.State().RequestChange(test.StateChangeLambdaDKG, time.Duration( cConfig.LambdaDKG)*time.Millisecond) // #nosec G104 - n.gov.State().RequestChange(test.StateChangeRoundInterval, time.Duration( - cConfig.RoundInterval)*time.Millisecond) // #nosec G104 + n.gov.State().RequestChange(test.StateChangeRoundInterval, cConfig.RoundInterval) // #nosec G104 n.gov.State().RequestChange(test.StateChangeMinBlockInterval, time.Duration( cConfig.MinBlockInterval)*time.Millisecond) // #nosec G104 n.gov.State().ProposeCRS(0, crypto.Keccak256Hash([]byte(cConfig.GenesisCRS))) // #nosec G104 diff --git a/test_config/test-config-change.toml b/test_config/test-config-change.toml index 396e627..9ee0839 100644 --- a/test_config/test-config-change.toml +++ b/test_config/test-config-change.toml @@ -6,13 +6,10 @@ max_block = 18446744073709551615 # node.consensus is the genesis configuration. [node.consensus] -phi_ratio = 6.666666865348816e-01 -k = 1 -num_chains = 4 genesis_crs = "In DEXON we trust." lambda_ba = 250 lambda_dkg = 4000 -round_interval = 100000 +round_interval = 1000 notary_set_size = 7 dkg_set_size = 7 min_block_interval = 750 @@ -20,15 +17,15 @@ min_block_interval = 750 # node.config_changes describe the changes of configuration for each round. [[node.changes]] round = 1 -type = "num_chains" +type = "notary_set_size" value = "5" [[node.changes]] round = 2 -type = "num_chains" +type = "notary_set_size" value = "6" [[node.changes]] round = 3 -type = "num_chains" +type = "notary_set_size" value = "4" [node.legacy] diff --git a/test_config/test.toml b/test_config/test.toml index 8c6e342..d16676b 100644 --- a/test_config/test.toml +++ b/test_config/test.toml @@ -5,13 +5,10 @@ num = 7 max_block = 18446744073709551615 [node.consensus] -phi_ratio = 6.666666865348816e-01 -k = 1 -chain_num = 7 genesis_crs = "In DEXON we trust." lambda_ba = 250 lambda_dkg = 4000 -round_interval = 200000 +round_interval = 2000 notary_set_size = 7 dkg_set_size = 7 min_block_interval = 750 |