Skip to content

Commit 9088583

Browse files
committed
chained rolldpos scheme
1 parent 58df69e commit 9088583

File tree

12 files changed

+944
-39
lines changed

12 files changed

+944
-39
lines changed

consensus/consensusfsm/chainedfsm.go

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package consensusfsm
2+
3+
import (
4+
"github.com/facebookgo/clock"
5+
fsm "github.com/iotexproject/go-fsm"
6+
"github.com/pkg/errors"
7+
)
8+
9+
const (
10+
// consensus states
11+
SFinalized fsm.State = "S_FINALIZED"
12+
SInvalid fsm.State = "S_INVALID"
13+
)
14+
15+
type ChainedConsensusFSM struct {
16+
*ConsensusFSM
17+
}
18+
19+
func NewChainedConsensusFSM(ctx Context, clock clock.Clock) (*ChainedConsensusFSM, error) {
20+
mm := &ConsensusFSM{
21+
evtq: make(chan *ConsensusEvent, ctx.EventChanSize()),
22+
close: make(chan interface{}),
23+
ctx: ctx,
24+
clock: clock,
25+
}
26+
cm := &ChainedConsensusFSM{
27+
ConsensusFSM: mm,
28+
}
29+
b := fsm.NewBuilder().
30+
AddInitialState(sPrepare).
31+
AddStates(
32+
sAcceptBlockProposal,
33+
sAcceptProposalEndorsement,
34+
sAcceptLockEndorsement,
35+
sAcceptPreCommitEndorsement,
36+
SInvalid,
37+
SFinalized,
38+
).
39+
AddTransition(sPrepare, ePrepare, cm.prepare, []fsm.State{
40+
sPrepare,
41+
sAcceptBlockProposal,
42+
sAcceptPreCommitEndorsement,
43+
}).
44+
AddTransition(
45+
sAcceptBlockProposal,
46+
eReceiveBlock,
47+
cm.onReceiveBlock,
48+
[]fsm.State{
49+
sAcceptBlockProposal, // proposed block invalid
50+
sAcceptProposalEndorsement, // receive valid block, jump to next step
51+
}).
52+
AddTransition(
53+
sAcceptBlockProposal,
54+
eFailedToReceiveBlock,
55+
cm.onFailedToReceiveBlock,
56+
[]fsm.State{
57+
sAcceptProposalEndorsement, // no valid block, jump to next step
58+
}).
59+
AddTransition(
60+
sAcceptProposalEndorsement,
61+
eReceiveProposalEndorsement,
62+
cm.onReceiveProposalEndorsementInAcceptProposalEndorsementState,
63+
[]fsm.State{
64+
sAcceptProposalEndorsement, // not enough endorsements
65+
sAcceptLockEndorsement, // enough endorsements
66+
}).
67+
AddTransition(
68+
sAcceptProposalEndorsement,
69+
eReceivePreCommitEndorsement,
70+
cm.onReceiveProposalEndorsementInAcceptProposalEndorsementState,
71+
[]fsm.State{
72+
sAcceptProposalEndorsement, // not enough endorsements
73+
sAcceptLockEndorsement, // enough endorsements
74+
}).
75+
AddTransition(
76+
sAcceptProposalEndorsement,
77+
eStopReceivingProposalEndorsement,
78+
cm.onStopReceivingProposalEndorsement,
79+
[]fsm.State{
80+
sAcceptLockEndorsement, // timeout, jump to next step
81+
}).
82+
AddTransition(
83+
sAcceptLockEndorsement,
84+
eReceiveProposalEndorsement,
85+
cm.onReceiveProposalEndorsementInAcceptLockEndorsementState,
86+
[]fsm.State{
87+
sAcceptLockEndorsement,
88+
},
89+
).
90+
AddTransition(
91+
sAcceptLockEndorsement,
92+
eReceiveLockEndorsement,
93+
cm.onReceiveLockEndorsement,
94+
[]fsm.State{
95+
sAcceptLockEndorsement, // not enough endorsements
96+
sAcceptPreCommitEndorsement, // reach commit agreement, jump to next step
97+
}).
98+
AddTransition(
99+
sAcceptLockEndorsement,
100+
eReceivePreCommitEndorsement,
101+
cm.onReceiveLockEndorsement,
102+
[]fsm.State{
103+
sAcceptLockEndorsement, // not enough endorsements
104+
sAcceptPreCommitEndorsement, // reach commit agreement, jump to next step
105+
}).
106+
AddTransition(
107+
sAcceptLockEndorsement,
108+
eStopReceivingLockEndorsement,
109+
cm.onStopReceivingLockEndorsement,
110+
[]fsm.State{
111+
SInvalid, // timeout, invalid
112+
}).
113+
AddTransition(
114+
sAcceptPreCommitEndorsement,
115+
eBroadcastPreCommitEndorsement,
116+
cm.onBroadcastPreCommitEndorsement,
117+
[]fsm.State{
118+
sAcceptPreCommitEndorsement,
119+
}).
120+
AddTransition(
121+
sAcceptPreCommitEndorsement,
122+
eStopReceivingPreCommitEndorsement,
123+
cm.onStopReceivingPreCommitEndorsement,
124+
[]fsm.State{
125+
SInvalid,
126+
}).
127+
AddTransition(
128+
sAcceptPreCommitEndorsement,
129+
eReceivePreCommitEndorsement,
130+
cm.onReceivePreCommitEndorsement,
131+
[]fsm.State{
132+
sAcceptPreCommitEndorsement,
133+
SFinalized, // reach consensus, start next epoch
134+
})
135+
// Add the backdoor transition so that we could unit test the transition from any given state
136+
for _, state := range consensusStates {
137+
b = b.AddTransition(state, BackdoorEvent, cm.handleBackdoorEvt, consensusStates)
138+
if state != sPrepare {
139+
b = b.AddTransition(state, eCalibrate, cm.calibrate, []fsm.State{sPrepare, state})
140+
}
141+
}
142+
m, err := b.Build()
143+
if err != nil {
144+
return nil, errors.Wrap(err, "error when building the FSM")
145+
}
146+
cm.fsm = m
147+
return cm, nil
148+
}
149+
150+
func (m *ChainedConsensusFSM) onStopReceivingLockEndorsement(evt fsm.Event) (fsm.State, error) {
151+
m.ctx.Logger().Warn("Not enough lock endorsements")
152+
153+
return m.Invalid()
154+
}
155+
156+
func (m *ChainedConsensusFSM) onStopReceivingPreCommitEndorsement(evt fsm.Event) (fsm.State, error) {
157+
m.ctx.Logger().Warn("Not enough pre-commit endorsements")
158+
159+
return m.Invalid()
160+
}
161+
162+
func (m *ChainedConsensusFSM) onReceivePreCommitEndorsement(evt fsm.Event) (fsm.State, error) {
163+
cEvt, ok := evt.(*ConsensusEvent)
164+
if !ok {
165+
return sAcceptPreCommitEndorsement, errors.Wrap(ErrEvtCast, "failed to cast to consensus event")
166+
}
167+
committed, err := m.ctx.Commit(cEvt.Data())
168+
if err != nil || !committed {
169+
return sAcceptPreCommitEndorsement, err
170+
}
171+
return SFinalized, nil
172+
}
173+
174+
func (m *ChainedConsensusFSM) Finalize() (fsm.State, error) {
175+
m.ctx.Logger().Warn("Finalized")
176+
return SFinalized, nil
177+
}
178+
179+
func (m *ChainedConsensusFSM) Invalid() (fsm.State, error) {
180+
m.ctx.Logger().Warn("Invalid")
181+
return SInvalid, nil
182+
}

