github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/wire/msggetblocks.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wire
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  
    11  	"github.com/mit-dci/lit/btcutil/chaincfg/chainhash"
    12  )
    13  
    14  // MaxBlockLocatorsPerMsg is the maximum number of block locator hashes allowed
    15  // per message.
    16  const MaxBlockLocatorsPerMsg = 500
    17  
    18  // MsgGetBlocks implements the Message interface and represents a bitcoin
    19  // getblocks message.  It is used to request a list of blocks starting after the
    20  // last known hash in the slice of block locator hashes.  The list is returned
    21  // via an inv message (MsgInv) and is limited by a specific hash to stop at or
    22  // the maximum number of blocks per message, which is currently 500.
    23  //
    24  // Set the HashStop field to the hash at which to stop and use
    25  // AddBlockLocatorHash to build up the list of block locator hashes.
    26  //
    27  // The algorithm for building the block locator hashes should be to add the
    28  // hashes in reverse order until you reach the genesis block.  In order to keep
    29  // the list of locator hashes to a reasonable number of entries, first add the
    30  // most recent 10 block hashes, then double the step each loop iteration to
    31  // exponentially decrease the number of hashes the further away from head and
    32  // closer to the genesis block you get.
    33  type MsgGetBlocks struct {
    34  	ProtocolVersion    uint32
    35  	BlockLocatorHashes []*chainhash.Hash
    36  	HashStop           chainhash.Hash
    37  }
    38  
    39  // AddBlockLocatorHash adds a new block locator hash to the message.
    40  func (msg *MsgGetBlocks) AddBlockLocatorHash(hash *chainhash.Hash) error {
    41  	if len(msg.BlockLocatorHashes)+1 > MaxBlockLocatorsPerMsg {
    42  		str := fmt.Sprintf("too many block locator hashes for message [max %v]",
    43  			MaxBlockLocatorsPerMsg)
    44  		return messageError("MsgGetBlocks.AddBlockLocatorHash", str)
    45  	}
    46  
    47  	msg.BlockLocatorHashes = append(msg.BlockLocatorHashes, hash)
    48  	return nil
    49  }
    50  
    51  // BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
    52  // This is part of the Message interface implementation.
    53  func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
    54  	err := readElement(r, &msg.ProtocolVersion)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	// Read num block locator hashes and limit to max.
    60  	count, err := ReadVarInt(r, pver)
    61  	if err != nil {
    62  		return err
    63  	}
    64  	if count > MaxBlockLocatorsPerMsg {
    65  		str := fmt.Sprintf("too many block locator hashes for message "+
    66  			"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
    67  		return messageError("MsgGetBlocks.BtcDecode", str)
    68  	}
    69  
    70  	// Create a contiguous slice of hashes to deserialize into in order to
    71  	// reduce the number of allocations.
    72  	locatorHashes := make([]chainhash.Hash, count)
    73  	msg.BlockLocatorHashes = make([]*chainhash.Hash, 0, count)
    74  	for i := uint64(0); i < count; i++ {
    75  		hash := &locatorHashes[i]
    76  		err := readElement(r, hash)
    77  		if err != nil {
    78  			return err
    79  		}
    80  		msg.AddBlockLocatorHash(hash)
    81  	}
    82  
    83  	err = readElement(r, &msg.HashStop)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	return nil
    89  }
    90  
    91  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
    92  // This is part of the Message interface implementation.
    93  func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
    94  	count := len(msg.BlockLocatorHashes)
    95  	if count > MaxBlockLocatorsPerMsg {
    96  		str := fmt.Sprintf("too many block locator hashes for message "+
    97  			"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
    98  		return messageError("MsgGetBlocks.BtcEncode", str)
    99  	}
   100  
   101  	err := writeElement(w, msg.ProtocolVersion)
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	err = WriteVarInt(w, pver, uint64(count))
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	for _, hash := range msg.BlockLocatorHashes {
   112  		err = writeElement(w, hash)
   113  		if err != nil {
   114  			return err
   115  		}
   116  	}
   117  
   118  	err = writeElement(w, &msg.HashStop)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	return nil
   124  }
   125  
   126  // Command returns the protocol command string for the message.  This is part
   127  // of the Message interface implementation.
   128  func (msg *MsgGetBlocks) Command() string {
   129  	return CmdGetBlocks
   130  }
   131  
   132  // MaxPayloadLength returns the maximum length the payload can be for the
   133  // receiver.  This is part of the Message interface implementation.
   134  func (msg *MsgGetBlocks) MaxPayloadLength(pver uint32) uint32 {
   135  	// Protocol version 4 bytes + num hashes (varInt) + max block locator
   136  	// hashes + hash stop.
   137  	return 4 + MaxVarIntPayload + (MaxBlockLocatorsPerMsg * chainhash.HashSize) + chainhash.HashSize
   138  }
   139  
   140  // NewMsgGetBlocks returns a new bitcoin getblocks message that conforms to the
   141  // Message interface using the passed parameters and defaults for the remaining
   142  // fields.
   143  func NewMsgGetBlocks(hashStop *chainhash.Hash) *MsgGetBlocks {
   144  	return &MsgGetBlocks{
   145  		ProtocolVersion:    ProtocolVersion,
   146  		BlockLocatorHashes: make([]*chainhash.Hash, 0, MaxBlockLocatorsPerMsg),
   147  		HashStop:           *hashStop,
   148  	}
   149  }