Skip to content

Commit ae176a7

Browse files
authored
Set timeouts on initBlockPropose (iotexproject#246)
* move ttls to init block propose * address comments
1 parent 9e6bcba commit ae176a7

File tree

4 files changed

+86
-60
lines changed

4 files changed

+86
-60
lines changed

config/config.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -505,12 +505,21 @@ func ValidateDispatcher(cfg *Config) error {
505505

506506
// ValidateRollDPoS validates the roll-DPoS configs
507507
func ValidateRollDPoS(cfg *Config) error {
508-
if cfg.Consensus.Scheme == RollDPoSScheme && cfg.Consensus.RollDPoS.EventChanSize <= 0 {
508+
if cfg.Consensus.Scheme != RollDPoSScheme {
509+
return nil
510+
}
511+
rollDPoS := cfg.Consensus.RollDPoS
512+
if rollDPoS.EventChanSize <= 0 {
509513
return errors.Wrap(ErrInvalidCfg, "roll-DPoS event chan size should be greater than 0")
510514
}
511-
if cfg.Consensus.Scheme == RollDPoSScheme && cfg.Consensus.RollDPoS.NumDelegates <= 0 {
515+
if rollDPoS.NumDelegates <= 0 {
512516
return errors.Wrap(ErrInvalidCfg, "roll-DPoS event delegate number should be greater than 0")
513517
}
518+
ttl := rollDPoS.AcceptCommitEndorseTTL + rollDPoS.AcceptProposeTTL + rollDPoS.AcceptProposalEndorseTTL
519+
if ttl >= rollDPoS.ProposerInterval {
520+
return errors.Wrap(ErrInvalidCfg, "roll-DPoS ttl sum is larger than proposer interval")
521+
}
522+
514523
return nil
515524
}
516525

config/config_test.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"path/filepath"
1414
"strings"
1515
"testing"
16+
"time"
1617

1718
"github.com/pkg/errors"
1819
"github.com/stretchr/testify/assert"
@@ -280,10 +281,23 @@ func TestValidateRollDPoS(t *testing.T) {
280281
cfg := Default
281282
cfg.NodeType = DelegateType
282283
cfg.Consensus.Scheme = RollDPoSScheme
283-
cfg.Consensus.RollDPoS.EventChanSize = 0
284+
285+
cfg.Consensus.RollDPoS.AcceptCommitEndorseTTL = 3 * time.Second
286+
cfg.Consensus.RollDPoS.AcceptProposalEndorseTTL = 3 * time.Second
287+
cfg.Consensus.RollDPoS.AcceptProposeTTL = 3 * time.Second
288+
cfg.Consensus.RollDPoS.ProposerInterval = 8 * time.Second
284289
err := ValidateRollDPoS(&cfg)
285290
require.NotNil(t, err)
286291
require.Equal(t, ErrInvalidCfg, errors.Cause(err))
292+
require.True(
293+
t,
294+
strings.Contains(err.Error(), "roll-DPoS ttl sum is larger than proposer interval"),
295+
)
296+
297+
cfg.Consensus.RollDPoS.EventChanSize = 0
298+
err = ValidateRollDPoS(&cfg)
299+
require.NotNil(t, err)
300+
require.Equal(t, ErrInvalidCfg, errors.Cause(err))
287301
require.True(
288302
t,
289303
strings.Contains(err.Error(), "roll-DPoS event chan size should be greater than 0"),

consensus/scheme/rolldpos/fsm.go

+21-29
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const (
4848
sEpochStart fsm.State = "S_EPOCH_START"
4949
sDKGGeneration fsm.State = "S_DKG_GENERATION"
5050
sRoundStart fsm.State = "S_ROUND_START"
51-
sInitPropose fsm.State = "S_INIT_PROPOSE"
51+
sBlockPropose fsm.State = "S_BLOCK_PROPOSE"
5252
sAcceptPropose fsm.State = "S_ACCEPT_PROPOSE"
5353
sAcceptProposalEndorse fsm.State = "S_ACCEPT_PROPOSAL_ENDROSE"
5454
sAcceptLockEndorse fsm.State = "S_ACCEPT_LOCK_ENDORSE"
@@ -58,7 +58,7 @@ const (
5858
eRollDelegates fsm.EventType = "E_ROLL_DELEGATES"
5959
eGenerateDKG fsm.EventType = "E_GENERATE_DKG"
6060
eStartRound fsm.EventType = "E_START_ROUND"
61-
eInitBlock fsm.EventType = "E_INIT_BLOCK"
61+
eInitBlockPropose fsm.EventType = "E_INIT_BLOCK_PROPOSE"
6262
eProposeBlock fsm.EventType = "E_PROPOSE_BLOCK"
6363
eProposeBlockTimeout fsm.EventType = "E_PROPOSE_BLOCK_TIMEOUT"
6464
eEndorseProposal fsm.EventType = "E_ENDORSE_PROPOSAL"
@@ -85,7 +85,7 @@ var (
8585
sEpochStart,
8686
sDKGGeneration,
8787
sRoundStart,
88-
sInitPropose,
88+
sBlockPropose,
8989
sAcceptPropose,
9090
sAcceptProposalEndorse,
9191
sAcceptLockEndorse,
@@ -113,25 +113,25 @@ func newConsensusFSM(ctx *rollDPoSCtx) (*cFSM, error) {
113113
AddStates(
114114
sDKGGeneration,
115115
sRoundStart,
116-
sInitPropose,
116+
sBlockPropose,
117117
sAcceptPropose,
118118
sAcceptProposalEndorse,
119119
sAcceptLockEndorse,
120120
sAcceptCommitEndorse,
121121
).
122122
AddTransition(sEpochStart, eRollDelegates, cm.handleRollDelegatesEvt, []fsm.State{sEpochStart, sDKGGeneration}).
123123
AddTransition(sDKGGeneration, eGenerateDKG, cm.handleGenerateDKGEvt, []fsm.State{sRoundStart}).
124-
AddTransition(sRoundStart, eStartRound, cm.handleStartRoundEvt, []fsm.State{sInitPropose}).
124+
AddTransition(sRoundStart, eStartRound, cm.handleStartRoundEvt, []fsm.State{sBlockPropose}).
125125
AddTransition(sRoundStart, eFinishEpoch, cm.handleFinishEpochEvt, []fsm.State{sEpochStart, sRoundStart}).
126-
AddTransition(sInitPropose, eInitBlock, cm.handleInitBlockEvt, []fsm.State{sAcceptPropose}).
127-
AddTransition(sInitPropose, eProposeBlockTimeout, cm.handleProposeBlockTimeout, []fsm.State{sAcceptProposalEndorse}).
126+
AddTransition(sBlockPropose, eInitBlockPropose, cm.handleInitBlockProposeEvt, []fsm.State{sAcceptPropose}).
127+
AddTransition(sBlockPropose, eProposeBlockTimeout, cm.handleProposeBlockTimeout, []fsm.State{sAcceptProposalEndorse}).
128128
AddTransition(
129129
sAcceptPropose,
130130
eProposeBlock,
131131
cm.handleProposeBlockEvt,
132132
[]fsm.State{
133133
sAcceptPropose, // proposed block invalid
134-
sAcceptProposalEndorse, // proposed block valid
134+
sAcceptProposalEndorse, // receive valid block, jump to next step
135135
}).
136136
AddTransition(
137137
sAcceptPropose,
@@ -368,14 +368,19 @@ func (m *cFSM) handleStartRoundEvt(_ fsm.Event) (fsm.State, error) {
368368
m.ctx.round.proposer = proposer
369369
m.ctx.round.timestamp = m.ctx.clock.Now()
370370

371+
m.produce(m.newCEvt(eInitBlockPropose), 0)
371372
// Setup timeout for waiting for proposed block
372-
m.produce(m.newCEvt(eInitBlock), 0)
373-
m.produce(m.newTimeoutEvt(eProposeBlockTimeout), m.ctx.cfg.AcceptProposeTTL)
373+
ttl := m.ctx.cfg.AcceptProposeTTL
374+
m.produce(m.newTimeoutEvt(eProposeBlockTimeout), ttl)
375+
ttl += m.ctx.cfg.AcceptProposalEndorseTTL
376+
m.produce(m.newTimeoutEvt(eEndorseProposalTimeout), ttl)
377+
ttl += m.ctx.cfg.AcceptCommitEndorseTTL
378+
m.produce(m.newTimeoutEvt(eEndorseLockTimeout), ttl)
374379

375-
return sInitPropose, nil
380+
return sBlockPropose, nil
376381
}
377382

378-
func (m *cFSM) handleInitBlockEvt(evt fsm.Event) (fsm.State, error) {
383+
func (m *cFSM) handleInitBlockProposeEvt(evt fsm.Event) (fsm.State, error) {
379384
log := logger.Info().
380385
Str("proposer", m.ctx.round.proposer).
381386
Uint64("height", m.ctx.round.height).
@@ -451,17 +456,10 @@ func (m *cFSM) validateProposeBlock(blk *blockchain.Block, expectedProposer stri
451456
return true
452457
}
453458

454-
func (m *cFSM) moveToAcceptProposalEndorse() (fsm.State, error) {
455-
// Setup timeout for waiting for endorse
456-
m.produce(m.newTimeoutEvt(eEndorseProposalTimeout), m.ctx.cfg.AcceptProposalEndorseTTL)
457-
return sAcceptProposalEndorse, nil
458-
}
459-
460459
func (m *cFSM) handleProposeBlockEvt(evt fsm.Event) (fsm.State, error) {
461460
if evt.Type() != eProposeBlock {
462461
return sEpochStart, errors.Errorf("invalid event type %s", evt.Type())
463462
}
464-
m.ctx.round.block = nil
465463
proposeBlkEvt, ok := evt.(*proposeBlkEvt)
466464
if !ok {
467465
return sEpochStart, errors.Wrap(ErrEvtCast, "the event is not a proposeBlkEvt")
@@ -476,7 +474,7 @@ func (m *cFSM) handleProposeBlockEvt(evt fsm.Event) (fsm.State, error) {
476474
m.ctx.round.block = proposeBlkEvt.block
477475
m.broadcastConsensusVote(m.ctx.round.block.HashBlock(), endorsement.PROPOSAL)
478476

479-
return m.moveToAcceptProposalEndorse()
477+
return sAcceptProposalEndorse, nil
480478
}
481479

482480
func (m *cFSM) handleProposeBlockTimeout(evt fsm.Event) (fsm.State, error) {
@@ -489,7 +487,7 @@ func (m *cFSM) handleProposeBlockTimeout(evt fsm.Event) (fsm.State, error) {
489487
Uint32("round", m.ctx.round.number).
490488
Msg("didn't receive the proposed block before timeout")
491489

492-
return m.moveToAcceptProposalEndorse()
490+
return sAcceptProposalEndorse, nil
493491
}
494492

495493
func (m *cFSM) isDelegateEndorsement(endorser string) bool {
@@ -530,12 +528,6 @@ func (m *cFSM) validateEndorse(
530528
return true
531529
}
532530

533-
func (m *cFSM) moveToAcceptLockEndorse() (fsm.State, error) {
534-
// Setup timeout for waiting for commit
535-
m.produce(m.newTimeoutEvt(eEndorseLockTimeout), m.ctx.cfg.AcceptCommitEndorseTTL)
536-
return sAcceptLockEndorse, nil
537-
}
538-
539531
func (m *cFSM) isProposedBlock(hash []byte) bool {
540532
if m.ctx.round.block == nil {
541533
return false
@@ -629,7 +621,7 @@ func (m *cFSM) handleEndorseProposalEvt(evt fsm.Event) (fsm.State, error) {
629621
m.ctx.round.proofOfLock = endorsementSet
630622
m.broadcastConsensusVote(endorsementSet.BlockHash(), endorsement.LOCK)
631623

632-
return m.moveToAcceptLockEndorse()
624+
return sAcceptLockEndorse, nil
633625
}
634626

635627
func (m *cFSM) handleEndorseProposalTimeout(evt fsm.Event) (fsm.State, error) {
@@ -640,7 +632,7 @@ func (m *cFSM) handleEndorseProposalTimeout(evt fsm.Event) (fsm.State, error) {
640632
Uint64("height", m.ctx.round.height).
641633
Msg("didn't collect enough proposal endorses before timeout")
642634

643-
return m.moveToAcceptLockEndorse()
635+
return sAcceptLockEndorse, nil
644636
}
645637

646638
func (m *cFSM) handleEndorseLockEvt(evt fsm.Event) (fsm.State, error) {

consensus/scheme/rolldpos/fsm_test.go

+39-28
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,21 @@ func TestStartRoundEvt(t *testing.T) {
221221
height: uint64(1),
222222
numSubEpochs: uint(1),
223223
}
224+
require := require.New(t)
224225
s, err := cfsm.handleStartRoundEvt(cfsm.newCEvt(eStartRound))
225-
require.NoError(t, err)
226-
require.Equal(t, sInitPropose, s)
227-
assert.Equal(t, uint64(0), cfsm.ctx.epoch.subEpochNum)
228-
assert.NotNil(t, cfsm.ctx.round.proposer, delegates[2])
229-
assert.NotNil(t, cfsm.ctx.round.endorsementSets, s)
230-
assert.Equal(t, eInitBlock, (<-cfsm.evtq).Type())
226+
require.NoError(err)
227+
require.Equal(sBlockPropose, s)
228+
require.Equal(uint64(0), cfsm.ctx.epoch.subEpochNum)
229+
require.NotNil(cfsm.ctx.round.proposer, delegates[2])
230+
require.NotNil(cfsm.ctx.round.endorsementSets, s)
231+
e := <-cfsm.evtq
232+
require.Equal(eInitBlockPropose, e.Type())
233+
e = <-cfsm.evtq
234+
require.Equal(eProposeBlockTimeout, e.Type())
235+
e = <-cfsm.evtq
236+
require.Equal(eEndorseProposalTimeout, e.Type())
237+
e = <-cfsm.evtq
238+
require.Equal(eEndorseLockTimeout, e.Type())
231239
})
232240
t.Run("is-not-proposer", func(t *testing.T) {
233241
ctrl := gomock.NewController(t)
@@ -244,22 +252,33 @@ func TestStartRoundEvt(t *testing.T) {
244252
height: uint64(1),
245253
numSubEpochs: uint(1),
246254
}
255+
require := require.New(t)
247256
s, err := cfsm.handleStartRoundEvt(cfsm.newCEvt(eStartRound))
248-
require.NoError(t, err)
249-
require.Equal(t, sInitPropose, s)
250-
assert.Equal(t, uint64(0), cfsm.ctx.epoch.subEpochNum)
251-
assert.NotNil(t, cfsm.ctx.round.proposer, delegates[2])
252-
assert.NotNil(t, cfsm.ctx.round.endorsementSets, s)
257+
require.NoError(err)
258+
require.Equal(sBlockPropose, s)
259+
require.Equal(uint64(0), cfsm.ctx.epoch.subEpochNum)
260+
require.NotNil(cfsm.ctx.round.proposer, delegates[2])
261+
require.NotNil(cfsm.ctx.round.endorsementSets, s)
253262
evt := <-cfsm.evtq
254-
assert.Equal(t, eInitBlock, evt.Type())
255-
s, err = cfsm.handleInitBlockEvt(evt)
256-
assert.Equal(t, sAcceptPropose, s)
257-
assert.NoError(t, err)
263+
require.Equal(eInitBlockPropose, evt.Type())
264+
s, err = cfsm.handleInitBlockProposeEvt(evt)
265+
require.Equal(sAcceptPropose, s)
266+
require.NoError(err)
258267
evt = <-cfsm.evtq
259-
assert.Equal(t, eProposeBlockTimeout, evt.Type())
268+
require.Equal(eProposeBlockTimeout, evt.Type())
260269
s, err = cfsm.handleProposeBlockTimeout(evt)
261-
assert.Equal(t, sAcceptProposalEndorse, s)
262-
assert.NoError(t, err)
270+
require.Equal(sAcceptProposalEndorse, s)
271+
require.NoError(err)
272+
evt = <-cfsm.evtq
273+
require.Equal(eEndorseProposalTimeout, evt.Type())
274+
s, err = cfsm.handleEndorseProposalTimeout(evt)
275+
require.NoError(err)
276+
require.Equal(sAcceptLockEndorse, s)
277+
evt = <-cfsm.evtq
278+
require.Equal(eEndorseLockTimeout, evt.Type())
279+
s, err = cfsm.handleEndorseLockTimeout(evt)
280+
require.NoError(err)
281+
require.Equal(sRoundStart, s)
263282
})
264283
}
265284

@@ -295,7 +314,7 @@ func TestHandleInitBlockEvt(t *testing.T) {
295314

296315
t.Run("secret-block", func(t *testing.T) {
297316
cfsm.ctx.epoch.subEpochNum = uint64(0)
298-
s, err := cfsm.handleInitBlockEvt(cfsm.newCEvt(eInitBlock))
317+
s, err := cfsm.handleInitBlockProposeEvt(cfsm.newCEvt(eInitBlockPropose))
299318
require.NoError(t, err)
300319
require.Equal(t, sAcceptPropose, s)
301320
e := <-cfsm.evtq
@@ -308,7 +327,7 @@ func TestHandleInitBlockEvt(t *testing.T) {
308327
})
309328
t.Run("normal-block", func(t *testing.T) {
310329
cfsm.ctx.epoch.subEpochNum = uint64(1)
311-
s, err := cfsm.handleInitBlockEvt(cfsm.newCEvt(eInitBlock))
330+
s, err := cfsm.handleInitBlockProposeEvt(cfsm.newCEvt(eInitBlockPropose))
312331
require.NoError(t, err)
313332
require.Equal(t, sAcceptPropose, s)
314333
e := <-cfsm.evtq
@@ -373,7 +392,6 @@ func TestHandleProposeBlockEvt(t *testing.T) {
373392
evt, ok := e.(*endorseEvt)
374393
require.True(t, ok)
375394
assert.Equal(t, eEndorseProposal, evt.Type())
376-
assert.Equal(t, eEndorseProposalTimeout, (<-cfsm.evtq).Type())
377395
})
378396

379397
t.Run("pass-validation-time-rotation", func(t *testing.T) {
@@ -468,7 +486,6 @@ func TestHandleProposeBlockEvt(t *testing.T) {
468486
evt, ok := e.(*endorseEvt)
469487
require.True(t, ok)
470488
assert.Equal(t, eEndorseProposal, evt.Type())
471-
assert.Equal(t, eEndorseProposalTimeout, (<-cfsm.evtq).Type())
472489
})
473490

474491
t.Run("invalid-proposer", func(t *testing.T) {
@@ -544,7 +561,6 @@ func TestHandleProposeBlockEvt(t *testing.T) {
544561
state, err := cfsm.handleProposeBlockTimeout(cfsm.newCEvt(eProposeBlockTimeout))
545562
assert.NoError(t, err)
546563
assert.Equal(t, sAcceptProposalEndorse, state)
547-
assert.Equal(t, eEndorseProposalTimeout, (<-cfsm.evtq).Type())
548564
})
549565
}
550566

@@ -614,7 +630,6 @@ func TestHandleProposalEndorseEvt(t *testing.T) {
614630
evt, ok := e.(*endorseEvt)
615631
require.True(t, ok)
616632
assert.Equal(t, eEndorseLock, evt.Type())
617-
assert.Equal(t, eEndorseLockTimeout, (<-cfsm.evtq).Type())
618633
})
619634

620635
t.Run("timeout", func(t *testing.T) {
@@ -641,10 +656,6 @@ func TestHandleProposalEndorseEvt(t *testing.T) {
641656
state, err := cfsm.handleEndorseProposalTimeout(cfsm.newCEvt(eEndorseProposalTimeout))
642657
assert.NoError(t, err)
643658
assert.Equal(t, sAcceptLockEndorse, state)
644-
e := <-cfsm.evtq
645-
evt, ok := e.(*timeoutEvt)
646-
require.True(t, ok)
647-
assert.Equal(t, eEndorseLockTimeout, evt.Type())
648659
})
649660
}
650661

0 commit comments

Comments
 (0)