github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/core/roundstate.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "io" 21 "math/big" 22 "runtime/debug" 23 "sync" 24 25 "github.com/bigzoro/my_simplechain/common" 26 "github.com/bigzoro/my_simplechain/consensus/pbft" 27 "github.com/bigzoro/my_simplechain/rlp" 28 ) 29 30 // newRoundState creates a new roundState instance with the given view and validatorSet 31 // lockedHash and preprepare are for round change when lock exists, 32 // we need to keep a reference of preprepare in order to propose locked proposal when there is a lock and itself is the proposer 33 func newRoundState(view *pbft.View, validatorSet pbft.ValidatorSet, lockedHash common.Hash, preprepare *pbft.Preprepare, 34 prepare pbft.Conclusion, pendingRequest *pbft.Request, hasBadProposal func(hash common.Hash) bool) *roundState { 35 return &roundState{ 36 round: view.Round, 37 sequence: view.Sequence, 38 Preprepare: preprepare, 39 Prepare: prepare, 40 Prepares: newMessageSet(validatorSet), 41 Commits: newMessageSet(validatorSet), 42 lockedHash: lockedHash, 43 mu: new(sync.RWMutex), 44 pendingRequest: pendingRequest, 45 hasBadProposal: hasBadProposal, 46 } 47 } 48 49 // roundState stores the consensus state 50 type roundState struct { 51 round *big.Int 52 sequence *big.Int 53 LightPrepare *pbft.LightPreprepare 54 Preprepare *pbft.Preprepare 55 Prepare pbft.Conclusion // executed proposal 56 Prepares *messageSet 57 Commits *messageSet 58 lockedHash common.Hash 59 pendingRequest *pbft.Request 60 61 mu *sync.RWMutex 62 hasBadProposal func(hash common.Hash) bool 63 } 64 65 func (s *roundState) GetPrepareOrCommitSize() int { 66 s.mu.RLock() 67 defer s.mu.RUnlock() 68 69 result := s.Prepares.Size() + s.Commits.Size() 70 71 // find duplicate one 72 for _, m := range s.Prepares.Values() { 73 if s.Commits.Get(m.Address) != nil { 74 result-- 75 } 76 } 77 return result 78 } 79 80 func (s *roundState) Subject() *pbft.Subject { 81 s.mu.RLock() 82 defer s.mu.RUnlock() 83 84 if s.Preprepare == nil || s.Prepare == nil { 85 return nil 86 } 87 88 return &pbft.Subject{ 89 View: &pbft.View{ 90 Round: new(big.Int).Set(s.round), 91 Sequence: new(big.Int).Set(s.sequence), 92 }, 93 Pending: s.Preprepare.Proposal.PendingHash(), // pending hash of proposal 94 Digest: s.Prepare.Hash(), // hash of conclusion 95 } 96 } 97 98 func (s *roundState) SetLightPrepare(preprepare *pbft.LightPreprepare) { 99 s.mu.Lock() 100 defer s.mu.Unlock() 101 102 s.LightPrepare = preprepare 103 } 104 105 func (s *roundState) SetPreprepare(preprepare *pbft.Preprepare) { 106 s.mu.Lock() 107 defer s.mu.Unlock() 108 109 s.Preprepare = preprepare 110 } 111 112 func (s *roundState) SetPrepare(prepare pbft.Conclusion) { 113 s.mu.Lock() 114 defer s.mu.Unlock() 115 116 s.Prepare = prepare 117 } 118 119 func (s *roundState) Proposal() pbft.Proposal { 120 s.mu.RLock() 121 defer s.mu.RUnlock() 122 123 if s.Preprepare != nil { 124 return s.Preprepare.Proposal 125 } 126 return nil 127 } 128 129 // return light block proposal, 130 // return nil if the proposal is not exist or not a light proposal 131 func (s *roundState) LightProposal() pbft.LightProposal { 132 s.mu.RLock() 133 defer s.mu.RUnlock() 134 135 if s.LightPrepare != nil { 136 return s.LightPrepare.Proposal.(pbft.LightProposal) 137 } 138 return nil 139 } 140 141 func (s *roundState) Conclusion() pbft.Conclusion { 142 s.mu.RLock() 143 defer s.mu.RUnlock() 144 145 if s.Prepare != nil { 146 return s.Prepare 147 } 148 149 return nil 150 } 151 152 func (s *roundState) SetRound(r *big.Int) { 153 s.mu.Lock() 154 defer s.mu.Unlock() 155 156 s.round = new(big.Int).Set(r) 157 } 158 159 func (s *roundState) Round() *big.Int { 160 s.mu.RLock() 161 defer s.mu.RUnlock() 162 163 return s.round 164 } 165 166 func (s *roundState) SetSequence(seq *big.Int) { 167 s.mu.Lock() 168 defer s.mu.Unlock() 169 170 s.sequence = seq 171 } 172 173 func (s *roundState) Sequence() *big.Int { 174 s.mu.RLock() 175 defer s.mu.RUnlock() 176 177 return s.sequence 178 } 179 180 func (s *roundState) LockHash() { 181 s.mu.Lock() 182 defer s.mu.Unlock() 183 184 if s.Preprepare != nil { 185 s.lockedHash = s.Preprepare.Proposal.PendingHash() 186 } 187 } 188 189 func (s *roundState) UnlockHash() { 190 s.mu.Lock() 191 defer s.mu.Unlock() 192 193 s.lockedHash = common.Hash{} 194 } 195 196 func (s *roundState) IsHashLocked() bool { 197 s.mu.RLock() 198 defer s.mu.RUnlock() 199 200 if (common.Hash{}) == s.lockedHash { 201 return false 202 } 203 return !s.hasBadProposal(s.GetLockedHash()) 204 } 205 206 func (s *roundState) GetLockedHash() common.Hash { 207 s.mu.RLock() 208 defer s.mu.RUnlock() 209 210 return s.lockedHash 211 } 212 213 // The DecodeRLP method should read one value from the given 214 // Stream. It is not forbidden to read less or more, but it might 215 // be confusing. 216 func (s *roundState) DecodeRLP(stream *rlp.Stream) error { 217 debug.PrintStack() 218 var ss struct { 219 Round *big.Int 220 Sequence *big.Int 221 Preprepare *pbft.Preprepare 222 Prepares *messageSet 223 Commits *messageSet 224 lockedHash common.Hash 225 pendingRequest *pbft.Request 226 } 227 228 if err := stream.Decode(&ss); err != nil { 229 return err 230 } 231 s.round = ss.Round 232 s.sequence = ss.Sequence 233 s.Preprepare = ss.Preprepare 234 s.Prepares = ss.Prepares 235 s.Commits = ss.Commits 236 s.lockedHash = ss.lockedHash 237 s.pendingRequest = ss.pendingRequest 238 s.mu = new(sync.RWMutex) 239 240 return nil 241 } 242 243 // EncodeRLP should write the RLP encoding of its receiver to w. 244 // If the implementation is a pointer method, it may also be 245 // called for nil pointers. 246 // 247 // Implementations should generate valid RLP. The data written is 248 // not verified at the moment, but a future version might. It is 249 // recommended to write only a single value but writing multiple 250 // values or no value at all is also permitted. 251 func (s *roundState) EncodeRLP(w io.Writer) error { 252 s.mu.RLock() 253 defer s.mu.RUnlock() 254 255 return rlp.Encode(w, []interface{}{ 256 s.round, 257 s.sequence, 258 s.Preprepare, 259 s.Prepares, 260 s.Commits, 261 s.lockedHash, 262 s.pendingRequest, 263 }) 264 }