msgmerkleblock.go raw

   1  package wire
   2  
   3  import (
   4  	"fmt"
   5  	"io"
   6  	
   7  	"github.com/p9c/p9/pkg/chainhash"
   8  )
   9  
  10  // maxFlagsPerMerkleBlock is the maximum number of flag bytes that could possibly fit into a merkle block. Since each
  11  // transaction is represented by a single bit, this is the max number of transactions per block divided by 8 bits per
  12  // byte. Then an extra one to cover partials.
  13  const maxFlagsPerMerkleBlock = maxTxPerBlock / 8
  14  
  15  // MsgMerkleBlock implements the Message interface and represents a bitcoin merkleblock message which is used to reset a
  16  // Bloom filter. This message was not added until protocol version BIP0037Version.
  17  type MsgMerkleBlock struct {
  18  	Header       BlockHeader
  19  	Transactions uint32
  20  	Hashes       []*chainhash.Hash
  21  	Flags        []byte
  22  }
  23  
  24  // AddTxHash adds a new transaction hash to the message.
  25  func (msg *MsgMerkleBlock) AddTxHash(hash *chainhash.Hash) (e error) {
  26  	if len(msg.Hashes)+1 > maxTxPerBlock {
  27  		str := fmt.Sprintf(
  28  			"too many tx hashes for message [max %v]",
  29  			maxTxPerBlock,
  30  		)
  31  		return messageError("MsgMerkleBlock.AddTxHash", str)
  32  	}
  33  	msg.Hashes = append(msg.Hashes, hash)
  34  	return nil
  35  }
  36  
  37  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. This is part of the Message interface
  38  // implementation.
  39  func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) (e error) {
  40  	if pver < BIP0037Version {
  41  		str := fmt.Sprintf(
  42  			"merkleblock message invalid for protocol "+
  43  				"version %d", pver,
  44  		)
  45  		return messageError("MsgMerkleBlock.BtcDecode", str)
  46  	}
  47  	if e = readBlockHeader(r, pver, &msg.Header); E.Chk(e) {
  48  		return
  49  	}
  50  	if e = readElement(r, &msg.Transactions); E.Chk(e) {
  51  		return
  52  	}
  53  	// Read num block locator hashes and limit to max.
  54  	var count uint64
  55  	if count, e = ReadVarInt(r, pver); E.Chk(e) {
  56  		return
  57  	}
  58  	if count > maxTxPerBlock {
  59  		str := fmt.Sprintf(
  60  			"too many transaction hashes for message "+
  61  				"[count %v, max %v]", count, maxTxPerBlock,
  62  		)
  63  		return messageError("MsgMerkleBlock.BtcDecode", str)
  64  	}
  65  	// Create a contiguous slice of hashes to deserialize into in order to reduce the number of allocations.
  66  	hashes := make([]chainhash.Hash, count)
  67  	msg.Hashes = make([]*chainhash.Hash, 0, count)
  68  	for i := uint64(0); i < count; i++ {
  69  		hash := &hashes[i]
  70  		if e = readElement(r, hash); E.Chk(e) {
  71  			return
  72  		}
  73  		if e = msg.AddTxHash(hash); E.Chk(e) {
  74  		}
  75  	}
  76  	msg.Flags, e = ReadVarBytes(
  77  		r, pver, maxFlagsPerMerkleBlock,
  78  		"merkle block flags size",
  79  	)
  80  	return
  81  }
  82  
  83  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. This is part of the Message interface
  84  // implementation.
  85  func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) (e error) {
  86  	if pver < BIP0037Version {
  87  		str := fmt.Sprintf(
  88  			"merkleblock message invalid for protocol "+
  89  				"version %d", pver,
  90  		)
  91  		return messageError("MsgMerkleBlock.BtcEncode", str)
  92  	}
  93  	// Read num transaction hashes and limit to max.
  94  	numHashes := len(msg.Hashes)
  95  	if numHashes > maxTxPerBlock {
  96  		str := fmt.Sprintf(
  97  			"too many transaction hashes for message "+
  98  				"[count %v, max %v]", numHashes, maxTxPerBlock,
  99  		)
 100  		return messageError("MsgMerkleBlock.BtcDecode", str)
 101  	}
 102  	numFlagBytes := len(msg.Flags)
 103  	if numFlagBytes > maxFlagsPerMerkleBlock {
 104  		str := fmt.Sprintf(
 105  			"too many flag bytes for message [count %v, "+
 106  				"max %v]", numFlagBytes, maxFlagsPerMerkleBlock,
 107  		)
 108  		return messageError("MsgMerkleBlock.BtcDecode", str)
 109  	}
 110  	if e = writeBlockHeader(w, pver, &msg.Header); E.Chk(e) {
 111  		return
 112  	}
 113  	e = writeElement(w, msg.Transactions)
 114  	if e != nil {
 115  		return
 116  	}
 117  	e = WriteVarInt(w, pver, uint64(numHashes))
 118  	if e != nil {
 119  		return
 120  	}
 121  	for _, hash := range msg.Hashes {
 122  		e = writeElement(w, hash)
 123  		if e != nil {
 124  			return
 125  		}
 126  	}
 127  	return WriteVarBytes(w, pver, msg.Flags)
 128  }
 129  
 130  // Command returns the protocol command string for the message.  This is part of the Message interface implementation.
 131  func (msg *MsgMerkleBlock) Command() string {
 132  	return CmdMerkleBlock
 133  }
 134  
 135  // MaxPayloadLength returns the maximum length the payload can be for the receiver. This is part of the Message
 136  // interface implementation.
 137  func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 {
 138  	return MaxBlockPayload
 139  }
 140  
 141  // NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to the Message interface. See
 142  // MsgMerkleBlock for details.
 143  func NewMsgMerkleBlock(bh *BlockHeader) *MsgMerkleBlock {
 144  	return &MsgMerkleBlock{
 145  		Header:       *bh,
 146  		Transactions: 0,
 147  		Hashes:       make([]*chainhash.Hash, 0),
 148  		Flags:        make([]byte, 0),
 149  	}
 150  }
 151