6211eef7ee
This commit adds a new function which is similar to the DoubleSha256 function except it returns a ShaHash copy instead of a byte slice. It also adds a new benchmark for it. This can be a slight optimization in certain cases where the caller ultimately wants a ShaHash since it can avoid a heap allocation and additional copy to convert the result to a ShaHash (the function simply performs a type cast against the returned array which is not possible against a []byte). existing: DoubleSha256 500000 3081 ns/op 32 B/op 1 allocs/op new: DoubleSha256SH 500000 2939 ns/op 0 B/op 0 allocs/op The hashing functions for blocks and transactions have also been updated to make use of the new function since they directly return the ShaHash. The transaction change in particular is quite useful since transactions are frequently hashed and this change allows all of those hashes to avoid an additional heap allocation.
127 lines
4.2 KiB
Go
127 lines
4.2 KiB
Go
// 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
|
|
}
|