diff options
Diffstat (limited to 'vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-state.go')
-rw-r--r-- | vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-state.go | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-state.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-state.go new file mode 100644 index 000000000..77569d549 --- /dev/null +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-state.go @@ -0,0 +1,170 @@ +// 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 +// <http://www.gnu.org/licenses/>. + +package core + +import ( + "fmt" + + "github.com/dexon-foundation/dexon-consensus/common" + "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 ( + stateInitial agreementStateType = iota + statePreCommit + stateCommit + stateForward + statePullVote +) + +var nullBlockHash = common.Hash{} +var skipBlockHash common.Hash + +func init() { + for idx := range skipBlockHash { + skipBlockHash[idx] = 0xff + } +} + +type agreementState interface { + state() agreementStateType + nextState() (agreementState, error) + clocks() int +} + +//----- 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) { + hash := s.a.recv.ProposeBlock() + s.a.lock.Lock() + defer s.a.lock.Unlock() + s.a.recv.ProposeVote(&types.Vote{ + Type: types.VoteInit, + BlockHash: hash, + Period: 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() + hash := s.a.lockValue + if hash == nullBlockHash { + hash = s.a.leader.leaderBlockHash() + } + s.a.recv.ProposeVote(&types.Vote{ + Type: types.VotePreCom, + BlockHash: hash, + Period: 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) { + hash, ok := s.a.countVote(s.a.period, types.VotePreCom) + s.a.lock.Lock() + defer s.a.lock.Unlock() + if ok && hash != skipBlockHash { + s.a.lockValue = hash + s.a.lockRound = s.a.period + } else { + hash = skipBlockHash + } + s.a.recv.ProposeVote(&types.Vote{ + Type: types.VoteCom, + BlockHash: hash, + Period: 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 +} |