github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/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 }