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