odr_requests.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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 light implements on-demand retrieval capable state and chain objects
  17. // for the Ethereum Light Client.
  18. package les
  19. import (
  20. "bytes"
  21. "encoding/binary"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/core"
  24. "github.com/ethereum/go-ethereum/core/types"
  25. "github.com/ethereum/go-ethereum/crypto"
  26. "github.com/ethereum/go-ethereum/ethdb"
  27. "github.com/ethereum/go-ethereum/light"
  28. "github.com/ethereum/go-ethereum/logger"
  29. "github.com/ethereum/go-ethereum/logger/glog"
  30. "github.com/ethereum/go-ethereum/rlp"
  31. "github.com/ethereum/go-ethereum/trie"
  32. )
  33. type LesOdrRequest interface {
  34. GetCost(*peer) uint64
  35. CanSend(*peer) bool
  36. Request(uint64, *peer) error
  37. Valid(ethdb.Database, *Msg) bool // if true, keeps the retrieved object
  38. }
  39. func LesRequest(req light.OdrRequest) LesOdrRequest {
  40. switch r := req.(type) {
  41. case *light.BlockRequest:
  42. return (*BlockRequest)(r)
  43. case *light.ReceiptsRequest:
  44. return (*ReceiptsRequest)(r)
  45. case *light.TrieRequest:
  46. return (*TrieRequest)(r)
  47. case *light.CodeRequest:
  48. return (*CodeRequest)(r)
  49. case *light.ChtRequest:
  50. return (*ChtRequest)(r)
  51. default:
  52. return nil
  53. }
  54. }
  55. // BlockRequest is the ODR request type for block bodies
  56. type BlockRequest light.BlockRequest
  57. // GetCost returns the cost of the given ODR request according to the serving
  58. // peer's cost table (implementation of LesOdrRequest)
  59. func (self *BlockRequest) GetCost(peer *peer) uint64 {
  60. return peer.GetRequestCost(GetBlockBodiesMsg, 1)
  61. }
  62. // CanSend tells if a certain peer is suitable for serving the given request
  63. func (self *BlockRequest) CanSend(peer *peer) bool {
  64. return peer.HasBlock(self.Hash, self.Number)
  65. }
  66. // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
  67. func (self *BlockRequest) Request(reqID uint64, peer *peer) error {
  68. glog.V(logger.Debug).Infof("ODR: requesting body of block %08x from peer %v", self.Hash[:4], peer.id)
  69. return peer.RequestBodies(reqID, self.GetCost(peer), []common.Hash{self.Hash})
  70. }
  71. // Valid processes an ODR request reply message from the LES network
  72. // returns true and stores results in memory if the message was a valid reply
  73. // to the request (implementation of LesOdrRequest)
  74. func (self *BlockRequest) Valid(db ethdb.Database, msg *Msg) bool {
  75. glog.V(logger.Debug).Infof("ODR: validating body of block %08x", self.Hash[:4])
  76. if msg.MsgType != MsgBlockBodies {
  77. glog.V(logger.Debug).Infof("ODR: invalid message type")
  78. return false
  79. }
  80. bodies := msg.Obj.([]*types.Body)
  81. if len(bodies) != 1 {
  82. glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(bodies))
  83. return false
  84. }
  85. body := bodies[0]
  86. header := core.GetHeader(db, self.Hash, self.Number)
  87. if header == nil {
  88. glog.V(logger.Debug).Infof("ODR: header not found for block %08x", self.Hash[:4])
  89. return false
  90. }
  91. txHash := types.DeriveSha(types.Transactions(body.Transactions))
  92. if header.TxHash != txHash {
  93. glog.V(logger.Debug).Infof("ODR: header.TxHash %08x does not match received txHash %08x", header.TxHash[:4], txHash[:4])
  94. return false
  95. }
  96. uncleHash := types.CalcUncleHash(body.Uncles)
  97. if header.UncleHash != uncleHash {
  98. glog.V(logger.Debug).Infof("ODR: header.UncleHash %08x does not match received uncleHash %08x", header.UncleHash[:4], uncleHash[:4])
  99. return false
  100. }
  101. data, err := rlp.EncodeToBytes(body)
  102. if err != nil {
  103. glog.V(logger.Debug).Infof("ODR: body RLP encode error: %v", err)
  104. return false
  105. }
  106. self.Rlp = data
  107. glog.V(logger.Debug).Infof("ODR: validation successful")
  108. return true
  109. }
  110. // ReceiptsRequest is the ODR request type for block receipts by block hash
  111. type ReceiptsRequest light.ReceiptsRequest
  112. // GetCost returns the cost of the given ODR request according to the serving
  113. // peer's cost table (implementation of LesOdrRequest)
  114. func (self *ReceiptsRequest) GetCost(peer *peer) uint64 {
  115. return peer.GetRequestCost(GetReceiptsMsg, 1)
  116. }
  117. // CanSend tells if a certain peer is suitable for serving the given request
  118. func (self *ReceiptsRequest) CanSend(peer *peer) bool {
  119. return peer.HasBlock(self.Hash, self.Number)
  120. }
  121. // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
  122. func (self *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
  123. glog.V(logger.Debug).Infof("ODR: requesting receipts for block %08x from peer %v", self.Hash[:4], peer.id)
  124. return peer.RequestReceipts(reqID, self.GetCost(peer), []common.Hash{self.Hash})
  125. }
  126. // Valid processes an ODR request reply message from the LES network
  127. // returns true and stores results in memory if the message was a valid reply
  128. // to the request (implementation of LesOdrRequest)
  129. func (self *ReceiptsRequest) Valid(db ethdb.Database, msg *Msg) bool {
  130. glog.V(logger.Debug).Infof("ODR: validating receipts for block %08x", self.Hash[:4])
  131. if msg.MsgType != MsgReceipts {
  132. glog.V(logger.Debug).Infof("ODR: invalid message type")
  133. return false
  134. }
  135. receipts := msg.Obj.([]types.Receipts)
  136. if len(receipts) != 1 {
  137. glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(receipts))
  138. return false
  139. }
  140. hash := types.DeriveSha(receipts[0])
  141. header := core.GetHeader(db, self.Hash, self.Number)
  142. if header == nil {
  143. glog.V(logger.Debug).Infof("ODR: header not found for block %08x", self.Hash[:4])
  144. return false
  145. }
  146. if !bytes.Equal(header.ReceiptHash[:], hash[:]) {
  147. glog.V(logger.Debug).Infof("ODR: header receipts hash %08x does not match calculated RLP hash %08x", header.ReceiptHash[:4], hash[:4])
  148. return false
  149. }
  150. self.Receipts = receipts[0]
  151. glog.V(logger.Debug).Infof("ODR: validation successful")
  152. return true
  153. }
  154. type ProofReq struct {
  155. BHash common.Hash
  156. AccKey, Key []byte
  157. FromLevel uint
  158. }
  159. // ODR request type for state/storage trie entries, see LesOdrRequest interface
  160. type TrieRequest light.TrieRequest
  161. // GetCost returns the cost of the given ODR request according to the serving
  162. // peer's cost table (implementation of LesOdrRequest)
  163. func (self *TrieRequest) GetCost(peer *peer) uint64 {
  164. return peer.GetRequestCost(GetProofsMsg, 1)
  165. }
  166. // CanSend tells if a certain peer is suitable for serving the given request
  167. func (self *TrieRequest) CanSend(peer *peer) bool {
  168. return peer.HasBlock(self.Id.BlockHash, self.Id.BlockNumber)
  169. }
  170. // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
  171. func (self *TrieRequest) Request(reqID uint64, peer *peer) error {
  172. glog.V(logger.Debug).Infof("ODR: requesting trie root %08x key %08x from peer %v", self.Id.Root[:4], self.Key[:4], peer.id)
  173. req := &ProofReq{
  174. BHash: self.Id.BlockHash,
  175. AccKey: self.Id.AccKey,
  176. Key: self.Key,
  177. }
  178. return peer.RequestProofs(reqID, self.GetCost(peer), []*ProofReq{req})
  179. }
  180. // Valid processes an ODR request reply message from the LES network
  181. // returns true and stores results in memory if the message was a valid reply
  182. // to the request (implementation of LesOdrRequest)
  183. func (self *TrieRequest) Valid(db ethdb.Database, msg *Msg) bool {
  184. glog.V(logger.Debug).Infof("ODR: validating trie root %08x key %08x", self.Id.Root[:4], self.Key[:4])
  185. if msg.MsgType != MsgProofs {
  186. glog.V(logger.Debug).Infof("ODR: invalid message type")
  187. return false
  188. }
  189. proofs := msg.Obj.([][]rlp.RawValue)
  190. if len(proofs) != 1 {
  191. glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(proofs))
  192. return false
  193. }
  194. _, err := trie.VerifyProof(self.Id.Root, self.Key, proofs[0])
  195. if err != nil {
  196. glog.V(logger.Debug).Infof("ODR: merkle proof verification error: %v", err)
  197. return false
  198. }
  199. self.Proof = proofs[0]
  200. glog.V(logger.Debug).Infof("ODR: validation successful")
  201. return true
  202. }
  203. type CodeReq struct {
  204. BHash common.Hash
  205. AccKey []byte
  206. }
  207. // ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface
  208. type CodeRequest light.CodeRequest
  209. // GetCost returns the cost of the given ODR request according to the serving
  210. // peer's cost table (implementation of LesOdrRequest)
  211. func (self *CodeRequest) GetCost(peer *peer) uint64 {
  212. return peer.GetRequestCost(GetCodeMsg, 1)
  213. }
  214. // CanSend tells if a certain peer is suitable for serving the given request
  215. func (self *CodeRequest) CanSend(peer *peer) bool {
  216. return peer.HasBlock(self.Id.BlockHash, self.Id.BlockNumber)
  217. }
  218. // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
  219. func (self *CodeRequest) Request(reqID uint64, peer *peer) error {
  220. glog.V(logger.Debug).Infof("ODR: requesting node data for hash %08x from peer %v", self.Hash[:4], peer.id)
  221. req := &CodeReq{
  222. BHash: self.Id.BlockHash,
  223. AccKey: self.Id.AccKey,
  224. }
  225. return peer.RequestCode(reqID, self.GetCost(peer), []*CodeReq{req})
  226. }
  227. // Valid processes an ODR request reply message from the LES network
  228. // returns true and stores results in memory if the message was a valid reply
  229. // to the request (implementation of LesOdrRequest)
  230. func (self *CodeRequest) Valid(db ethdb.Database, msg *Msg) bool {
  231. glog.V(logger.Debug).Infof("ODR: validating node data for hash %08x", self.Hash[:4])
  232. if msg.MsgType != MsgCode {
  233. glog.V(logger.Debug).Infof("ODR: invalid message type")
  234. return false
  235. }
  236. reply := msg.Obj.([][]byte)
  237. if len(reply) != 1 {
  238. glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(reply))
  239. return false
  240. }
  241. data := reply[0]
  242. if hash := crypto.Keccak256Hash(data); self.Hash != hash {
  243. glog.V(logger.Debug).Infof("ODR: requested hash %08x does not match received data hash %08x", self.Hash[:4], hash[:4])
  244. return false
  245. }
  246. self.Data = data
  247. glog.V(logger.Debug).Infof("ODR: validation successful")
  248. return true
  249. }
  250. type ChtReq struct {
  251. ChtNum, BlockNum, FromLevel uint64
  252. }
  253. type ChtResp struct {
  254. Header *types.Header
  255. Proof []rlp.RawValue
  256. }
  257. // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
  258. type ChtRequest light.ChtRequest
  259. // GetCost returns the cost of the given ODR request according to the serving
  260. // peer's cost table (implementation of LesOdrRequest)
  261. func (self *ChtRequest) GetCost(peer *peer) uint64 {
  262. return peer.GetRequestCost(GetHeaderProofsMsg, 1)
  263. }
  264. // CanSend tells if a certain peer is suitable for serving the given request
  265. func (self *ChtRequest) CanSend(peer *peer) bool {
  266. peer.lock.RLock()
  267. defer peer.lock.RUnlock()
  268. return self.ChtNum <= (peer.headInfo.Number-light.ChtConfirmations)/light.ChtFrequency
  269. }
  270. // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
  271. func (self *ChtRequest) Request(reqID uint64, peer *peer) error {
  272. glog.V(logger.Debug).Infof("ODR: requesting CHT #%d block #%d from peer %v", self.ChtNum, self.BlockNum, peer.id)
  273. req := &ChtReq{
  274. ChtNum: self.ChtNum,
  275. BlockNum: self.BlockNum,
  276. }
  277. return peer.RequestHeaderProofs(reqID, self.GetCost(peer), []*ChtReq{req})
  278. }
  279. // Valid processes an ODR request reply message from the LES network
  280. // returns true and stores results in memory if the message was a valid reply
  281. // to the request (implementation of LesOdrRequest)
  282. func (self *ChtRequest) Valid(db ethdb.Database, msg *Msg) bool {
  283. glog.V(logger.Debug).Infof("ODR: validating CHT #%d block #%d", self.ChtNum, self.BlockNum)
  284. if msg.MsgType != MsgHeaderProofs {
  285. glog.V(logger.Debug).Infof("ODR: invalid message type")
  286. return false
  287. }
  288. proofs := msg.Obj.([]ChtResp)
  289. if len(proofs) != 1 {
  290. glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(proofs))
  291. return false
  292. }
  293. proof := proofs[0]
  294. var encNumber [8]byte
  295. binary.BigEndian.PutUint64(encNumber[:], self.BlockNum)
  296. value, err := trie.VerifyProof(self.ChtRoot, encNumber[:], proof.Proof)
  297. if err != nil {
  298. glog.V(logger.Debug).Infof("ODR: CHT merkle proof verification error: %v", err)
  299. return false
  300. }
  301. var node light.ChtNode
  302. if err := rlp.DecodeBytes(value, &node); err != nil {
  303. glog.V(logger.Debug).Infof("ODR: error decoding CHT node: %v", err)
  304. return false
  305. }
  306. if node.Hash != proof.Header.Hash() {
  307. glog.V(logger.Debug).Infof("ODR: CHT header hash does not match")
  308. return false
  309. }
  310. self.Proof = proof.Proof
  311. self.Header = proof.Header
  312. self.Td = node.Td
  313. glog.V(logger.Debug).Infof("ODR: validation successful")
  314. return true
  315. }