github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/block/header.go (about) 1 package block 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "strconv" 8 9 "github.com/nspcc-dev/neo-go/pkg/core/transaction" 10 "github.com/nspcc-dev/neo-go/pkg/crypto/hash" 11 "github.com/nspcc-dev/neo-go/pkg/encoding/address" 12 "github.com/nspcc-dev/neo-go/pkg/io" 13 "github.com/nspcc-dev/neo-go/pkg/util" 14 ) 15 16 // VersionInitial is the default Neo block version. 17 const VersionInitial uint32 = 0 18 19 // Header holds the base info of a block. 20 type Header struct { 21 // Version of the block. 22 Version uint32 23 24 // hash of the previous block. 25 PrevHash util.Uint256 26 27 // Root hash of a transaction list. 28 MerkleRoot util.Uint256 29 30 // Timestamp is a millisecond-precision timestamp. 31 // The time stamp of each block must be later than the previous block's time stamp. 32 // Generally, the difference between two block's time stamps is about 15 seconds and imprecision is allowed. 33 // The height of the block must be exactly equal to the height of the previous block plus 1. 34 Timestamp uint64 35 36 // Nonce is block random number. 37 Nonce uint64 38 39 // index/height of the block 40 Index uint32 41 42 // Contract address of the next miner 43 NextConsensus util.Uint160 44 45 // Script used to validate the block 46 Script transaction.Witness 47 48 // StateRootEnabled specifies if the header contains state root. 49 StateRootEnabled bool 50 // PrevStateRoot is the state root of the previous block. 51 PrevStateRoot util.Uint256 52 // PrimaryIndex is the index of the primary consensus node for this block. 53 PrimaryIndex byte 54 55 // Hash of this block, created when binary encoded (double SHA256). 56 hash util.Uint256 57 } 58 59 // baseAux is used to marshal/unmarshal to/from JSON, it's almost the same 60 // as original Base, but with Nonce and NextConsensus fields differing and 61 // Hash added. 62 type baseAux struct { 63 Hash util.Uint256 `json:"hash"` 64 Version uint32 `json:"version"` 65 PrevHash util.Uint256 `json:"previousblockhash"` 66 MerkleRoot util.Uint256 `json:"merkleroot"` 67 Timestamp uint64 `json:"time"` 68 Nonce string `json:"nonce"` 69 Index uint32 `json:"index"` 70 NextConsensus string `json:"nextconsensus"` 71 PrimaryIndex byte `json:"primary"` 72 PrevStateRoot *util.Uint256 `json:"previousstateroot,omitempty"` 73 Witnesses []transaction.Witness `json:"witnesses"` 74 } 75 76 // Hash returns the hash of the block. 77 func (b *Header) Hash() util.Uint256 { 78 if b.hash.Equals(util.Uint256{}) { 79 b.createHash() 80 } 81 return b.hash 82 } 83 84 // DecodeBinary implements the Serializable interface. 85 func (b *Header) DecodeBinary(br *io.BinReader) { 86 b.decodeHashableFields(br) 87 witnessCount := br.ReadVarUint() 88 if br.Err == nil && witnessCount != 1 { 89 br.Err = errors.New("wrong witness count") 90 return 91 } 92 93 b.Script.DecodeBinary(br) 94 } 95 96 // EncodeBinary implements the Serializable interface. 97 func (b *Header) EncodeBinary(bw *io.BinWriter) { 98 b.encodeHashableFields(bw) 99 bw.WriteVarUint(1) 100 b.Script.EncodeBinary(bw) 101 } 102 103 // createHash creates the hash of the block. 104 // When calculating the hash value of the block, instead of processing the entire block, 105 // only the header (without the signatures) is added as an input for the hash. It differs 106 // from the complete block only in that it doesn't contain transactions, but their hashes 107 // are used for MerkleRoot hash calculation. Therefore, adding/removing/changing any 108 // transaction affects the header hash and there is no need to use the complete block for 109 // hash calculation. 110 func (b *Header) createHash() { 111 buf := io.NewBufBinWriter() 112 // No error can occur while encoding hashable fields. 113 b.encodeHashableFields(buf.BinWriter) 114 115 b.hash = hash.Sha256(buf.Bytes()) 116 } 117 118 // encodeHashableFields will only encode the fields used for hashing. 119 // see Hash() for more information about the fields. 120 func (b *Header) encodeHashableFields(bw *io.BinWriter) { 121 bw.WriteU32LE(b.Version) 122 bw.WriteBytes(b.PrevHash[:]) 123 bw.WriteBytes(b.MerkleRoot[:]) 124 bw.WriteU64LE(b.Timestamp) 125 bw.WriteU64LE(b.Nonce) 126 bw.WriteU32LE(b.Index) 127 bw.WriteB(b.PrimaryIndex) 128 bw.WriteBytes(b.NextConsensus[:]) 129 if b.StateRootEnabled { 130 bw.WriteBytes(b.PrevStateRoot[:]) 131 } 132 } 133 134 // decodeHashableFields decodes the fields used for hashing. 135 // see Hash() for more information about the fields. 136 func (b *Header) decodeHashableFields(br *io.BinReader) { 137 b.Version = br.ReadU32LE() 138 br.ReadBytes(b.PrevHash[:]) 139 br.ReadBytes(b.MerkleRoot[:]) 140 b.Timestamp = br.ReadU64LE() 141 b.Nonce = br.ReadU64LE() 142 b.Index = br.ReadU32LE() 143 b.PrimaryIndex = br.ReadB() 144 br.ReadBytes(b.NextConsensus[:]) 145 if b.StateRootEnabled { 146 br.ReadBytes(b.PrevStateRoot[:]) 147 } 148 149 // Make the hash of the block here so we dont need to do this 150 // again. 151 if br.Err == nil { 152 b.createHash() 153 } 154 } 155 156 // MarshalJSON implements the json.Marshaler interface. 157 func (b Header) MarshalJSON() ([]byte, error) { 158 aux := baseAux{ 159 Hash: b.Hash(), 160 Version: b.Version, 161 PrevHash: b.PrevHash, 162 MerkleRoot: b.MerkleRoot, 163 Timestamp: b.Timestamp, 164 Nonce: fmt.Sprintf("%016X", b.Nonce), 165 Index: b.Index, 166 PrimaryIndex: b.PrimaryIndex, 167 NextConsensus: address.Uint160ToString(b.NextConsensus), 168 Witnesses: []transaction.Witness{b.Script}, 169 } 170 if b.StateRootEnabled { 171 aux.PrevStateRoot = &b.PrevStateRoot 172 } 173 return json.Marshal(aux) 174 } 175 176 // UnmarshalJSON implements the json.Unmarshaler interface. 177 func (b *Header) UnmarshalJSON(data []byte) error { 178 var aux = new(baseAux) 179 var nextC util.Uint160 180 181 err := json.Unmarshal(data, aux) 182 if err != nil { 183 return err 184 } 185 186 var nonce uint64 187 if len(aux.Nonce) != 0 { 188 nonce, err = strconv.ParseUint(aux.Nonce, 16, 64) 189 if err != nil { 190 return err 191 } 192 } 193 nextC, err = address.StringToUint160(aux.NextConsensus) 194 if err != nil { 195 return err 196 } 197 if len(aux.Witnesses) != 1 { 198 return errors.New("wrong number of witnesses") 199 } 200 b.Version = aux.Version 201 b.PrevHash = aux.PrevHash 202 b.MerkleRoot = aux.MerkleRoot 203 b.Timestamp = aux.Timestamp 204 b.Nonce = nonce 205 b.Index = aux.Index 206 b.PrimaryIndex = aux.PrimaryIndex 207 b.NextConsensus = nextC 208 b.Script = aux.Witnesses[0] 209 if b.StateRootEnabled { 210 if aux.PrevStateRoot == nil { 211 return errors.New("'previousstateroot' is empty") 212 } 213 b.PrevStateRoot = *aux.PrevStateRoot 214 } 215 if !aux.Hash.Equals(b.Hash()) { 216 return errors.New("json 'hash' doesn't match block hash") 217 } 218 return nil 219 }