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 }