odr_util.go 11 KB

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