// Copyright 2018 The dexon-consensus-core Authors // This file is part of the dexon-consensus-core library. // // The dexon-consensus-core 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-core 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-core library. If not, see // . package core import ( "fmt" "sync" "github.com/dexon-foundation/dexon-consensus-core/common" "github.com/dexon-foundation/dexon-consensus-core/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 ( statePrepare agreementStateType = iota stateAck stateConfirm statePass1 statePass2 ) var nullBlockHash = common.Hash{} type agreementState interface { state() agreementStateType nextState() (agreementState, error) receiveVote() error clocks() int terminate() } //----- PrepareState ----- type prepareState struct { a *agreementData } func newPrepareState(a *agreementData) *prepareState { return &prepareState{a: a} } func (s *prepareState) state() agreementStateType { return statePrepare } func (s *prepareState) clocks() int { return 0 } func (s *prepareState) terminate() {} func (s *prepareState) nextState() (agreementState, error) { hash := common.Hash{} if s.a.period == 1 { hash = s.a.blockProposer().Hash s.a.recv.ProposeBlock(hash) } else { var proposed bool _, proposed = s.a.countVote(s.a.period-1, types.VotePass) if !proposed { return nil, ErrNoEnoughVoteInPrepareState } } return newAckState(s.a), nil } func (s *prepareState) receiveVote() error { return nil } // ----- AckState ----- type ackState struct { a *agreementData } func newAckState(a *agreementData) *ackState { return &ackState{a: a} } func (s *ackState) state() agreementStateType { return stateAck } func (s *ackState) clocks() int { return 2 } func (s *ackState) terminate() {} func (s *ackState) nextState() (agreementState, error) { acked := false hash := common.Hash{} if s.a.period == 1 { acked = true } else { hash, acked = s.a.countVote(s.a.period-1, types.VotePass) } if !acked { return nil, ErrNoEnoughVoteInAckState } if hash == nullBlockHash { hash = s.a.leader.leaderBlockHash() } s.a.recv.ProposeVote(&types.Vote{ Type: types.VoteAck, BlockHash: hash, Period: s.a.period, }) return newConfirmState(s.a), nil } func (s *ackState) receiveVote() error { return nil } // ----- ConfirmState ----- type confirmState struct { a *agreementData lock sync.Mutex voted bool } func newConfirmState(a *agreementData) *confirmState { return &confirmState{ a: a, } } func (s *confirmState) state() agreementStateType { return stateConfirm } func (s *confirmState) clocks() int { return 2 } func (s *confirmState) terminate() {} func (s *confirmState) nextState() (agreementState, error) { return newPass1State(s.a), nil } func (s *confirmState) receiveVote() error { s.lock.Lock() defer s.lock.Unlock() if s.voted { return nil } hash, ok := s.a.countVote(s.a.period, types.VoteAck) if !ok { return nil } if hash != nullBlockHash { s.a.recv.ProposeVote(&types.Vote{ Type: types.VoteConfirm, BlockHash: hash, Period: s.a.period, }) s.voted = true } return nil } // ----- Pass1State ----- type pass1State struct { a *agreementData } func newPass1State(a *agreementData) *pass1State { return &pass1State{a: a} } func (s *pass1State) state() agreementStateType { return statePass1 } func (s *pass1State) clocks() int { return 0 } func (s *pass1State) terminate() {} func (s *pass1State) nextState() (agreementState, error) { voteDefault := false if vote, exist := func() (*types.Vote, bool) { s.a.votesLock.RLock() defer s.a.votesLock.RUnlock() v, e := s.a.votes[s.a.period][types.VoteConfirm][s.a.ID] return v, e }(); exist { s.a.recv.ProposeVote(&types.Vote{ Type: types.VotePass, BlockHash: vote.BlockHash, Period: s.a.period, }) } else if s.a.period == 1 { voteDefault = true } else { hash, ok := s.a.countVote(s.a.period-1, types.VotePass) if ok { if hash == nullBlockHash { s.a.recv.ProposeVote(&types.Vote{ Type: types.VotePass, BlockHash: hash, Period: s.a.period, }) } else { voteDefault = true } } else { voteDefault = true } } if voteDefault { s.a.recv.ProposeVote(&types.Vote{ Type: types.VotePass, BlockHash: s.a.defaultBlock, Period: s.a.period, }) } return newPass2State(s.a), nil } func (s *pass1State) receiveVote() error { return nil } // ----- Pass2State ----- type pass2State struct { a *agreementData lock sync.Mutex voted bool enoughPassVote chan common.Hash terminateChan chan struct{} } func newPass2State(a *agreementData) *pass2State { return &pass2State{ a: a, enoughPassVote: make(chan common.Hash, 1), terminateChan: make(chan struct{}), } } func (s *pass2State) state() agreementStateType { return statePass2 } func (s *pass2State) clocks() int { return 0 } func (s *pass2State) terminate() { s.terminateChan <- struct{}{} } func (s *pass2State) nextState() (agreementState, error) { select { case <-s.terminateChan: break case hash := <-s.enoughPassVote: s.a.votesLock.RLock() defer s.a.votesLock.RUnlock() s.a.defaultBlock = hash s.a.period++ oldBlock := s.a.blocks[s.a.ID] s.a.blocks = map[types.NodeID]*types.Block{ s.a.ID: oldBlock, } } return newPrepareState(s.a), nil } func (s *pass2State) receiveVote() error { s.lock.Lock() defer s.lock.Unlock() if s.voted { return nil } hash, ok := s.a.countVote(s.a.period, types.VotePass) if ok { s.voted = true s.enoughPassVote <- hash } return nil }