github.com/lbryio/lbcd@v0.22.119/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/lbryio/lbcd/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  	return readElement(r, &msg.HashStop)
    84  }
    85  
    86  // BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
    87  // This is part of the Message interface implementation.
    88  func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
    89  	count := len(msg.BlockLocatorHashes)
    90  	if count > MaxBlockLocatorsPerMsg {
    91  		str := fmt.Sprintf("too many block locator hashes for message "+
    92  			"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
    93  		return messageError("MsgGetBlocks.BtcEncode", str)
    94  	}
    95  
    96  	err := writeElement(w, msg.ProtocolVersion)
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	err = WriteVarInt(w, pver, uint64(count))
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	for _, hash := range msg.BlockLocatorHashes {
   107  		err = writeElement(w, hash)
   108  		if err != nil {
   109  			return err
   110  		}
   111  	}
   112  
   113  	return writeElement(w, &msg.HashStop)
   114  }
   115  
   116  // Command returns the protocol command string for the message.  This is part
   117  // of the Message interface implementation.
   118  func (msg *MsgGetBlocks) Command() string {
   119  	return CmdGetBlocks
   120  }
   121  
   122  // MaxPayloadLength returns the maximum length the payload can be for the
   123  // receiver.  This is part of the Message interface implementation.
   124  func (msg *MsgGetBlocks) MaxPayloadLength(pver uint32) uint32 {
   125  	// Protocol version 4 bytes + num hashes (varInt) + max block locator
   126  	// hashes + hash stop.
   127  	return 4 + MaxVarIntPayload + (MaxBlockLocatorsPerMsg * chainhash.HashSize) + chainhash.HashSize
   128  }
   129  
   130  // NewMsgGetBlocks returns a new bitcoin getblocks message that conforms to the
   131  // Message interface using the passed parameters and defaults for the remaining
   132  // fields.
   133  func NewMsgGetBlocks(hashStop *chainhash.Hash) *MsgGetBlocks {
   134  	return &MsgGetBlocks{
   135  		ProtocolVersion:    ProtocolVersion,
   136  		BlockLocatorHashes: make([]*chainhash.Hash, 0, MaxBlockLocatorsPerMsg),
   137  		HashStop:           *hashStop,
   138  	}
   139  }