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