github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/types/roundchange.go (about) 1 package qbfttypes 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math/big" 8 9 "github.com/electroneum/electroneum-sc/common" 10 "github.com/electroneum/electroneum-sc/consensus/istanbul" 11 istanbulcommon "github.com/electroneum/electroneum-sc/consensus/istanbul/common" 12 "github.com/electroneum/electroneum-sc/core/types" 13 "github.com/electroneum/electroneum-sc/log" 14 "github.com/electroneum/electroneum-sc/rlp" 15 ) 16 17 // ROUND-CHANGE 18 type RoundChange struct { 19 SignedRoundChangePayload 20 PreparedBlock *types.Block 21 Justification []*Prepare 22 } 23 24 func NewRoundChange(sequence *big.Int, round *big.Int, preparedRound *big.Int, preparedBlock istanbul.Proposal, hasBadProposal bool) *RoundChange { 25 roundChange := &RoundChange{ 26 SignedRoundChangePayload: SignedRoundChangePayload{ 27 CommonPayload: CommonPayload{ 28 code: RoundChangeCode, 29 Sequence: sequence, 30 Round: round, 31 }, 32 PreparedRound: preparedRound, 33 PreparedDigest: common.Hash{}, 34 }, 35 } 36 37 if preparedBlock != nil { 38 roundChange.PreparedBlock = preparedBlock.(*types.Block) 39 roundChange.PreparedDigest = preparedBlock.Hash() 40 roundChange.HasBadProposal = hasBadProposal 41 } 42 43 return roundChange 44 } 45 46 type SignedRoundChangePayload struct { 47 CommonPayload 48 PreparedRound *big.Int 49 PreparedDigest common.Hash 50 HasBadProposal bool 51 } 52 53 func (p *SignedRoundChangePayload) String() string { 54 return fmt.Sprintf("RoundChange {seq=%v, round=%v, pr=%v, pv=%v, hasBadProposal=%v}", 55 p.Sequence, p.Round, p.PreparedRound, p.PreparedDigest.Hex(), p.HasBadProposal) 56 } 57 58 func (p *SignedRoundChangePayload) EncodeRLP(w io.Writer) error { 59 var encodedPayload rlp.RawValue 60 encodedPayload, err := p.encodePayloadInternal() 61 if err != nil { 62 return err 63 } 64 65 return rlp.Encode( 66 w, 67 []interface{}{encodedPayload, p.signature}) 68 } 69 70 func (p *SignedRoundChangePayload) DecodeRLP(stream *rlp.Stream) error { 71 // Signed Payload 72 if _, err := stream.List(); err != nil { 73 log.Error("IBFT: Error List() Signed Payload", "err", err) 74 return err 75 } 76 77 // Payload 78 encodedPayload, err := stream.Raw() 79 if err != nil { 80 log.Error("IBFT: Error Raw()", "err", err) 81 return err 82 } 83 84 payloadStream := rlp.NewStream(bytes.NewReader(encodedPayload), 0) 85 86 if _, err = payloadStream.List(); err != nil { 87 log.Error("IBFT: Error List() Payload", "err", err) 88 return err 89 } 90 91 if err = payloadStream.Decode(&p.Sequence); err != nil { 92 log.Error("IBFT: Error Decode(&m.Sequence)", "err", err) 93 return err 94 } 95 if err = payloadStream.Decode(&p.Round); err != nil { 96 log.Error("IBFT: Error Decode(&m.Round)", "err", err) 97 return err 98 } 99 100 // Prepared 101 var size uint64 102 if size, err = payloadStream.List(); err != nil { 103 log.Error("IBFT: Error List() Prepared", "err", err) 104 return err 105 } 106 if size > 0 { 107 if err = payloadStream.Decode(&p.PreparedRound); err != nil { 108 log.Error("IBFT: Error Decode(&m.PreparedRound)", "err", err) 109 return err 110 } 111 if err = payloadStream.Decode(&p.PreparedDigest); err != nil { 112 log.Error("IBFT: Error Decode(&p.PreparedDigest)", "err", err) 113 return err 114 } 115 if err = payloadStream.Decode(&p.HasBadProposal); err != nil { 116 log.Error("IBFT: Error Decode(&p.HasBadProposal)", "err", err) 117 return err 118 } 119 } 120 // End Prepared 121 if err = payloadStream.ListEnd(); err != nil { 122 return err 123 } 124 125 // End Payload 126 if err = payloadStream.ListEnd(); err != nil { 127 return err 128 } 129 130 if err = stream.Decode(&p.signature); err != nil { 131 return err 132 } 133 // End SignedPayload 134 if err = stream.ListEnd(); err != nil { 135 return err 136 } 137 138 p.code = RoundChangeCode 139 140 log.Info("IBFT: Correctly decoded SignedRoundChangePayload", "p", p) 141 142 return nil 143 } 144 145 func (p *SignedRoundChangePayload) encodePayloadInternal() ([]byte, error) { 146 var prepared = []interface{}{} 147 if p.PreparedRound != nil && !common.EmptyHash(p.PreparedDigest) { 148 prepared = []interface{}{p.PreparedRound, p.PreparedDigest, p.HasBadProposal} 149 } 150 return rlp.EncodeToBytes( 151 []interface{}{ 152 p.Sequence, 153 p.Round, 154 prepared}) 155 } 156 157 func (p *SignedRoundChangePayload) EncodePayloadForSigning() ([]byte, error) { 158 var encodedPayload rlp.RawValue 159 encodedPayload, err := p.encodePayloadInternal() 160 if err != nil { 161 return nil, err 162 } 163 164 return rlp.EncodeToBytes( 165 []interface{}{ 166 p.Code(), 167 encodedPayload, 168 }) 169 } 170 171 func (m *RoundChange) EncodeRLP(w io.Writer) error { 172 var encodedPayload rlp.RawValue 173 encodedPayload, err := m.encodePayloadInternal() 174 if err != nil { 175 return err 176 } 177 178 return rlp.Encode( 179 w, 180 []interface{}{ 181 []interface{}{ 182 encodedPayload, 183 m.signature, 184 }, 185 m.PreparedBlock, m.Justification, 186 }) 187 } 188 189 func (m *RoundChange) DecodeRLP(stream *rlp.Stream) error { 190 var err error 191 192 // RoundChange Message 193 if _, err = stream.List(); err != nil { 194 return err 195 } 196 197 // Signed Payload 198 if _, err = stream.List(); err != nil { 199 log.Error("IBFT: Error List() Signed Payload", "err", err) 200 return err 201 } 202 203 // Payload 204 encodedPayload, err := stream.Raw() 205 if err != nil { 206 log.Error("IBFT: Error Raw()", "err", err) 207 return err 208 } 209 210 payloadStream := rlp.NewStream(bytes.NewReader(encodedPayload), 0) 211 212 if _, err = payloadStream.List(); err != nil { 213 log.Error("IBFT: Error List() Payload", "err", err) 214 return err 215 } 216 217 if err = payloadStream.Decode(&m.Sequence); err != nil { 218 log.Error("IBFT: Error Decode(&m.Sequence)", "err", err) 219 return err 220 } 221 if err = payloadStream.Decode(&m.Round); err != nil { 222 log.Error("IBFT: Error Decode(&m.Round)", "err", err) 223 return err 224 } 225 226 // Prepared 227 var size uint64 228 if size, err = payloadStream.List(); err != nil { 229 log.Error("IBFT: Error List() Prepared", "err", err) 230 return err 231 } 232 if size > 0 { 233 if err = payloadStream.Decode(&m.PreparedRound); err != nil { 234 log.Error("IBFT: Error Decode(&m.PreparedRound)", "err", err) 235 return err 236 } 237 if err = payloadStream.Decode(&m.PreparedDigest); err != nil { 238 log.Error("IBFT: Error Decode(&m.PreparedDigest)", "err", err) 239 return err 240 } 241 if err = payloadStream.Decode(&m.HasBadProposal); err != nil { 242 log.Error("IBFT: Error Decode(&m.HasBadProposal)", "err", err) 243 return err 244 } 245 } 246 // End Prepared 247 if err = payloadStream.ListEnd(); err != nil { 248 return err 249 } 250 251 // End Payload 252 if err = payloadStream.ListEnd(); err != nil { 253 return err 254 } 255 256 if err = stream.Decode(&m.signature); err != nil { 257 return err 258 } 259 // End SignedPayload 260 if err = stream.ListEnd(); err != nil { 261 return err 262 } 263 264 if _, size, err = stream.Kind(); err != nil { 265 log.Error("IBFT: Error Kind()", "err", err) 266 return err 267 } 268 if size == 0 { 269 if _, err = stream.Raw(); err != nil { 270 log.Error("IBFT: Error Raw()", "err", err) 271 return err 272 } 273 } else { 274 if err = stream.Decode(&m.PreparedBlock); err != nil { 275 log.Error("IBFT: Error Decode(&m.PreparedDigest)", "err", err) 276 return err 277 } 278 if m.PreparedBlock.Hash() != m.PreparedDigest { 279 log.Error("IBFT: Error m.PreparedDigest.Hash() != digest") 280 return istanbulcommon.ErrFailedDecodePreprepare 281 } 282 } 283 284 if _, size, err = stream.Kind(); err != nil { 285 log.Error("IBFT: Error Kind()", "err", err) 286 return err 287 } 288 if size == 0 { 289 if _, err = stream.Raw(); err != nil { 290 log.Error("IBFT: Error Raw()", "err", err) 291 return err 292 } 293 } else { 294 if err = stream.Decode(&m.Justification); err != nil { 295 log.Error("IBFT: Error Decode(&m.Justification)", "err", err) 296 return err 297 } 298 } 299 300 // End RoundChange Message 301 if err = stream.ListEnd(); err != nil { 302 return err 303 } 304 305 m.code = RoundChangeCode 306 307 return nil 308 }