// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package wire import ( "bytes" "io" "time" ) // BlockVersion is the current latest supported block version. const BlockVersion = 3 // Version 4 bytes + Timestamp 4 bytes + Bits 4 bytes + Nonce 4 bytes + // PrevBlock and MerkleRoot hashes. const MaxBlockHeaderPayload = 16 + (HashSize * 2) // BlockHeader defines information about a block and is used in the bitcoin // block (MsgBlock) and headers (MsgHeaders) messages. type BlockHeader struct { // Version of the block. This is not the same as the protocol version. Version int32 // Hash of the previous block in the block chain. PrevBlock ShaHash // Merkle tree reference to hash of all transactions for the block. MerkleRoot ShaHash // Time the block was created. This is, unfortunately, encoded as a // uint32 on the wire and therefore is limited to 2106. Timestamp time.Time // Difficulty target for the block. Bits uint32 // Nonce used to generate the block. Nonce uint32 } // blockHeaderLen is a constant that represents the number of bytes for a block // header. const blockHeaderLen = 80 // BlockSha computes the block identifier hash for the given block header. func (h *BlockHeader) BlockSha() (ShaHash, error) { // Encode the header and double sha256 everything prior to the number of // transactions. Ignore the error returns since there is no way the // encode could fail except being out of memory which would cause a // run-time panic. var buf bytes.Buffer _ = writeBlockHeader(&buf, 0, h) // Even though this function can't currently fail, it still returns // a potential error to help future proof the API should a failure // become possible. return DoubleSha256SH(buf.Bytes()), nil } // Deserialize decodes a block header from r into the receiver using a format // that is suitable for long-term storage such as a database while respecting // the Version field. func (h *BlockHeader) Deserialize(r io.Reader) error { // At the current time, there is no difference between the wire encoding // at protocol version 0 and the stable long-term storage format. As // a result, make use of readBlockHeader. return readBlockHeader(r, 0, h) } // Serialize encodes a block header from r into the receiver using a format // that is suitable for long-term storage such as a database while respecting // the Version field. func (h *BlockHeader) Serialize(w io.Writer) error { // At the current time, there is no difference between the wire encoding // at protocol version 0 and the stable long-term storage format. As // a result, make use of writeBlockHeader. return writeBlockHeader(w, 0, h) } // NewBlockHeader returns a new BlockHeader using the provided previous block // hash, merkle root hash, difficulty bits, and nonce used to generate the // block with defaults for the remaining fields. func NewBlockHeader(prevHash *ShaHash, merkleRootHash *ShaHash, bits uint32, nonce uint32) *BlockHeader { // Limit the timestamp to one second precision since the protocol // doesn't support better. return &BlockHeader{ Version: BlockVersion, PrevBlock: *prevHash, MerkleRoot: *merkleRootHash, Timestamp: time.Unix(time.Now().Unix(), 0), Bits: bits, Nonce: nonce, } } // readBlockHeader reads a bitcoin block header from r. See Deserialize for // decoding block headers stored to disk, such as in a database, as opposed to // decoding from the wire. func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error { var sec uint32 err := readElements(r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot, &sec, &bh.Bits, &bh.Nonce) if err != nil { return err } bh.Timestamp = time.Unix(int64(sec), 0) return nil } // writeBlockHeader writes a bitcoin block header to w. See Serialize for // encoding block headers to be stored to disk, such as in a database, as // opposed to encoding for the wire. func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { sec := uint32(bh.Timestamp.Unix()) err := writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot, sec, bh.Bits, bh.Nonce) if err != nil { return err } return nil }