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