github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/wire/msggetheaders.go (about)

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