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