github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/consensus/istanbul/types.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 istanbul 18 19 import ( 20 "fmt" 21 "io" 22 "math/big" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/core/types" 26 "github.com/ethereum/go-ethereum/rlp" 27 ) 28 29 // UptimeEntry contains the uptime score of a validator during an epoch as well as the 30 // last block they signed on 31 type UptimeEntry struct { 32 ScoreTally uint64 33 LastSignedBlock uint64 34 } 35 36 func (u *UptimeEntry) String() string { 37 return fmt.Sprintf("UptimeEntry { scoreTally: %v, lastBlock: %v}", u.ScoreTally, u.LastSignedBlock) 38 } 39 40 // Uptime contains the latest block for which uptime metrics were accounted for. It also contains 41 // an array of Entries where the `i`th entry represents the uptime statistics of the `i`th validator 42 // in the validator set for that epoch 43 type Uptime struct { 44 LatestBlock uint64 45 Entries []UptimeEntry 46 } 47 48 // Proposal supports retrieving height and serialized block to be used during Istanbul consensus. 49 type Proposal interface { 50 // Number retrieves the sequence number of this proposal. 51 Number() *big.Int 52 53 Header() *types.Header 54 55 // Hash retrieves the hash of this block 56 Hash() common.Hash 57 58 // ParentHash retrieves the hash of this block's parent 59 ParentHash() common.Hash 60 61 EncodeRLP(w io.Writer) error 62 63 DecodeRLP(s *rlp.Stream) error 64 } 65 66 // ## Request ############################################################## 67 68 type Request struct { 69 Proposal Proposal 70 } 71 72 // EncodeRLP serializes b into the Ethereum RLP format. 73 func (b *Request) EncodeRLP(w io.Writer) error { 74 return rlp.Encode(w, []interface{}{b.Proposal}) 75 } 76 77 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 78 func (b *Request) DecodeRLP(s *rlp.Stream) error { 79 var request struct { 80 Proposal *types.Block 81 } 82 83 if err := s.Decode(&request); err != nil { 84 return err 85 } 86 87 b.Proposal = request.Proposal 88 return nil 89 } 90 91 // ## View ############################################################## 92 93 // View includes a round number and a sequence number. 94 // Sequence is the block number we'd like to commit. 95 // Each round has a number and is composed by 3 steps: preprepare, prepare and commit. 96 // 97 // If the given block is not accepted by validators, a round change will occur 98 // and the validators start a new round with round+1. 99 type View struct { 100 Round *big.Int 101 Sequence *big.Int 102 } 103 104 func (v *View) String() string { 105 if v.Round == nil || v.Sequence == nil { 106 return "Invalid" 107 } 108 return fmt.Sprintf("{Round: %d, Sequence: %d}", v.Round.Uint64(), v.Sequence.Uint64()) 109 } 110 111 // Cmp compares v and y and returns: 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 // ## RoundChangeCertificate ############################################################## 126 127 type RoundChangeCertificate struct { 128 RoundChangeMessages []Message 129 } 130 131 func (b *RoundChangeCertificate) IsEmpty() bool { 132 return len(b.RoundChangeMessages) == 0 133 } 134 135 // ## Preprepare ############################################################## 136 137 type Preprepare struct { 138 View *View 139 Proposal Proposal 140 RoundChangeCertificate RoundChangeCertificate 141 } 142 143 type PreprepareData struct { 144 View *View 145 Proposal *types.Block 146 RoundChangeCertificate RoundChangeCertificate 147 } 148 149 type PreprepareSummary struct { 150 View *View `json:"view"` 151 ProposalHash common.Hash `json:"proposalHash"` 152 RoundChangeCertificateSenders []common.Address `json:"roundChangeCertificateSenders"` 153 } 154 155 func (pp *Preprepare) HasRoundChangeCertificate() bool { 156 return !pp.RoundChangeCertificate.IsEmpty() 157 } 158 159 func (pp *Preprepare) AsData() *PreprepareData { 160 return &PreprepareData{ 161 View: pp.View, 162 Proposal: pp.Proposal.(*types.Block), 163 RoundChangeCertificate: pp.RoundChangeCertificate, 164 } 165 } 166 167 func (pp *Preprepare) Summary() *PreprepareSummary { 168 return &PreprepareSummary{ 169 View: pp.View, 170 ProposalHash: pp.Proposal.Hash(), 171 RoundChangeCertificateSenders: MapMessagesToSenders(pp.RoundChangeCertificate.RoundChangeMessages), 172 } 173 } 174 175 // RLP Encoding --------------------------------------------------------------- 176 177 // EncodeRLP serializes b into the Ethereum RLP format. 178 func (pp *Preprepare) EncodeRLP(w io.Writer) error { 179 return rlp.Encode(w, pp.AsData()) 180 } 181 182 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 183 func (pp *Preprepare) DecodeRLP(s *rlp.Stream) error { 184 var data PreprepareData 185 if err := s.Decode(&data); err != nil { 186 return err 187 } 188 pp.View, pp.Proposal, pp.RoundChangeCertificate = data.View, data.Proposal, data.RoundChangeCertificate 189 return nil 190 } 191 192 // ## PreparedCertificate ##################################################### 193 194 type PreparedCertificate struct { 195 Proposal Proposal 196 PrepareOrCommitMessages []Message 197 } 198 199 type PreparedCertificateData struct { 200 Proposal *types.Block 201 PrepareOrCommitMessages []Message 202 } 203 204 type PreparedCertificateSummary struct { 205 ProposalHash common.Hash `json:"proposalHash"` 206 PrepareSenders []common.Address `json:"prepareSenders"` 207 CommitSenders []common.Address `json:"commitSenders"` 208 } 209 210 func EmptyPreparedCertificate() PreparedCertificate { 211 emptyHeader := &types.Header{ 212 Difficulty: big.NewInt(0), 213 Number: big.NewInt(0), 214 GasLimit: 0, 215 GasUsed: 0, 216 Time: big.NewInt(0), 217 } 218 block := &types.Block{} 219 block = block.WithRandomness(&types.EmptyRandomness) 220 block = block.WithEpochSnarkData(&types.EmptyEpochSnarkData) 221 222 return PreparedCertificate{ 223 Proposal: block.WithSeal(emptyHeader), 224 PrepareOrCommitMessages: []Message{}, 225 } 226 } 227 228 func (pc *PreparedCertificate) IsEmpty() bool { 229 return len(pc.PrepareOrCommitMessages) == 0 230 } 231 232 func (pc *PreparedCertificate) AsData() *PreparedCertificateData { 233 return &PreparedCertificateData{ 234 Proposal: pc.Proposal.(*types.Block), 235 PrepareOrCommitMessages: pc.PrepareOrCommitMessages, 236 } 237 } 238 239 func (pc *PreparedCertificate) Summary() *PreparedCertificateSummary { 240 var prepareSenders, commitSenders []common.Address 241 for _, msg := range pc.PrepareOrCommitMessages { 242 if msg.Code == MsgPrepare { 243 prepareSenders = append(prepareSenders, msg.Address) 244 } else { 245 commitSenders = append(commitSenders, msg.Address) 246 } 247 } 248 249 return &PreparedCertificateSummary{ 250 ProposalHash: pc.Proposal.Hash(), 251 PrepareSenders: prepareSenders, 252 CommitSenders: commitSenders, 253 } 254 } 255 256 // RLP Encoding --------------------------------------------------------------- 257 258 // EncodeRLP serializes b into the Ethereum RLP format. 259 func (pc *PreparedCertificate) EncodeRLP(w io.Writer) error { 260 return rlp.Encode(w, pc.AsData()) 261 } 262 263 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 264 func (pc *PreparedCertificate) DecodeRLP(s *rlp.Stream) error { 265 var data PreparedCertificateData 266 if err := s.Decode(&data); err != nil { 267 return err 268 } 269 pc.PrepareOrCommitMessages, pc.Proposal = data.PrepareOrCommitMessages, data.Proposal 270 return nil 271 272 } 273 274 // ## RoundChange ############################################################# 275 276 type RoundChange struct { 277 View *View 278 PreparedCertificate PreparedCertificate 279 } 280 281 func (b *RoundChange) HasPreparedCertificate() bool { 282 return !b.PreparedCertificate.IsEmpty() 283 } 284 285 // EncodeRLP serializes b into the Ethereum RLP format. 286 func (b *RoundChange) EncodeRLP(w io.Writer) error { 287 return rlp.Encode(w, []interface{}{b.View, &b.PreparedCertificate}) 288 } 289 290 // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream. 291 func (b *RoundChange) DecodeRLP(s *rlp.Stream) error { 292 var roundChange struct { 293 View *View 294 PreparedCertificate PreparedCertificate 295 } 296 297 if err := s.Decode(&roundChange); err != nil { 298 return err 299 } 300 b.View, b.PreparedCertificate = roundChange.View, roundChange.PreparedCertificate 301 return nil 302 } 303 304 // ## Subject ################################################################# 305 306 type Subject struct { 307 View *View 308 Digest common.Hash 309 } 310 311 func (s *Subject) String() string { 312 return fmt.Sprintf("{View: %v, Digest: %v}", s.View, s.Digest.String()) 313 } 314 315 // ## CommittedSubject ################################################################# 316 317 type CommittedSubject struct { 318 Subject *Subject 319 CommittedSeal []byte 320 EpochValidatorSetSeal []byte 321 } 322 323 // ## ForwardMessage ################################################################# 324 325 type ForwardMessage struct { 326 Msg []byte 327 DestAddresses []common.Address 328 } 329 330 // ## Message ################################################################# 331 332 const ( 333 MsgPreprepare uint64 = iota 334 MsgPrepare 335 MsgCommit 336 MsgRoundChange 337 ) 338 339 type Message struct { 340 Code uint64 341 Msg []byte 342 Address common.Address // The sender address 343 Signature []byte // Signature of the Message using the private key associated with the "Address" field 344 } 345 346 // define the functions that needs to be provided for core. 347 348 func (m *Message) Sign(signingFn func(data []byte) ([]byte, error)) error { 349 // Construct and encode a message with no signature 350 payloadNoSig, err := m.PayloadNoSig() 351 if err != nil { 352 return err 353 } 354 m.Signature, err = signingFn(payloadNoSig) 355 return err 356 } 357 358 func (m *Message) FromPayload(b []byte, validateFn func([]byte, []byte) (common.Address, error)) error { 359 // Decode Message 360 err := rlp.DecodeBytes(b, &m) 361 if err != nil { 362 return err 363 } 364 365 // Validate message (on a message without Signature) 366 if validateFn != nil { 367 var payload []byte 368 payload, err = m.PayloadNoSig() 369 if err != nil { 370 return err 371 } 372 373 signed_val_addr, err := validateFn(payload, m.Signature) 374 if err != nil { 375 return err 376 } 377 if signed_val_addr != m.Address { 378 return ErrInvalidSigner 379 } 380 } 381 return nil 382 } 383 384 func (m *Message) Payload() ([]byte, error) { 385 return rlp.EncodeToBytes(m) 386 } 387 388 func (m *Message) PayloadNoSig() ([]byte, error) { 389 return rlp.EncodeToBytes(&Message{ 390 Code: m.Code, 391 Msg: m.Msg, 392 Address: m.Address, 393 Signature: []byte{}, 394 }) 395 } 396 397 func (m *Message) Decode(val interface{}) error { 398 return rlp.DecodeBytes(m.Msg, val) 399 } 400 401 func (m *Message) String() string { 402 return fmt.Sprintf("{Code: %v, Address: %v}", m.Code, m.Address.String()) 403 } 404 405 // MapMessagesToSenders map a list of Messages to the list of the sender addresses 406 func MapMessagesToSenders(messages []Message) []common.Address { 407 returnList := make([]common.Address, len(messages)) 408 409 for i, ms := range messages { 410 returnList[i] = ms.Address 411 } 412 413 return returnList 414 }