lbcd/wire/blockheader.go

133 lines
5 KiB
Go
Raw Normal View History

// Copyright (c) 2013-2016 The btcsuite developers
2013-05-08 21:31:00 +02:00
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
2013-05-08 21:31:00 +02:00
import (
"bytes"
"io"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
2013-05-08 21:31:00 +02:00
)
// MaxBlockHeaderPayload is the maximum number of bytes a block header can be.
2013-05-08 21:31:00 +02:00
// Version 4 bytes + Timestamp 4 bytes + Bits 4 bytes + Nonce 4 bytes +
Remove BlockHeader.TxnCount field. This commit removes the TxnCount field from the BlockHeader type and updates the tests accordingly. Note that this change does not affect the actual wire protocol encoding in any way. The reason the field has been removed is it really doesn't belong there even though the wire protocol wiki entry on the official bitcoin wiki implies it does. The implication is an artifact from the way the reference implementation serializes headers (MsgHeaders) messages. It includes the transaction count, which is naturally always 0 for headers, along with every header. However, in reality, a block header does not include the transaction count. This can be evidenced by looking at how a block hash is calculated. It is only up to and including the Nonce field (a total of 80 bytes). From an API standpoint, having the field as part of the BlockHeader type results in several odd cases. For example, the transaction count for MsgBlocks (the only place that actually has a real transaction count since MsgHeaders does not) is available by taking the len of the Transactions slice. As such, having the extra field in the BlockHeader is really a useless field that could potentially get out of sync and cause the encode to fail. Another example is related to deserializing a block header from the database in order to serve it in response to a getheaders (MsgGetheaders) request. If a block header is assumed to have the transaction count as a part of it, then derserializing a block header not only consumes more than the 80 bytes that actually comprise the header as stated above, but you then need to change the transaction count to 0 before sending the headers (MsgHeaders) message. So, not only are you reading and deserializing more bytes than needed, but worse, you generally have to make a copy of it so you can change the transaction count without busting cached headers. This is part 1 of #13.
2014-01-19 02:37:33 +01:00
// PrevBlock and MerkleRoot hashes.
const MaxBlockHeaderPayload = 16 + (chainhash.HashSize * 3)
2013-05-08 21:31:00 +02:00
// 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
2013-05-08 21:31:00 +02:00
// Hash of the previous block header in the block chain.
PrevBlock chainhash.Hash
2013-05-08 21:31:00 +02:00
// Merkle tree reference to hash of all transactions for the block.
MerkleRoot chainhash.Hash
2013-05-08 21:31:00 +02:00
// ClaimTrie reference to hash of ClaimTrie.
ClaimTrie chainhash.Hash
2013-05-08 21:31:00 +02:00
// 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
2013-05-08 21:31:00 +02:00
// BlockHash computes the block identifier hash for the given block header.
func (h *BlockHeader) BlockHash() chainhash.Hash {
// 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.
2016-11-16 17:04:47 +01:00
buf := bytes.NewBuffer(make([]byte, 0, MaxBlockHeaderPayload))
_ = writeBlockHeader(buf, 0, h)
return chainhash.DoubleHashH(buf.Bytes())
2013-05-08 21:31:00 +02:00
}
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
// This is part of the Message interface implementation.
// See Deserialize for decoding block headers stored to disk, such as in a
// database, as opposed to decoding block headers from the wire.
func (h *BlockHeader) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
return readBlockHeader(r, pver, h)
}
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
// This is part of the Message interface implementation.
// See Serialize for encoding block headers to be stored to disk, such as in a
// database, as opposed to encoding block headers for the wire.
func (h *BlockHeader) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
return writeBlockHeader(w, pver, h)
}
// 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 version, previous
// block hash, merkle root hash, difficulty bits, and nonce used to generate the
2013-05-08 21:31:00 +02:00
// block with defaults for the remaining fields.
func NewBlockHeader(version int32, prevHash, merkleRootHash *chainhash.Hash,
claimTrieHash *chainhash.Hash, bits uint32, nonce uint32) *BlockHeader {
2013-05-08 21:31:00 +02:00
// Limit the timestamp to one second precision since the protocol
// doesn't support better.
2013-05-08 21:31:00 +02:00
return &BlockHeader{
Version: version,
2013-05-08 21:31:00 +02:00
PrevBlock: *prevHash,
MerkleRoot: *merkleRootHash,
ClaimTrie: *claimTrieHash,
Timestamp: time.Unix(time.Now().Unix(), 0),
2013-05-08 21:31:00 +02:00
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.
2013-05-08 21:31:00 +02:00
func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
return readElements(r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
&bh.ClaimTrie, (*uint32Time)(&bh.Timestamp), &bh.Bits, &bh.Nonce)
2013-05-08 21:31:00 +02:00
}
// 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.
2013-05-08 21:31:00 +02:00
func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
sec := uint32(bh.Timestamp.Unix())
return writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
&bh.ClaimTrie, sec, bh.Bits, bh.Nonce)
2013-05-08 21:31:00 +02:00
}