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 }