github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/roundstate.go (about)

     1  package core
     2  
     3  import (
     4  	"io"
     5  	"math/big"
     6  	"sync"
     7  
     8  	"github.com/quickchainproject/quickchain/common"
     9  	bft "github.com/quickchainproject/quickchain/consensus/dbft"
    10  	"github.com/quickchainproject/quickchain/rlp"
    11  )
    12  
    13  // newRoundState creates a new roundState instance with the given view and validatorSet
    14  // lockedHash and preprepare are for round change when lock exists,
    15  // we need to keep a reference of preprepare in order to propose locked proposal when there is a lock and itself is the proposer
    16  func newRoundState(view *bft.View, validatorSet bft.ValidatorSet, lockedHash common.Hash, preprepare *bft.Preprepare, pendingRequest *bft.Request, hasBadProposal func(hash common.Hash) bool) *roundState {
    17  	return &roundState{
    18  		round:          view.Round,
    19  		sequence:       view.Sequence,
    20  		Preprepare:     preprepare,
    21  		Prepares:       newMessageSet(validatorSet),
    22  		Commits:        newMessageSet(validatorSet),
    23  		lockedHash:     lockedHash,
    24  		mu:             new(sync.RWMutex),
    25  		pendingRequest: pendingRequest,
    26  		hasBadProposal: hasBadProposal,
    27  	}
    28  }
    29  
    30  // roundState stores the consensus state
    31  type roundState struct {
    32  	round          *big.Int
    33  	sequence       *big.Int
    34  	Preprepare     *bft.Preprepare
    35  	Prepares       *messageSet
    36  	Commits        *messageSet
    37  	lockedHash     common.Hash
    38  	pendingRequest *bft.Request
    39  
    40  	mu             *sync.RWMutex
    41  	hasBadProposal func(hash common.Hash) bool
    42  }
    43  
    44  func (s *roundState) GetPrepareOrCommitSize() int {
    45  	s.mu.RLock()
    46  	defer s.mu.RUnlock()
    47  
    48  	result := s.Prepares.Size() + s.Commits.Size()
    49  
    50  	// find duplicate one
    51  	for _, m := range s.Prepares.Values() {
    52  		if s.Commits.Get(m.Address) != nil {
    53  			result--
    54  		}
    55  	}
    56  	return result
    57  }
    58  
    59  func (s *roundState) Subject() *bft.Subject {
    60  	s.mu.RLock()
    61  	defer s.mu.RUnlock()
    62  
    63  	if s.Preprepare == nil {
    64  		return nil
    65  	}
    66  
    67  	return &bft.Subject{
    68  		View: &bft.View{
    69  			Round:    new(big.Int).Set(s.round),
    70  			Sequence: new(big.Int).Set(s.sequence),
    71  		},
    72  		Digest: s.Preprepare.Proposal.Hash(),
    73  	}
    74  }
    75  
    76  func (s *roundState) SetPreprepare(preprepare *bft.Preprepare) {
    77  	s.mu.Lock()
    78  	defer s.mu.Unlock()
    79  
    80  	s.Preprepare = preprepare
    81  }
    82  
    83  func (s *roundState) Proposal() bft.Proposal {
    84  	s.mu.RLock()
    85  	defer s.mu.RUnlock()
    86  
    87  	if s.Preprepare != nil {
    88  		return s.Preprepare.Proposal
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  func (s *roundState) SetRound(r *big.Int) {
    95  	s.mu.Lock()
    96  	defer s.mu.Unlock()
    97  
    98  	s.round = new(big.Int).Set(r)
    99  }
   100  
   101  func (s *roundState) Round() *big.Int {
   102  	s.mu.RLock()
   103  	defer s.mu.RUnlock()
   104  
   105  	return s.round
   106  }
   107  
   108  func (s *roundState) SetSequence(seq *big.Int) {
   109  	s.mu.Lock()
   110  	defer s.mu.Unlock()
   111  
   112  	s.sequence = seq
   113  }
   114  
   115  func (s *roundState) Sequence() *big.Int {
   116  	s.mu.RLock()
   117  	defer s.mu.RUnlock()
   118  
   119  	return s.sequence
   120  }
   121  
   122  func (s *roundState) LockHash() {
   123  	s.mu.Lock()
   124  	defer s.mu.Unlock()
   125  
   126  	if s.Preprepare != nil {
   127  		s.lockedHash = s.Preprepare.Proposal.Hash()
   128  	}
   129  }
   130  
   131  func (s *roundState) UnlockHash() {
   132  	s.mu.Lock()
   133  	defer s.mu.Unlock()
   134  
   135  	s.lockedHash = common.Hash{}
   136  }
   137  
   138  func (s *roundState) IsHashLocked() bool {
   139  	s.mu.RLock()
   140  	defer s.mu.RUnlock()
   141  
   142  	if common.EmptyHash(s.lockedHash) {
   143  		return false
   144  	}
   145  	return !s.hasBadProposal(s.GetLockedHash())
   146  }
   147  
   148  func (s *roundState) GetLockedHash() common.Hash {
   149  	s.mu.RLock()
   150  	defer s.mu.RUnlock()
   151  
   152  	return s.lockedHash
   153  }
   154  
   155  // The DecodeRLP method should read one value from the given
   156  // Stream. It is not forbidden to read less or more, but it might
   157  // be confusing.
   158  func (s *roundState) DecodeRLP(stream *rlp.Stream) error {
   159  	var ss struct {
   160  		Round          *big.Int
   161  		Sequence       *big.Int
   162  		Preprepare     *bft.Preprepare
   163  		Prepares       *messageSet
   164  		Commits        *messageSet
   165  		lockedHash     common.Hash
   166  		pendingRequest *bft.Request
   167  	}
   168  
   169  	if err := stream.Decode(&ss); err != nil {
   170  		return err
   171  	}
   172  	s.round = ss.Round
   173  	s.sequence = ss.Sequence
   174  	s.Preprepare = ss.Preprepare
   175  	s.Prepares = ss.Prepares
   176  	s.Commits = ss.Commits
   177  	s.lockedHash = ss.lockedHash
   178  	s.pendingRequest = ss.pendingRequest
   179  	s.mu = new(sync.RWMutex)
   180  
   181  	return nil
   182  }
   183  
   184  // EncodeRLP should write the RLP encoding of its receiver to w.
   185  // If the implementation is a pointer method, it may also be
   186  // called for nil pointers.
   187  //
   188  // Implementations should generate valid RLP. The data written is
   189  // not verified at the moment, but a future version might. It is
   190  // recommended to write only a single value but writing multiple
   191  // values or no value at all is also permitted.
   192  func (s *roundState) EncodeRLP(w io.Writer) error {
   193  	s.mu.RLock()
   194  	defer s.mu.RUnlock()
   195  
   196  	return rlp.Encode(w, []interface{}{
   197  		s.round,
   198  		s.sequence,
   199  		s.Preprepare,
   200  		s.Prepares,
   201  		s.Commits,
   202  		s.lockedHash,
   203  		s.pendingRequest,
   204  	})
   205  }