// Copyright 2018 The dexon-consensus Authors // This file is part of the dexon-consensus library. // // The dexon-consensus library is free software: you can redistribute it // and/or modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // The dexon-consensus library is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser // General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the dexon-consensus library. If not, see // . package core import ( "fmt" "github.com/dexon-foundation/dexon-consensus/core/types" ) // Errors for agreement state module. var ( ErrNoEnoughVoteInPrepareState = fmt.Errorf("no enough vote in prepare state") ErrNoEnoughVoteInAckState = fmt.Errorf("no enough vote in ack state") ) // agreementStateType is the state of agreement type agreementStateType int // agreementStateType enum. const ( stateFast agreementStateType = iota stateFastVote stateInitial statePreCommit stateCommit stateForward statePullVote stateSleep ) type agreementState interface { state() agreementStateType nextState() (agreementState, error) clocks() int } //----- FastState ----- type fastState struct { a *agreementData } func newFastState(a *agreementData) *fastState { return &fastState{a: a} } func (s *fastState) state() agreementStateType { return stateFast } func (s *fastState) clocks() int { return 0 } func (s *fastState) nextState() (agreementState, error) { if func() bool { s.a.lock.Lock() defer s.a.lock.Unlock() return s.a.isLeader }() { hash := s.a.recv.ProposeBlock() if hash != types.NullBlockHash { s.a.lock.Lock() defer s.a.lock.Unlock() s.a.recv.ProposeVote(types.NewVote(types.VoteFast, hash, s.a.period)) } } return newFastVoteState(s.a), nil } //----- FastVoteState ----- type fastVoteState struct { a *agreementData } func newFastVoteState(a *agreementData) *fastVoteState { return &fastVoteState{a: a} } func (s *fastVoteState) state() agreementStateType { return stateFastVote } func (s *fastVoteState) clocks() int { return 3 } func (s *fastVoteState) nextState() (agreementState, error) { return newInitialState(s.a), nil } //----- InitialState ----- type initialState struct { a *agreementData } func newInitialState(a *agreementData) *initialState { return &initialState{a: a} } func (s *initialState) state() agreementStateType { return stateInitial } func (s *initialState) clocks() int { return 0 } func (s *initialState) nextState() (agreementState, error) { if func() bool { s.a.lock.Lock() defer s.a.lock.Unlock() return !s.a.isLeader }() { // Leader already proposed block in fastState. hash := s.a.recv.ProposeBlock() s.a.lock.Lock() defer s.a.lock.Unlock() s.a.recv.ProposeVote(types.NewVote(types.VoteInit, hash, s.a.period)) } return newPreCommitState(s.a), nil } //----- PreCommitState ----- type preCommitState struct { a *agreementData } func newPreCommitState(a *agreementData) *preCommitState { return &preCommitState{a: a} } func (s *preCommitState) state() agreementStateType { return statePreCommit } func (s *preCommitState) clocks() int { return 2 } func (s *preCommitState) nextState() (agreementState, error) { s.a.lock.RLock() defer s.a.lock.RUnlock() if s.a.lockValue == types.SkipBlockHash || s.a.lockValue == types.NullBlockHash { hash := s.a.leader.leaderBlockHash() s.a.recv.ProposeVote(types.NewVote(types.VotePreCom, hash, s.a.period)) } else { s.a.recv.ProposeVote(types.NewVote( types.VotePreCom, s.a.lockValue, s.a.period)) } return newCommitState(s.a), nil } //----- CommitState ----- type commitState struct { a *agreementData } func newCommitState(a *agreementData) *commitState { return &commitState{a: a} } func (s *commitState) state() agreementStateType { return stateCommit } func (s *commitState) clocks() int { return 2 } func (s *commitState) nextState() (agreementState, error) { s.a.lock.Lock() defer s.a.lock.Unlock() s.a.recv.ProposeVote(types.NewVote(types.VoteCom, s.a.lockValue, s.a.period)) return newForwardState(s.a), nil } // ----- ForwardState ----- type forwardState struct { a *agreementData } func newForwardState(a *agreementData) *forwardState { return &forwardState{a: a} } func (s *forwardState) state() agreementStateType { return stateForward } func (s *forwardState) clocks() int { return 4 } func (s *forwardState) nextState() (agreementState, error) { return newPullVoteState(s.a), nil } // ----- PullVoteState ----- // pullVoteState is a special state to ensure the assumption in the consensus // algorithm that every vote will eventually arrive for all nodes. type pullVoteState struct { a *agreementData } func newPullVoteState(a *agreementData) *pullVoteState { return &pullVoteState{a: a} } func (s *pullVoteState) state() agreementStateType { return statePullVote } func (s *pullVoteState) clocks() int { return 4 } func (s *pullVoteState) nextState() (agreementState, error) { return s, nil } // ----- SleepState ----- // sleepState is a special state after BA has output and waits for restart. type sleepState struct { a *agreementData } func newSleepState(a *agreementData) *sleepState { return &sleepState{a: a} } func (s *sleepState) state() agreementStateType { return stateSleep } func (s *sleepState) clocks() int { return 65536 } func (s *sleepState) nextState() (agreementState, error) { return s, nil }