github.com/theQRL/go-zond@v0.1.1/les/protocol.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package les 18 19 import ( 20 "crypto/ecdsa" 21 "errors" 22 "fmt" 23 "io" 24 "math/big" 25 26 "github.com/theQRL/go-zond/common" 27 "github.com/theQRL/go-zond/core/types" 28 "github.com/theQRL/go-zond/crypto" 29 vfc "github.com/theQRL/go-zond/les/vflux/client" 30 "github.com/theQRL/go-zond/p2p/enode" 31 "github.com/theQRL/go-zond/rlp" 32 ) 33 34 // Constants to match up protocol versions and messages 35 const ( 36 lpv2 = 2 37 lpv3 = 3 38 lpv4 = 4 39 ) 40 41 // Supported versions of the les protocol (first is primary) 42 var ( 43 ClientProtocolVersions = []uint{lpv2, lpv3, lpv4} 44 ServerProtocolVersions = []uint{lpv2, lpv3, lpv4} 45 ) 46 47 // ProtocolLengths is the number of implemented message corresponding to different protocol versions. 48 var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24, lpv4: 24} 49 50 const ( 51 NetworkId = 1 52 ProtocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message 53 blockSafetyMargin = 4 // safety margin applied to block ranges specified relative to head block 54 55 txIndexUnlimited = 0 // this value in the "recentTxLookup" handshake field means the entire tx index history is served 56 txIndexDisabled = 1 // this value means tx index is not served at all 57 txIndexRecentOffset = 1 // txIndexRecentOffset + N in the handshake field means then tx index of the last N blocks is supported 58 ) 59 60 // les protocol message codes 61 const ( 62 // Protocol messages inherited from LPV1 63 StatusMsg = 0x00 64 AnnounceMsg = 0x01 65 GetBlockHeadersMsg = 0x02 66 BlockHeadersMsg = 0x03 67 GetBlockBodiesMsg = 0x04 68 BlockBodiesMsg = 0x05 69 GetReceiptsMsg = 0x06 70 ReceiptsMsg = 0x07 71 GetCodeMsg = 0x0a 72 CodeMsg = 0x0b 73 // Protocol messages introduced in LPV2 74 GetProofsV2Msg = 0x0f 75 ProofsV2Msg = 0x10 76 GetHelperTrieProofsMsg = 0x11 77 HelperTrieProofsMsg = 0x12 78 SendTxV2Msg = 0x13 79 GetTxStatusMsg = 0x14 80 TxStatusMsg = 0x15 81 // Protocol messages introduced in LPV3 82 StopMsg = 0x16 83 ResumeMsg = 0x17 84 ) 85 86 // GetBlockHeadersData represents a block header query (the request ID is not included) 87 type GetBlockHeadersData struct { 88 Origin hashOrNumber // Block from which to retrieve headers 89 Amount uint64 // Maximum number of headers to retrieve 90 Skip uint64 // Blocks to skip between consecutive headers 91 Reverse bool // Query direction (false = rising towards latest, true = falling towards genesis) 92 } 93 94 // GetBlockHeadersPacket represents a block header request 95 type GetBlockHeadersPacket struct { 96 ReqID uint64 97 Query GetBlockHeadersData 98 } 99 100 // GetBlockBodiesPacket represents a block body request 101 type GetBlockBodiesPacket struct { 102 ReqID uint64 103 Hashes []common.Hash 104 } 105 106 // GetCodePacket represents a contract code request 107 type GetCodePacket struct { 108 ReqID uint64 109 Reqs []CodeReq 110 } 111 112 // GetReceiptsPacket represents a block receipts request 113 type GetReceiptsPacket struct { 114 ReqID uint64 115 Hashes []common.Hash 116 } 117 118 // GetProofsPacket represents a proof request 119 type GetProofsPacket struct { 120 ReqID uint64 121 Reqs []ProofReq 122 } 123 124 // GetHelperTrieProofsPacket represents a helper trie proof request 125 type GetHelperTrieProofsPacket struct { 126 ReqID uint64 127 Reqs []HelperTrieReq 128 } 129 130 // SendTxPacket represents a transaction propagation request 131 type SendTxPacket struct { 132 ReqID uint64 133 Txs []*types.Transaction 134 } 135 136 // GetTxStatusPacket represents a transaction status query 137 type GetTxStatusPacket struct { 138 ReqID uint64 139 Hashes []common.Hash 140 } 141 142 type requestInfo struct { 143 name string 144 maxCount uint64 145 refBasketFirst, refBasketRest float64 146 } 147 148 // reqMapping maps an LES request to one or two vflux service vector entries. 149 // If rest != -1 and the request type is used with amounts larger than one then the 150 // first one of the multi-request is mapped to first while the rest is mapped to rest. 151 type reqMapping struct { 152 first, rest int 153 } 154 155 var ( 156 // requests describes the available LES request types and their initializing amounts 157 // in the vfc.ValueTracker reference basket. Initial values are estimates 158 // based on the same values as the server's default cost estimates (reqAvgTimeCost). 159 requests = map[uint64]requestInfo{ 160 GetBlockHeadersMsg: {"GetBlockHeaders", MaxHeaderFetch, 10, 1000}, 161 GetBlockBodiesMsg: {"GetBlockBodies", MaxBodyFetch, 1, 0}, 162 GetReceiptsMsg: {"GetReceipts", MaxReceiptFetch, 1, 0}, 163 GetCodeMsg: {"GetCode", MaxCodeFetch, 1, 0}, 164 GetProofsV2Msg: {"GetProofsV2", MaxProofsFetch, 10, 0}, 165 GetHelperTrieProofsMsg: {"GetHelperTrieProofs", MaxHelperTrieProofsFetch, 10, 100}, 166 SendTxV2Msg: {"SendTxV2", MaxTxSend, 1, 0}, 167 GetTxStatusMsg: {"GetTxStatus", MaxTxStatus, 10, 0}, 168 } 169 requestList []vfc.RequestInfo 170 requestMapping map[uint32]reqMapping 171 ) 172 173 // init creates a request list and mapping between protocol message codes and vflux 174 // service vector indices. 175 func init() { 176 requestMapping = make(map[uint32]reqMapping) 177 for code, req := range requests { 178 cost := reqAvgTimeCost[code] 179 rm := reqMapping{len(requestList), -1} 180 requestList = append(requestList, vfc.RequestInfo{ 181 Name: req.name + ".first", 182 InitAmount: req.refBasketFirst, 183 InitValue: float64(cost.baseCost + cost.reqCost), 184 }) 185 if req.refBasketRest != 0 { 186 rm.rest = len(requestList) 187 requestList = append(requestList, vfc.RequestInfo{ 188 Name: req.name + ".rest", 189 InitAmount: req.refBasketRest, 190 InitValue: float64(cost.reqCost), 191 }) 192 } 193 requestMapping[uint32(code)] = rm 194 } 195 } 196 197 type errCode int 198 199 const ( 200 ErrMsgTooLarge = iota 201 ErrDecode 202 ErrInvalidMsgCode 203 ErrProtocolVersionMismatch 204 ErrNetworkIdMismatch 205 ErrGenesisBlockMismatch 206 ErrNoStatusMsg 207 ErrExtraStatusMsg 208 ErrSuspendedPeer 209 ErrUselessPeer 210 ErrRequestRejected 211 ErrUnexpectedResponse 212 ErrInvalidResponse 213 ErrTooManyTimeouts 214 ErrMissingKey 215 ErrForkIDRejected 216 ) 217 218 func (e errCode) String() string { 219 return errorToString[int(e)] 220 } 221 222 // XXX change once legacy code is out 223 var errorToString = map[int]string{ 224 ErrMsgTooLarge: "Message too long", 225 ErrDecode: "Invalid message", 226 ErrInvalidMsgCode: "Invalid message code", 227 ErrProtocolVersionMismatch: "Protocol version mismatch", 228 ErrNetworkIdMismatch: "NetworkId mismatch", 229 ErrGenesisBlockMismatch: "Genesis block mismatch", 230 ErrNoStatusMsg: "No status message", 231 ErrExtraStatusMsg: "Extra status message", 232 ErrSuspendedPeer: "Suspended peer", 233 ErrRequestRejected: "Request rejected", 234 ErrUnexpectedResponse: "Unexpected response", 235 ErrInvalidResponse: "Invalid response", 236 ErrTooManyTimeouts: "Too many request timeouts", 237 ErrMissingKey: "Key missing from list", 238 ErrForkIDRejected: "ForkID rejected", 239 } 240 241 // announceData is the network packet for the block announcements. 242 type announceData struct { 243 Hash common.Hash // Hash of one particular block being announced 244 Number uint64 // Number of one particular block being announced 245 Td *big.Int // Total difficulty of one particular block being announced 246 ReorgDepth uint64 247 Update keyValueList 248 } 249 250 // sanityCheck verifies that the values are reasonable, as a DoS protection 251 func (a *announceData) sanityCheck() error { 252 if tdlen := a.Td.BitLen(); tdlen > 100 { 253 return fmt.Errorf("too large block TD: bitlen %d", tdlen) 254 } 255 return nil 256 } 257 258 // sign adds a signature to the block announcement by the given privKey 259 func (a *announceData) sign(privKey *ecdsa.PrivateKey) { 260 rlp, _ := rlp.EncodeToBytes(blockInfo{a.Hash, a.Number, a.Td}) 261 sig, _ := crypto.Sign(crypto.Keccak256(rlp), privKey) 262 a.Update = a.Update.add("sign", sig) 263 } 264 265 // checkSignature verifies if the block announcement has a valid signature by the given pubKey 266 func (a *announceData) checkSignature(id enode.ID, update keyValueMap) error { 267 var sig []byte 268 if err := update.get("sign", &sig); err != nil { 269 return err 270 } 271 rlp, _ := rlp.EncodeToBytes(blockInfo{a.Hash, a.Number, a.Td}) 272 recPubkey, err := crypto.SigToPub(crypto.Keccak256(rlp), sig) 273 if err != nil { 274 return err 275 } 276 if id == enode.PubkeyToIDV4(recPubkey) { 277 return nil 278 } 279 return errors.New("wrong signature") 280 } 281 282 type blockInfo struct { 283 Hash common.Hash // Hash of one particular block being announced 284 Number uint64 // Number of one particular block being announced 285 Td *big.Int // Total difficulty of one particular block being announced 286 } 287 288 // hashOrNumber is a combined field for specifying an origin block. 289 type hashOrNumber struct { 290 Hash common.Hash // Block hash from which to retrieve headers (excludes Number) 291 Number uint64 // Block hash from which to retrieve headers (excludes Hash) 292 } 293 294 // EncodeRLP is a specialized encoder for hashOrNumber to encode only one of the 295 // two contained union fields. 296 func (hn *hashOrNumber) EncodeRLP(w io.Writer) error { 297 if hn.Hash == (common.Hash{}) { 298 return rlp.Encode(w, hn.Number) 299 } 300 if hn.Number != 0 { 301 return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number) 302 } 303 return rlp.Encode(w, hn.Hash) 304 } 305 306 // DecodeRLP is a specialized decoder for hashOrNumber to decode the contents 307 // into either a block hash or a block number. 308 func (hn *hashOrNumber) DecodeRLP(s *rlp.Stream) error { 309 _, size, err := s.Kind() 310 switch { 311 case err != nil: 312 return err 313 case size == 32: 314 hn.Number = 0 315 return s.Decode(&hn.Hash) 316 case size <= 8: 317 hn.Hash = common.Hash{} 318 return s.Decode(&hn.Number) 319 default: 320 return fmt.Errorf("invalid input size %d for origin", size) 321 } 322 } 323 324 // CodeData is the network response packet for a node data retrieval. 325 type CodeData []struct { 326 Value []byte 327 }