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