github.com/klaytn/klaytn@v1.10.2/blockchain/types/istanbul.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/types/istanbul.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package types 22 23 import ( 24 "errors" 25 "io" 26 27 "github.com/klaytn/klaytn/common" 28 "github.com/klaytn/klaytn/rlp" 29 ) 30 31 var ( 32 // IstanbulDigest represents a hash of "Istanbul practical byzantine fault tolerance" 33 // to identify whether the block is from Istanbul consensus engine 34 IstanbulDigest = common.HexToHash("0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365") 35 36 IstanbulExtraVanity = 32 // Fixed number of extra-data bytes reserved for validator vanity 37 IstanbulExtraSeal = 65 // Fixed number of extra-data bytes reserved for validator seal 38 39 // ErrInvalidIstanbulHeaderExtra is returned if the length of extra-data is less than 32 bytes 40 ErrInvalidIstanbulHeaderExtra = errors.New("invalid istanbul header extra-data") 41 ) 42 43 type IstanbulExtra struct { 44 Validators []common.Address 45 Seal []byte 46 CommittedSeal [][]byte 47 } 48 49 // EncodeRLP serializes the istanbul fields into the Klaytn RLP format. 50 func (ist *IstanbulExtra) EncodeRLP(w io.Writer) error { 51 return rlp.Encode(w, []interface{}{ 52 ist.Validators, 53 ist.Seal, 54 ist.CommittedSeal, 55 }) 56 } 57 58 // DecodeRLP implements rlp.Decoder, and load the istanbul fields from a RLP stream. 59 func (ist *IstanbulExtra) DecodeRLP(s *rlp.Stream) error { 60 var istanbulExtra struct { 61 Validators []common.Address 62 Seal []byte 63 CommittedSeal [][]byte 64 } 65 if err := s.Decode(&istanbulExtra); err != nil { 66 return err 67 } 68 ist.Validators, ist.Seal, ist.CommittedSeal = istanbulExtra.Validators, istanbulExtra.Seal, istanbulExtra.CommittedSeal 69 return nil 70 } 71 72 // ExtractIstanbulExtra extracts all values of the IstanbulExtra from the header. It returns an 73 // error if the length of the given extra-data is less than 32 bytes or the extra-data can not 74 // be decoded. 75 func ExtractIstanbulExtra(h *Header) (*IstanbulExtra, error) { 76 if len(h.Extra) < IstanbulExtraVanity { 77 return nil, ErrInvalidIstanbulHeaderExtra 78 } 79 80 var istanbulExtra *IstanbulExtra 81 err := rlp.DecodeBytes(h.Extra[IstanbulExtraVanity:], &istanbulExtra) 82 if err != nil { 83 return nil, err 84 } 85 return istanbulExtra, nil 86 } 87 88 // IstanbulFilteredHeader returns a filtered header which some information (like seal, committed seals) 89 // are clean to fulfill the Istanbul hash rules. It returns nil if the extra-data cannot be 90 // decoded/encoded by rlp. 91 func IstanbulFilteredHeader(h *Header, keepSeal bool) *Header { 92 newHeader := CopyHeader(h) 93 istanbulExtra, err := ExtractIstanbulExtra(newHeader) 94 if err != nil { 95 return nil 96 } 97 98 if !keepSeal { 99 istanbulExtra.Seal = []byte{} 100 } 101 istanbulExtra.CommittedSeal = [][]byte{} 102 103 payload, err := rlp.EncodeToBytes(&istanbulExtra) 104 if err != nil { 105 return nil 106 } 107 newHeader = SetRoundToHeader(newHeader, 0) 108 newHeader.Extra = append(newHeader.Extra[:IstanbulExtraVanity], payload...) 109 110 return newHeader 111 } 112 113 func SetRoundToHeader(h *Header, r int64) *Header { 114 h.Extra[IstanbulExtraVanity-1] = byte(r) 115 return h 116 } 117 118 func SetRoundToBlock(block *Block, r int64) *Block { 119 header := SetRoundToHeader(block.Header(), r) 120 return block.WithSeal(header) 121 }