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 }