aboutsummaryrefslogblamecommitdiffstats
path: root/core/agreement-state.go
blob: 56c6c274d68c0748a11bf6ccd4d424549ae36840 (plain) (tree)




















                                                                               
              















                                                                                     



                                              


                                 






                                         



                                           
                    

 

                          


                        

                                                      

 











                                                                         
 
 

                            


                        

                                                          

 





                                                                             


                                                   
                                         
                                            

                                      
          
                                       

 

                         


                        

                                                    

 








                                                                       
                
                                    
         





                                         
 
 


                           

 

                                                      

 




                                                                          
 
// 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
// <http://www.gnu.org/licenses/>.

package core

import (
    "fmt"
    "math"

    "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 (
    stateInitial agreementStateType = iota
    statePreCommit
    stateCommit
    stateForward
)

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) {
    s.a.lock.Lock()
    defer s.a.lock.Unlock()
    hash := s.a.recv.ProposeBlock()
    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 math.MaxInt32 }

func (s *forwardState) nextState() (agreementState, error) {
    return s, nil
}