Skip to content

Commit dfe417d

Browse files
authored
IOTEX-2 Support time based rotation on proposing a block (iotexproject#65)
1 parent 9e33ed7 commit dfe417d

File tree

6 files changed

+250
-36
lines changed

6 files changed

+250
-36
lines changed

config/config.go

+11-5
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,14 @@ var (
115115
EventChanSize: 10000,
116116
NumDelegates: 21,
117117
EnableDummyBlock: true,
118+
TimeBasedRotation: false,
118119
},
119120
BlockCreationInterval: 10 * time.Second,
120121
},
121122
BlockSync: BlockSync{
122123
Interval: 10 * time.Second,
123124
BufferSize: 16,
124125
},
125-
126126
Dispatcher: Dispatcher{
127127
EventChanSize: 10000,
128128
},
@@ -236,6 +236,7 @@ type (
236236
EventChanSize uint `yaml:"eventChanSize"`
237237
NumDelegates uint `yaml:"numDelegates"`
238238
EnableDummyBlock bool `yaml:"enableDummyBlock"`
239+
TimeBasedRotation bool `yaml:"timeBasedRotation"`
239240
}
240241

241242
// Dispatcher is the dispatcher config
@@ -416,26 +417,31 @@ func ValidateConsensusScheme(cfg *Config) error {
416417
// ValidateDispatcher validates the dispatcher configs
417418
func ValidateDispatcher(cfg *Config) error {
418419
if cfg.Dispatcher.EventChanSize <= 0 {
419-
return errors.Wrapf(ErrInvalidCfg, "dispatcher event chan size should be greater than 0")
420+
return errors.Wrap(ErrInvalidCfg, "dispatcher event chan size should be greater than 0")
420421
}
421422
return nil
422423
}
423424

424425
// ValidateRollDPoS validates the roll-DPoS configs
425426
func ValidateRollDPoS(cfg *Config) error {
426427
if cfg.Consensus.Scheme == RollDPoSScheme && cfg.Consensus.RollDPoS.EventChanSize <= 0 {
427-
return errors.Wrapf(ErrInvalidCfg, "roll-DPoS event chan size should be greater than 0")
428+
return errors.Wrap(ErrInvalidCfg, "roll-DPoS event chan size should be greater than 0")
428429
}
429430
if cfg.Consensus.Scheme == RollDPoSScheme && cfg.Consensus.RollDPoS.NumDelegates <= 0 {
430-
return errors.Wrapf(ErrInvalidCfg, "roll-DPoS event delegate number should be greater than 0")
431+
return errors.Wrap(ErrInvalidCfg, "roll-DPoS event delegate number should be greater than 0")
432+
}
433+
if cfg.Consensus.Scheme == RollDPoSScheme &&
434+
cfg.Consensus.RollDPoS.EnableDummyBlock &&
435+
cfg.Consensus.RollDPoS.TimeBasedRotation {
436+
return errors.Wrap(ErrInvalidCfg, "roll-DPoS should enable dummy block when doing time based rotation")
431437
}
432438
return nil
433439
}
434440

435441
// ValidateExplorer validates the explorer configs
436442
func ValidateExplorer(cfg *Config) error {
437443
if cfg.Explorer.Enabled && cfg.Explorer.TpsWindow <= 0 {
438-
return errors.Wrapf(ErrInvalidCfg, "tps window is not a positive integer when the explorer is enabled")
444+
return errors.Wrap(ErrInvalidCfg, "tps window is not a positive integer when the explorer is enabled")
439445
}
440446
return nil
441447
}

config/config_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,17 @@ func TestValidateRollDPoS(t *testing.T) {
287287
t,
288288
strings.Contains(err.Error(), "roll-DPoS event delegate number should be greater than 0"),
289289
)
290+
291+
cfg.Consensus.RollDPoS.NumDelegates = 1
292+
cfg.Consensus.RollDPoS.EnableDummyBlock = true
293+
cfg.Consensus.RollDPoS.TimeBasedRotation = true
294+
err = ValidateRollDPoS(&cfg)
295+
require.NotNil(t, err)
296+
require.Equal(t, ErrInvalidCfg, errors.Cause(err))
297+
require.True(
298+
t,
299+
strings.Contains(err.Error(), "roll-DPoS should enable dummy block when doing time based rotation"),
300+
)
290301
}
291302

292303
func TestValidateNetwork(t *testing.T) {

consensus/scheme/rolldpos/fsm.go

+19-6
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ func (m *cFSM) Start(c context.Context) error {
273273
src := m.fsm.CurrentState()
274274
if err := m.fsm.Handle(evt); err != nil {
275275
if errors.Cause(err) == fsm.ErrTransitionNotFound {
276-
if time.Since(evt.timestamp()) <= m.ctx.cfg.UnmatchedEventTTL {
276+
if m.ctx.clock.Now().Sub(evt.timestamp()) <= m.ctx.cfg.UnmatchedEventTTL {
277277
m.produce(evt, m.ctx.cfg.UnmatchedEventInterval)
278278
logger.Debug().
279279
Str("src", string(src)).
@@ -320,7 +320,7 @@ func (m *cFSM) produce(evt iConsensusEvt, delay time.Duration) {
320320
go func() {
321321
select {
322322
case <-m.close:
323-
case <-time.After(delay):
323+
case <-m.ctx.clock.After(delay):
324324
m.evtq <- evt
325325
}
326326
m.wg.Done()
@@ -457,9 +457,22 @@ func (m *cFSM) handleProposeBlockEvt(evt fsm.Event) (fsm.State, error) {
457457
if !ok {
458458
return sInvalid, errors.Wrap(ErrEvtCast, "the event is not a proposeBlkEvt")
459459
}
460-
// If the block is self proposed, skip validation
461-
if proposeBlkEvt.proposer != m.ctx.addr.RawAddress {
462-
blkHash := proposeBlkEvt.block.HashBlock()
460+
proposer, err := m.ctx.calcProposer(proposeBlkEvt.block.Height(), m.ctx.epoch.delegates)
461+
if err != nil {
462+
return sInvalid, errors.Wrap(err, "error when calculating the proposer")
463+
}
464+
blkHash := proposeBlkEvt.block.HashBlock()
465+
if proposeBlkEvt.proposer != proposer {
466+
logger.Error().
467+
Str("proposer", proposeBlkEvt.proposer).
468+
Str("actualProposer", proposer).
469+
Uint64("block", proposeBlkEvt.block.Height()).
470+
Str("hash", hex.EncodeToString(blkHash[:])).
471+
Err(err).
472+
Msg("error when validating the block proposer")
473+
validated = false
474+
} else if proposeBlkEvt.proposer != m.ctx.addr.RawAddress {
475+
// If the block is self proposed, skip validation
463476
if err := m.ctx.chain.ValidateBlock(proposeBlkEvt.block); err != nil {
464477
logger.Error().
465478
Str("proposer", proposeBlkEvt.proposer).
@@ -688,7 +701,7 @@ func (m *cFSM) produceStartRoundEvt() error {
688701
)
689702
// If we have the cached last block, we get the timestamp from it
690703
if m.ctx.round.block != nil {
691-
duration = time.Since(m.ctx.round.block.Header.Timestamp())
704+
duration = m.ctx.clock.Now().Sub(m.ctx.round.block.Header.Timestamp())
692705
} else if duration, err = m.ctx.calcDurationSinceLastBlock(); err != nil {
693706
// Otherwise, we read it from blockchain
694707
return errors.Wrap(err, "error when computing the duration since last block time")

0 commit comments

Comments
 (0)