protocol.go 8.8 KB

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