consensus/consensusfsm/context.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type Context interface {
2525

2626
Logger() *zap.Logger
2727
Height() uint64
28+
Number() uint32
2829

2930
NewConsensusEvent(fsm.EventType, interface{}) *ConsensusEvent
3031
NewBackdoorEvt(fsm.State) *ConsensusEvent

consensus/consensusfsm/fsm.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ func (m *ConsensusFSM) produce(evt *ConsensusEvent, delay time.Duration) {
305305
if evt == nil {
306306
return
307307
}
308+
// m.ctx.Logger().Debug("produce event", zap.Any("event", evt.Type()), zap.Stack("stack"))
308309
_consensusEvtsMtc.WithLabelValues(string(evt.Type()), "produced").Inc()
309310
if delay > 0 {
310311
m.wg.Add(1)
@@ -328,7 +329,7 @@ func (m *ConsensusFSM) handle(evt *ConsensusEvent) error {
328329
return nil
329330
}
330331
if m.ctx.IsFutureEvent(evt) {
331-
m.ctx.Logger().Debug("future event", zap.Any("event", evt.Type()))
332+
m.ctx.Logger().Debug("future event", zap.Any("event", evt.Type()), zap.Any("eventHeight", evt.Height()), zap.Any("eventRount", evt.Round()))
332333
// TODO: find a more appropriate delay
333334
m.produce(evt, m.ctx.UnmatchedEventInterval(evt.Height()))
334335
_consensusEvtsMtc.WithLabelValues(string(evt.Type()), "backoff").Inc()
@@ -397,10 +398,10 @@ func (m *ConsensusFSM) calibrate(evt fsm.Event) (fsm.State, error) {
397398

398399
func (m *ConsensusFSM) prepare(evt fsm.Event) (fsm.State, error) {
399400
if err := m.ctx.Prepare(); err != nil {
400-
m.ctx.Logger().Error("Error during prepare", zap.Error(err))
401+
m.ctx.Logger().Error("Error during prepare", zap.Error(err), zap.Stack("stack"))
401402
return m.BackToPrepare(0)
402403
}
403-
m.ctx.Logger().Debug("Start a new round")
404+
m.ctx.Logger().Debug("Start a new round", zap.Stack("stack"))
404405
proposal, err := m.ctx.Proposal()
405406
if err != nil {
406407
m.ctx.Logger().Error("failed to generate block proposal", zap.Error(err))

0 commit comments

Comments
 (0)