github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/header.go (about) 1 package flow 2 3 import ( 4 "encoding/json" 5 "time" 6 7 "github.com/fxamacker/cbor/v2" 8 "github.com/vmihailenco/msgpack/v4" 9 10 cborcodec "github.com/onflow/flow-go/model/encoding/cbor" 11 "github.com/onflow/flow-go/model/fingerprint" 12 ) 13 14 // Header contains all meta-data for a block, as well as a hash representing 15 // the combined payload of the entire block. It is what consensus nodes agree 16 // on after validating the contents against the payload hash. 17 type Header struct { 18 // ChainID is a chain-specific value to prevent replay attacks. 19 ChainID ChainID 20 // ParentID is the ID of this block's parent. 21 ParentID Identifier 22 // Height is the height of the parent + 1 23 Height uint64 24 // PayloadHash is a hash of the payload of this block. 25 PayloadHash Identifier 26 // Timestamp is the time at which this block was proposed. 27 // The proposer can choose any time, so this should not be trusted as accurate. 28 Timestamp time.Time 29 // View number at which this block was proposed. 30 View uint64 31 // ParentView number at which parent block was proposed. 32 ParentView uint64 33 // ParentVoterIndices is a bitvector that represents all the voters for the parent block. 34 ParentVoterIndices []byte 35 // ParentVoterSigData is an aggregated signature over the parent block. Not a single cryptographic 36 // signature since the data represents cryptographic signatures serialized in some way (concatenation or other) 37 // A quorum certificate can be extracted from the header. 38 // This field is the SigData field of the extracted quorum certificate. 39 ParentVoterSigData []byte 40 // ProposerID is a proposer identifier for the block 41 ProposerID Identifier 42 // ProposerSigData is a signature of the proposer over the new block. Not a single cryptographic 43 // signature since the data represents cryptographic signatures serialized in some way (concatenation or other) 44 ProposerSigData []byte 45 // LastViewTC is a timeout certificate for previous view, it can be nil 46 // it has to be present if previous round ended with timeout. 47 LastViewTC *TimeoutCertificate 48 } 49 50 // Body returns the immutable part of the block header. 51 func (h Header) Body() interface{} { 52 return struct { 53 ChainID ChainID 54 ParentID Identifier 55 Height uint64 56 PayloadHash Identifier 57 Timestamp uint64 58 View uint64 59 ParentView uint64 60 ParentVoterIndices []byte 61 ParentVoterSigData []byte 62 ProposerID Identifier 63 LastViewTCID Identifier 64 }{ 65 ChainID: h.ChainID, 66 ParentID: h.ParentID, 67 Height: h.Height, 68 PayloadHash: h.PayloadHash, 69 Timestamp: uint64(h.Timestamp.UnixNano()), 70 View: h.View, 71 ParentView: h.ParentView, 72 ParentVoterIndices: h.ParentVoterIndices, 73 ParentVoterSigData: h.ParentVoterSigData, 74 ProposerID: h.ProposerID, 75 LastViewTCID: h.LastViewTC.ID(), 76 } 77 } 78 79 // QuorumCertificate returns quorum certificate that is incorporated in the block header. 80 func (h Header) QuorumCertificate() *QuorumCertificate { 81 return &QuorumCertificate{ 82 BlockID: h.ParentID, 83 View: h.ParentView, 84 SignerIndices: h.ParentVoterIndices, 85 SigData: h.ParentVoterSigData, 86 } 87 } 88 89 func (h Header) Fingerprint() []byte { 90 return fingerprint.Fingerprint(h.Body()) 91 } 92 93 // ID returns a unique ID to singularly identify the header and its block 94 // within the flow system. 95 func (h Header) ID() Identifier { 96 return MakeID(h) 97 } 98 99 // Checksum returns the checksum of the header. 100 func (h Header) Checksum() Identifier { 101 return MakeID(h) 102 } 103 104 // MarshalJSON makes sure the timestamp is encoded in UTC. 105 func (h Header) MarshalJSON() ([]byte, error) { 106 107 // NOTE: this is just a sanity check to make sure that we don't get 108 // different encodings if someone forgets to use UTC timestamps 109 if h.Timestamp.Location() != time.UTC { 110 h.Timestamp = h.Timestamp.UTC() 111 } 112 113 // we use an alias to avoid endless recursion; the alias will not have the 114 // marshal function and encode like a raw header 115 type Encodable Header 116 return json.Marshal(struct { 117 Encodable 118 ID string 119 }{ 120 Encodable: Encodable(h), 121 ID: h.ID().String(), 122 }) 123 } 124 125 // UnmarshalJSON makes sure the timestamp is decoded in UTC. 126 func (h *Header) UnmarshalJSON(data []byte) error { 127 128 // we use an alias to avoid endless recursion; the alias will not have the 129 // unmarshal function and decode like a raw header 130 type Decodable *Header 131 err := json.Unmarshal(data, Decodable(h)) 132 133 // NOTE: the timezone check is not required for JSON, as it already encodes 134 // timezones, but it doesn't hurt to add it in case someone messes with the 135 // raw encoded format 136 if h.Timestamp.Location() != time.UTC { 137 h.Timestamp = h.Timestamp.UTC() 138 } 139 140 return err 141 } 142 143 // MarshalCBOR makes sure the timestamp is encoded in UTC. 144 func (h Header) MarshalCBOR() ([]byte, error) { 145 146 // NOTE: this is just a sanity check to make sure that we don't get 147 // different encodings if someone forgets to use UTC timestamps 148 if h.Timestamp.Location() != time.UTC { 149 h.Timestamp = h.Timestamp.UTC() 150 } 151 152 // we use an alias to avoid endless recursion; the alias will not have the 153 // marshal function and encode like a raw header 154 type Encodable Header 155 return cborcodec.EncMode.Marshal(Encodable(h)) 156 } 157 158 // UnmarshalCBOR makes sure the timestamp is decoded in UTC. 159 func (h *Header) UnmarshalCBOR(data []byte) error { 160 161 // we use an alias to avoid endless recursion; the alias will not have the 162 // unmarshal function and decode like a raw header 163 // NOTE: for some reason, the pointer alias works for JSON to not recurse, 164 // but msgpack will still recurse; we have to do an extra struct copy here 165 type Decodable Header 166 decodable := Decodable(*h) 167 err := cbor.Unmarshal(data, &decodable) 168 *h = Header(decodable) 169 170 // NOTE: the timezone check is not required for CBOR, as it already encodes 171 // timezones, but it doesn't hurt to add it in case someone messes with the 172 // raw encoded format 173 if h.Timestamp.Location() != time.UTC { 174 h.Timestamp = h.Timestamp.UTC() 175 } 176 177 return err 178 } 179 180 // MarshalMsgpack makes sure the timestamp is encoded in UTC. 181 func (h Header) MarshalMsgpack() ([]byte, error) { 182 183 // NOTE: this is just a sanity check to make sure that we don't get 184 // different encodings if someone forgets to use UTC timestamps 185 if h.Timestamp.Location() != time.UTC { 186 h.Timestamp = h.Timestamp.UTC() 187 } 188 189 // we use an alias to avoid endless recursion; the alias will not have the 190 // marshal function and encode like a raw header 191 type Encodable Header 192 return msgpack.Marshal(Encodable(h)) 193 } 194 195 // UnmarshalMsgpack makes sure the timestamp is decoded in UTC. 196 func (h *Header) UnmarshalMsgpack(data []byte) error { 197 198 // we use an alias to avoid endless recursion; the alias will not have the 199 // unmarshal function and decode like a raw header 200 // NOTE: for some reason, the pointer alias works for JSON to not recurse, 201 // but msgpack will still recurse; we have to do an extra struct copy here 202 type Decodable Header 203 decodable := Decodable(*h) 204 err := msgpack.Unmarshal(data, &decodable) 205 *h = Header(decodable) 206 207 // NOTE: Msgpack unmarshals timestamps with the local timezone, which means 208 // that a block ID would suddenly be different after encoding and decoding 209 // on a machine with non-UTC local time 210 if h.Timestamp.Location() != time.UTC { 211 h.Timestamp = h.Timestamp.UTC() 212 } 213 214 return err 215 }