blockheader.go raw

   1  package wire
   2  
   3  import (
   4  	"bytes"
   5  	"github.com/p9c/p9/pkg/fork"
   6  	"github.com/p9c/p9/pkg/forkhash"
   7  	"io"
   8  	"time"
   9  	
  10  	"github.com/p9c/p9/pkg/chainhash"
  11  )
  12  
  13  // MaxBlockHeaderPayload is the maximum number of bytes a block header can be. Version 4 bytes + Timestamp 4 bytes +
  14  // Bits 4 bytes + Nonce 4 bytes + PrevBlock and MerkleRoot hashes.
  15  const MaxBlockHeaderPayload = 16 + (chainhash.HashSize * 2)
  16  
  17  // BlockHeader defines information about a block and is used in the bitcoin block (Block) and headers (MsgHeaders)
  18  // messages.
  19  type BlockHeader struct {
  20  	// Version of the block.  This is not the same as the protocol version.
  21  	Version int32
  22  	// Hash of the previous block header in the block chain.
  23  	PrevBlock chainhash.Hash
  24  	// MerkleRoot is the Merkle tree reference to hash of all transactions for the block.
  25  	MerkleRoot chainhash.Hash
  26  	// Time the block was created. This is, unfortunately, encoded as a uint32 on the wire and therefore is limited to
  27  	// 2106.
  28  	Timestamp time.Time
  29  	// Difficulty target for the block.
  30  	Bits uint32
  31  	// Nonce used to generate the block.
  32  	Nonce uint32
  33  }
  34  
  35  // blockHeaderLen is a constant that represents the number of bytes for a block header.
  36  const blockHeaderLen = 80
  37  
  38  // BlockHash computes the block identifier hash for the given block header.
  39  func (h BlockHeader) BlockHash() (out chainhash.Hash) {
  40  	// Encode the header and double sha256 everything prior to the number of transactions. Ignore the error returns
  41  	// since there is no way the encode could fail except being out of memory which would cause a run-time panic.
  42  	buf := bytes.NewBuffer(make([]byte, 0, MaxBlockHeaderPayload))
  43  	_ = writeBlockHeader(buf, 0, &h)
  44  	out = chainhash.DoubleHashH(buf.Bytes())
  45  	return
  46  }
  47  
  48  // BlockHashWithAlgos computes the block identifier hash for the given block header. This function is additional because
  49  // the sync manager and the parallelcoin protocol only use SHA256D hashes for inventories and calculating the scrypt (or
  50  // other) hash for these blocks when requested via that route causes an 'unrequested block' error.
  51  func (h *BlockHeader) BlockHashWithAlgos(height int32) (out chainhash.Hash) {
  52  	// Encode the header and double sha256 everything prior to the number of transactions. Ignore the error returns
  53  	// since there is no way the encode could fail except being out of memory which would cause a run-time panic.
  54  	buf := bytes.NewBuffer(make([]byte, 0, MaxBlockHeaderPayload))
  55  	if e := writeBlockHeader(buf, 0, h); E.Chk(e) {
  56  		E.Ln("error writing block header to buffer", e)
  57  	}
  58  	vers := h.Version
  59  	algo := fork.GetAlgoName(vers, height)
  60  	out = forkhash.Hash(buf.Bytes(), algo, height)
  61  	// L.Prror("BlockHashWithAlgos %d %s %s %s\n", vers, algo, out)
  62  	return
  63  }
  64  
  65  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. This is part of the Message interface
  66  // implementation. See Deserialize for decoding block headers stored to disk, such as in a database, as opposed to
  67  // decoding block headers from the wire.
  68  func (h *BlockHeader) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) (e error) {
  69  	return readBlockHeader(r, pver, h)
  70  }
  71  
  72  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. This is part of the Message interface
  73  // implementation. See Serialize for encoding block headers to be stored to disk, such as in a database, as opposed to
  74  // encoding block headers for the wire.
  75  func (h *BlockHeader) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) (e error) {
  76  	return writeBlockHeader(w, pver, h)
  77  }
  78  
  79  // Deserialize decodes a block header from r into the receiver using a format that is suitable for long-term storage
  80  // such as a database while respecting the Version field.
  81  func (h *BlockHeader) Deserialize(r io.Reader) (e error) {
  82  	// At the current time, there is no difference between the wire encoding at protocol version 0 and the stable
  83  	// long-term storage format. As a result, make use of readBlockHeader.
  84  	return readBlockHeader(r, 0, h)
  85  }
  86  
  87  // Serialize encodes a block header from r into the receiver using a format that is suitable for long-term storage such
  88  // as a database while respecting the Version field.
  89  func (h *BlockHeader) Serialize(w io.Writer) (e error) {
  90  	// At the current time, there is no difference between the wire encoding at protocol version 0 and the stable
  91  	// long-term storage format. As a result, make use of writeBlockHeader.
  92  	return writeBlockHeader(w, 0, h)
  93  }
  94  
  95  // NewBlockHeader returns a new BlockHeader using the provided version, previous block hash, merkle root hash,
  96  // difficulty bits, and nonce used to generate the block with defaults for the remaining fields.
  97  func NewBlockHeader(
  98  	version int32, prevHash, merkleRootHash *chainhash.Hash,
  99  	bits uint32, nonce uint32,
 100  ) *BlockHeader {
 101  	// Limit the timestamp to one second precision since the protocol doesn't support better.
 102  	return &BlockHeader{
 103  		Version:    version,
 104  		PrevBlock:  *prevHash,
 105  		MerkleRoot: *merkleRootHash,
 106  		Timestamp:  time.Now().Truncate(time.Second),
 107  		Bits:       bits,
 108  		Nonce:      nonce,
 109  	}
 110  }
 111  
 112  // readBlockHeader reads a bitcoin block header from r. See Deserialize for decoding block headers stored to disk, such
 113  // as in a database, as opposed to decoding from the wire.
 114  func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) (e error) {
 115  	return readElements(
 116  		r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
 117  		(*uint32Time)(&bh.Timestamp), &bh.Bits, &bh.Nonce,
 118  	)
 119  }
 120  
 121  // writeBlockHeader writes a bitcoin block header to w. See Serialize for encoding block headers to be stored to disk,
 122  // such as in a database, as opposed to encoding for the wire.
 123  func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) (e error) {
 124  	sec := uint32(bh.Timestamp.Unix())
 125  	return writeElements(
 126  		w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
 127  		sec, bh.Bits, bh.Nonce,
 128  	)
 129  }
 130