odr_util.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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
  17. import (
  18. "bytes"
  19. "context"
  20. "errors"
  21. "math/big"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/core"
  24. "github.com/ethereum/go-ethereum/core/rawdb"
  25. "github.com/ethereum/go-ethereum/core/types"
  26. "github.com/ethereum/go-ethereum/rlp"
  27. )
  28. // errNonCanonicalHash is returned if the requested chain data doesn't belong
  29. // to the canonical chain. ODR can only retrieve the canonical chain data covered
  30. // by the CHT or Bloom trie for verification.
  31. var errNonCanonicalHash = errors.New("hash is not currently canonical")
  32. // GetHeaderByNumber retrieves the canonical block header corresponding to the
  33. // given number. The returned header is proven by local CHT.
  34. func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) {
  35. // Try to find it in the local database first.
  36. db := odr.Database()
  37. hash := rawdb.ReadCanonicalHash(db, number)
  38. // If there is a canonical hash, there should have a header too.
  39. // But if it's pruned, re-fetch from network again.
  40. if (hash != common.Hash{}) {
  41. if header := rawdb.ReadHeader(db, hash, number); header != nil {
  42. return header, nil
  43. }
  44. }
  45. // Retrieve the header via ODR, ensure the requested header is covered
  46. // by local trusted CHT.
  47. chts, _, chtHead := odr.ChtIndexer().Sections()
  48. if number >= chts*odr.IndexerConfig().ChtSize {
  49. return nil, errNoTrustedCht
  50. }
  51. r := &ChtRequest{
  52. ChtRoot: GetChtRoot(db, chts-1, chtHead),
  53. ChtNum: chts - 1,
  54. BlockNum: number,
  55. Config: odr.IndexerConfig(),
  56. }
  57. if err := odr.Retrieve(ctx, r); err != nil {
  58. return nil, err
  59. }
  60. return r.Header, nil
  61. }
  62. // GetCanonicalHash retrieves the canonical block hash corresponding to the number.
  63. func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) {
  64. hash := rawdb.ReadCanonicalHash(odr.Database(), number)
  65. if hash != (common.Hash{}) {
  66. return hash, nil
  67. }
  68. header, err := GetHeaderByNumber(ctx, odr, number)
  69. if err != nil {
  70. return common.Hash{}, err
  71. }
  72. // number -> canonical mapping already be stored in db, get it.
  73. return header.Hash(), nil
  74. }
  75. // GetTd retrieves the total difficulty corresponding to the number and hash.
  76. func GetTd(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*big.Int, error) {
  77. td := rawdb.ReadTd(odr.Database(), hash, number)
  78. if td != nil {
  79. return td, nil
  80. }
  81. header, err := GetHeaderByNumber(ctx, odr, number)
  82. if err != nil {
  83. return nil, err
  84. }
  85. if header.Hash() != hash {
  86. return nil, errNonCanonicalHash
  87. }
  88. // <hash, number> -> td mapping already be stored in db, get it.
  89. return rawdb.ReadTd(odr.Database(), hash, number), nil
  90. }
  91. // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
  92. func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) {
  93. if data := rawdb.ReadBodyRLP(odr.Database(), hash, number); data != nil {
  94. return data, nil
  95. }
  96. // Retrieve the block header first and pass it for verification.
  97. header, err := GetHeaderByNumber(ctx, odr, number)
  98. if err != nil {
  99. return nil, errNoHeader
  100. }
  101. if header.Hash() != hash {
  102. return nil, errNonCanonicalHash
  103. }
  104. r := &BlockRequest{Hash: hash, Number: number, Header: header}
  105. if err := odr.Retrieve(ctx, r); err != nil {
  106. return nil, err
  107. }
  108. return r.Rlp, nil
  109. }
  110. // GetBody retrieves the block body (transactions, uncles) corresponding to the
  111. // hash.
  112. func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) {
  113. data, err := GetBodyRLP(ctx, odr, hash, number)
  114. if err != nil {
  115. return nil, err
  116. }
  117. body := new(types.Body)
  118. if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
  119. return nil, err
  120. }
  121. return body, nil
  122. }
  123. // GetBlock retrieves an entire block corresponding to the hash, assembling it
  124. // back from the stored header and body.
  125. func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) {
  126. // Retrieve the block header and body contents
  127. header, err := GetHeaderByNumber(ctx, odr, number)
  128. if err != nil {
  129. return nil, errNoHeader
  130. }
  131. body, err := GetBody(ctx, odr, hash, number)
  132. if err != nil {
  133. return nil, err
  134. }
  135. // Reassemble the block and return
  136. return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil
  137. }
  138. // GetBlockReceipts retrieves the receipts generated by the transactions included
  139. // in a block given by its hash.
  140. func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) {
  141. // Assume receipts are already stored locally and attempt to retrieve.
  142. receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number)
  143. if receipts == nil {
  144. header, err := GetHeaderByNumber(ctx, odr, number)
  145. if err != nil {
  146. return nil, errNoHeader
  147. }
  148. if header.Hash() != hash {
  149. return nil, errNonCanonicalHash
  150. }
  151. r := &ReceiptsRequest{Hash: hash, Number: number, Header: header}
  152. if err := odr.Retrieve(ctx, r); err != nil {
  153. return nil, err
  154. }
  155. receipts = r.Receipts
  156. }
  157. // If the receipts are incomplete, fill the derived fields
  158. if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) {
  159. block, err := GetBlock(ctx, odr, hash, number)
  160. if err != nil {
  161. return nil, err
  162. }
  163. genesis := rawdb.ReadCanonicalHash(odr.Database(), 0)
  164. config := rawdb.ReadChainConfig(odr.Database(), genesis)
  165. if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Transactions()); err != nil {
  166. return nil, err
  167. }
  168. rawdb.WriteReceipts(odr.Database(), hash, number, receipts)
  169. }
  170. return receipts, nil
  171. }
  172. // GetBlockLogs retrieves the logs generated by the transactions included in a
  173. // block given by its hash.
  174. func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) {
  175. // Retrieve the potentially incomplete receipts from disk or network
  176. receipts, err := GetBlockReceipts(ctx, odr, hash, number)
  177. if err != nil {
  178. return nil, err
  179. }
  180. logs := make([][]*types.Log, len(receipts))
  181. for i, receipt := range receipts {
  182. logs[i] = receipt.Logs
  183. }
  184. return logs, nil
  185. }
  186. // GetUntrustedBlockLogs retrieves the logs generated by the transactions included in a
  187. // block. The retrieved logs are regarded as untrusted and will not be stored in the
  188. // database. This function should only be used in light client checkpoint syncing.
  189. func GetUntrustedBlockLogs(ctx context.Context, odr OdrBackend, header *types.Header) ([][]*types.Log, error) {
  190. // Retrieve the potentially incomplete receipts from disk or network
  191. hash, number := header.Hash(), header.Number.Uint64()
  192. receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number)
  193. if receipts == nil {
  194. r := &ReceiptsRequest{Hash: hash, Number: number, Header: header, Untrusted: true}
  195. if err := odr.Retrieve(ctx, r); err != nil {
  196. return nil, err
  197. }
  198. receipts = r.Receipts
  199. // Untrusted receipts won't be stored in the database. Therefore
  200. // derived fields computation is unnecessary.
  201. }
  202. // Return the logs without deriving any computed fields on the receipts
  203. logs := make([][]*types.Log, len(receipts))
  204. for i, receipt := range receipts {
  205. logs[i] = receipt.Logs
  206. }
  207. return logs, nil
  208. }
  209. // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to
  210. // the given bit index and section indexes.
  211. func GetBloomBits(ctx context.Context, odr OdrBackend, bit uint, sections []uint64) ([][]byte, error) {
  212. var (
  213. reqIndex []int
  214. reqSections []uint64
  215. db = odr.Database()
  216. result = make([][]byte, len(sections))
  217. )
  218. blooms, _, sectionHead := odr.BloomTrieIndexer().Sections()
  219. for i, section := range sections {
  220. sectionHead := rawdb.ReadCanonicalHash(db, (section+1)*odr.IndexerConfig().BloomSize-1)
  221. // If we don't have the canonical hash stored for this section head number,
  222. // we'll still look for an entry with a zero sectionHead (we store it with
  223. // zero section head too if we don't know it at the time of the retrieval)
  224. if bloomBits, _ := rawdb.ReadBloomBits(db, bit, section, sectionHead); len(bloomBits) != 0 {
  225. result[i] = bloomBits
  226. continue
  227. }
  228. // TODO(rjl493456442) Convert sectionIndex to BloomTrie relative index
  229. if section >= blooms {
  230. return nil, errNoTrustedBloomTrie
  231. }
  232. reqSections = append(reqSections, section)
  233. reqIndex = append(reqIndex, i)
  234. }
  235. // Find all bloombits in database, nothing to query via odr, return.
  236. if reqSections == nil {
  237. return result, nil
  238. }
  239. // Send odr request to retrieve missing bloombits.
  240. r := &BloomRequest{
  241. BloomTrieRoot: GetBloomTrieRoot(db, blooms-1, sectionHead),
  242. BloomTrieNum: blooms - 1,
  243. BitIdx: bit,
  244. SectionIndexList: reqSections,
  245. Config: odr.IndexerConfig(),
  246. }
  247. if err := odr.Retrieve(ctx, r); err != nil {
  248. return nil, err
  249. }
  250. for i, idx := range reqIndex {
  251. result[idx] = r.BloomBits[i]
  252. }
  253. return result, nil
  254. }
  255. // GetTransaction retrieves a canonical transaction by hash and also returns
  256. // its position in the chain. There is no guarantee in the LES protocol that
  257. // the mined transaction will be retrieved back for sure because of different
  258. // reasons(the transaction is unindexed, the malicous server doesn't reply it
  259. // deliberately, etc). Therefore, unretrieved transactions will receive a certain
  260. // number of retrys, thus giving a weak guarantee.
  261. func GetTransaction(ctx context.Context, odr OdrBackend, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
  262. r := &TxStatusRequest{Hashes: []common.Hash{txHash}}
  263. if err := odr.RetrieveTxStatus(ctx, r); err != nil || r.Status[0].Status != core.TxStatusIncluded {
  264. return nil, common.Hash{}, 0, 0, err
  265. }
  266. pos := r.Status[0].Lookup
  267. // first ensure that we have the header, otherwise block body retrieval will fail
  268. // also verify if this is a canonical block by getting the header by number and checking its hash
  269. if header, err := GetHeaderByNumber(ctx, odr, pos.BlockIndex); err != nil || header.Hash() != pos.BlockHash {
  270. return nil, common.Hash{}, 0, 0, err
  271. }
  272. body, err := GetBody(ctx, odr, pos.BlockHash, pos.BlockIndex)
  273. if err != nil || uint64(len(body.Transactions)) <= pos.Index || body.Transactions[pos.Index].Hash() != txHash {
  274. return nil, common.Hash{}, 0, 0, err
  275. }
  276. return body.Transactions[pos.Index], pos.BlockHash, pos.BlockIndex, pos.Index, nil
  277. }