github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/types.go (about) 1 // Copyright 2020 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package pbft 18 19 import ( 20 "fmt" 21 "io" 22 "math/big" 23 24 "github.com/bigzoro/my_simplechain/common" 25 "github.com/bigzoro/my_simplechain/core/types" 26 "github.com/bigzoro/my_simplechain/rlp" 27 ) 28 29 // Proposal supports retrieving height and serialized block to be used during Istanbul consensus. 30 type Proposal interface { 31 // Number retrieves the sequence number of this proposal. 32 Number() *big.Int 33 34 PendingHash() common.Hash // unexecuted block hash 35 36 EncodeRLP(w io.Writer) error 37 38 DecodeRLP(s *rlp.Stream) error 39 40 String() string 41 42 FetchMissedTxs(misses []types.MissedTx) (types.Transactions, error) 43 44 IsEmpty() bool 45 } 46 47 // Conclusion means executed Proposal 48 type Conclusion interface { 49 Proposal 50 // Hash retrieves the hash of this proposal. 51 Hash() common.Hash 52 } 53 54 // LightProposal is a Proposal without tx body 55 type LightProposal interface { 56 Proposal 57 58 TxDigests() []common.Hash 59 60 Completed() bool // return whether the proposal is completed (no missed txs) 61 62 FillMissedTxs(txs types.Transactions) error 63 } 64 65 type Request struct { 66 Proposal Proposal // always common proposal (block with all txs) 67 } 68 69 func (r *Request) TerminalString() string { 70 if r == nil { 71 return "nil" 72 } 73 return fmt.Sprintf("hash: %s, number: %d", r.Proposal.PendingHash().TerminalString(), r.Proposal.Number()) 74 } 75 76 // View includes a round number and a sequence number. 77 // Sequence is the block number we'd like to commit. 78 // Each round has a number and is composed by 3 steps: preprepare, prepare and commit. 79 // 80 // If the given block is not accepted by validators, a round change will occur 81 // and the validators start a new round with round+1. 82 type View struct { 83 Round *big.Int 84 Sequence *big.Int 85 } 86 87 // EncodeRLP serializes b into the Ethereum RLP format. 88 func (v *View) EncodeRLP(w io.Writer) error { 89 return rlp.Encode(w, []interface{}{v.Round, v.Sequence}) 90 } 91 92 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 93 func (v *View) DecodeRLP(s *rlp.Stream) error { 94 var view struct { 95 Round *big.Int 96 Sequence *big.Int 97 } 98 99 if err := s.Decode(&view); err != nil { 100 return err 101 } 102 v.Round, v.Sequence = view.Round, view.Sequence 103 return nil 104 } 105 106 func (v *View) String() string { 107 return fmt.Sprintf("{Round: %d, Sequence: %d}", v.Round.Uint64(), v.Sequence.Uint64()) 108 } 109 110 // Cmp compares v and y and returns: 111 // 112 // -1 if v < y 113 // 0 if v == y 114 // +1 if v > y 115 func (v *View) Cmp(y *View) int { 116 if v.Sequence.Cmp(y.Sequence) != 0 { 117 return v.Sequence.Cmp(y.Sequence) 118 } 119 if v.Round.Cmp(y.Round) != 0 { 120 return v.Round.Cmp(y.Round) 121 } 122 return 0 123 } 124 125 type Preprepare struct { 126 View *View 127 Proposal Proposal 128 } 129 130 // EncodeRLP serializes b into the Ethereum RLP format. 131 func (b *Preprepare) EncodeRLP(w io.Writer) error { 132 return rlp.Encode(w, []interface{}{b.View, b.Proposal}) 133 } 134 135 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 136 func (b *Preprepare) DecodeRLP(s *rlp.Stream) error { 137 var preprepare struct { 138 View *View 139 Proposal *types.Block 140 } 141 142 if err := s.Decode(&preprepare); err != nil { 143 return err 144 } 145 b.View, b.Proposal = preprepare.View, preprepare.Proposal 146 147 return nil 148 } 149 150 type LightPreprepare Preprepare 151 152 func (b *LightPreprepare) FullPreprepare() *Preprepare { 153 return &Preprepare{ 154 View: b.View, 155 Proposal: Light2Proposal(b.Proposal), 156 } 157 } 158 159 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 160 // Overwrite Decode method for light block 161 func (b *LightPreprepare) DecodeRLP(s *rlp.Stream) error { 162 var preprepare struct { 163 View *View 164 Proposal *types.LightBlock 165 } 166 167 if err := s.Decode(&preprepare); err != nil { 168 return err 169 } 170 b.View, b.Proposal = preprepare.View, preprepare.Proposal 171 172 return nil 173 } 174 175 type Subject struct { 176 View *View 177 Pending common.Hash 178 Digest common.Hash 179 } 180 181 // EncodeRLP serializes b into the Ethereum RLP format. 182 func (b *Subject) EncodeRLP(w io.Writer) error { 183 return rlp.Encode(w, []interface{}{b.View, b.Pending, b.Digest}) 184 } 185 186 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 187 func (b *Subject) DecodeRLP(s *rlp.Stream) error { 188 var subject struct { 189 View *View 190 Pending common.Hash 191 Digest common.Hash 192 } 193 194 if err := s.Decode(&subject); err != nil { 195 return err 196 } 197 b.View, b.Pending, b.Digest = subject.View, subject.Pending, subject.Digest 198 return nil 199 } 200 201 func (b *Subject) String() string { 202 return fmt.Sprintf("{View: %v, Pending:%v, Digest: %v}", b.View, b.Pending.String(), b.Digest.String()) 203 } 204 205 type MissedReq struct { 206 View *View 207 MissedTxs []types.MissedTx 208 } 209 210 func (b *MissedReq) String() string { 211 return fmt.Sprintf("{View: %v, Missed:%v}", b.View, len(b.MissedTxs)) 212 213 } 214 215 func (b *MissedReq) EncodeRLP(w io.Writer) error { 216 return rlp.Encode(w, []interface{}{b.View, b.MissedTxs}) 217 } 218 219 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 220 func (b *MissedReq) DecodeRLP(s *rlp.Stream) error { 221 var subject struct { 222 View *View 223 MissedReq []types.MissedTx 224 } 225 226 if err := s.Decode(&subject); err != nil { 227 return err 228 } 229 b.View, b.MissedTxs = subject.View, subject.MissedReq 230 return nil 231 } 232 233 type MissedResp struct { 234 View *View 235 ReqTxs types.Transactions 236 } 237 238 func (b *MissedResp) EncodeRLP(w io.Writer) error { 239 return rlp.Encode(w, []interface{}{b.View, b.ReqTxs}) 240 } 241 242 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 243 func (b *MissedResp) DecodeRLP(s *rlp.Stream) error { 244 var subject struct { 245 View *View 246 ReqTxs types.Transactions 247 } 248 249 if err := s.Decode(&subject); err != nil { 250 return err 251 } 252 b.View, b.ReqTxs = subject.View, subject.ReqTxs 253 return nil 254 } 255 256 var offsetCodec = &types.OffsetTransactionsCodec{} 257 258 func (b *MissedResp) EncodeOffset() ([]byte, error) { 259 encTxs, err := offsetCodec.EncodeToBytes(b.ReqTxs) 260 if err != nil { 261 return nil, err 262 } 263 encView, err := rlp.EncodeToBytes(b.View) 264 if err != nil { 265 return nil, err 266 } 267 return append(encTxs, encView...), nil 268 } 269 270 func (b *MissedResp) DecodeOffset(buf []byte) error { 271 var txs = new(types.Transactions) 272 n, err := offsetCodec.DecodeBytes(buf, txs) 273 if err != nil { 274 return err 275 } 276 if n >= len(buf)-1 { 277 return fmt.Errorf("view info missed") 278 } 279 var view View 280 err = rlp.DecodeBytes(buf[n:], &view) 281 if err != nil { 282 return err 283 } 284 b.View, b.ReqTxs = &view, *txs 285 return nil 286 } 287 288 // Proposal2Light change the common proposal to the light proposal 289 // return nil if proposal to block failed 290 func Proposal2Light(proposal Proposal, init bool) LightProposal { 291 block, ok := proposal.(*types.Block) 292 if !ok { 293 return nil 294 } 295 if !init { 296 return &types.LightBlock{Block: *block} 297 } 298 return types.NewLightBlock(block) 299 } 300 301 // Light2Proposal trans a light proposal to the common proposal 302 // warning: will panic if proposal is not light 303 func Light2Proposal(proposal Proposal) Proposal { 304 return &proposal.(*types.LightBlock).Block 305 }