| 
									
										
										
										
											2016-11-09 02:01:56 +01:00
										 |  |  | // Copyright 2016 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2016-11-09 02:01:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | package light | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2017-03-22 18:20:33 +01:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2019-05-13 13:41:10 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/rawdb" | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 07:18:32 -08:00
										 |  |  | var sha3Nil = crypto.Keccak256Hash(nil) | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | // GetHeaderByNumber retrieves the canonical block header corresponding to the | 
					
						
							|  |  |  | // given number. | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	// Try to find it in the local database first. | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	db := odr.Database() | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 	hash := rawdb.ReadCanonicalHash(db, number) | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	// If there is a canonical hash, there should have a header too. | 
					
						
							|  |  |  | 	// But if it's pruned, re-fetch from network again. | 
					
						
							|  |  |  | 	if (hash != common.Hash{}) { | 
					
						
							|  |  |  | 		if header := rawdb.ReadHeader(db, hash, number); header != nil { | 
					
						
							|  |  |  | 			return header, nil | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	// Retrieve the header via ODR, ensure the requested header is covered | 
					
						
							|  |  |  | 	// by local trusted CHT. | 
					
						
							|  |  |  | 	chts, _, chtHead := odr.ChtIndexer().Sections() | 
					
						
							|  |  |  | 	if number >= chts*odr.IndexerConfig().ChtSize { | 
					
						
							| 
									
										
										
										
											2019-08-21 17:29:34 +08:00
										 |  |  | 		return nil, errNoTrustedCht | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	r := &ChtRequest{ | 
					
						
							|  |  |  | 		ChtRoot:  GetChtRoot(db, chts-1, chtHead), | 
					
						
							|  |  |  | 		ChtNum:   chts - 1, | 
					
						
							|  |  |  | 		BlockNum: number, | 
					
						
							|  |  |  | 		Config:   odr.IndexerConfig(), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	if err := odr.Retrieve(ctx, r); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-08 07:49:23 +02:00
										 |  |  | 	return r.Header, nil | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | // GetUntrustedHeaderByNumber retrieves specified block header without | 
					
						
							|  |  |  | // correctness checking. Note this function should only be used in light | 
					
						
							|  |  |  | // client checkpoint syncing. | 
					
						
							| 
									
										
											  
											
												all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
											
										 
											2019-06-28 15:34:02 +08:00
										 |  |  | func GetUntrustedHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64, peerId string) (*types.Header, error) { | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	// todo(rjl493456442) it's a hack to retrieve headers which is not covered | 
					
						
							|  |  |  | 	// by CHT. Fix it in LES4 | 
					
						
							|  |  |  | 	r := &ChtRequest{ | 
					
						
							|  |  |  | 		BlockNum:  number, | 
					
						
							|  |  |  | 		ChtNum:    number / odr.IndexerConfig().ChtSize, | 
					
						
							|  |  |  | 		Untrusted: true, | 
					
						
							|  |  |  | 		PeerId:    peerId, | 
					
						
							|  |  |  | 		Config:    odr.IndexerConfig(), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
											  
											
												all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
											
										 
											2019-06-28 15:34:02 +08:00
										 |  |  | 	if err := odr.Retrieve(ctx, r); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return r.Header, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | // GetCanonicalHash retrieves the canonical block hash corresponding to the number. | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 	hash := rawdb.ReadCanonicalHash(odr.Database(), number) | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	if hash != (common.Hash{}) { | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 		return hash, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	header, err := GetHeaderByNumber(ctx, odr, number) | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return common.Hash{}, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// number -> canonical mapping already be stored in db, get it. | 
					
						
							|  |  |  | 	return header.Hash(), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetTd retrieves the total difficulty corresponding to the number and hash. | 
					
						
							|  |  |  | func GetTd(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*big.Int, error) { | 
					
						
							|  |  |  | 	td := rawdb.ReadTd(odr.Database(), hash, number) | 
					
						
							|  |  |  | 	if td != nil { | 
					
						
							|  |  |  | 		return td, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, err := GetHeaderByNumber(ctx, odr, number) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	// <hash, number> -> td mapping already be stored in db, get it. | 
					
						
							|  |  |  | 	return rawdb.ReadTd(odr.Database(), hash, number), nil | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. | 
					
						
							|  |  |  | func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (rlp.RawValue, error) { | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 	if data := rawdb.ReadBodyRLP(odr.Database(), hash, number); data != nil { | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 		return data, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	// Retrieve the block header first and pass it for verification. | 
					
						
							|  |  |  | 	header, err := GetHeaderByNumber(ctx, odr, number) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, errNoHeader | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	r := &BlockRequest{Hash: hash, Number: number, Header: header} | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	if err := odr.Retrieve(ctx, r); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	return r.Rlp, nil | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | // GetBody retrieves the block body (transactions, uncles) corresponding to the | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | // hash. | 
					
						
							|  |  |  | func GetBody(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Body, error) { | 
					
						
							|  |  |  | 	data, err := GetBodyRLP(ctx, odr, hash, number) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	body := new(types.Body) | 
					
						
							|  |  |  | 	if err := rlp.Decode(bytes.NewReader(data), body); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return body, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetBlock retrieves an entire block corresponding to the hash, assembling it | 
					
						
							|  |  |  | // back from the stored header and body. | 
					
						
							|  |  |  | func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (*types.Block, error) { | 
					
						
							|  |  |  | 	// Retrieve the block header and body contents | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	header, err := GetHeaderByNumber(ctx, odr, number) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-21 17:29:34 +08:00
										 |  |  | 		return nil, errNoHeader | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	body, err := GetBody(ctx, odr, hash, number) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Reassemble the block and return | 
					
						
							|  |  |  | 	return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetBlockReceipts retrieves the receipts generated by the transactions included | 
					
						
							|  |  |  | // in a block given by its hash. | 
					
						
							|  |  |  | func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { | 
					
						
							| 
									
										
										
										
											2019-03-27 09:11:24 -07:00
										 |  |  | 	// Assume receipts are already stored locally and attempt to retrieve. | 
					
						
							|  |  |  | 	receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 	if receipts == nil { | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 		header, err := GetHeaderByNumber(ctx, odr, number) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, errNoHeader | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		r := &ReceiptsRequest{Hash: hash, Number: number, Header: header} | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 		if err := odr.Retrieve(ctx, r); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		receipts = r.Receipts | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 	// If the receipts are incomplete, fill the derived fields | 
					
						
							|  |  |  | 	if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) { | 
					
						
							|  |  |  | 		block, err := GetBlock(ctx, odr, hash, number) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		genesis := rawdb.ReadCanonicalHash(odr.Database(), 0) | 
					
						
							|  |  |  | 		config := rawdb.ReadChainConfig(odr.Database(), genesis) | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 12:36:27 +03:00
										 |  |  | 		if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Transactions()); err != nil { | 
					
						
							| 
									
										
										
										
											2018-03-07 19:05:14 +09:00
										 |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		rawdb.WriteReceipts(odr.Database(), hash, number, receipts) | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return receipts, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetBlockLogs retrieves the logs generated by the transactions included in a | 
					
						
							|  |  |  | // block given by its hash. | 
					
						
							|  |  |  | func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) { | 
					
						
							|  |  |  | 	// Retrieve the potentially incomplete receipts from disk or network | 
					
						
							| 
									
										
										
										
											2019-03-27 09:11:24 -07:00
										 |  |  | 	receipts, err := GetBlockReceipts(ctx, odr, hash, number) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	logs := make([][]*types.Log, len(receipts)) | 
					
						
							|  |  |  | 	for i, receipt := range receipts { | 
					
						
							|  |  |  | 		logs[i] = receipt.Logs | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 	return logs, nil | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
											
										 
											2019-06-28 15:34:02 +08:00
										 |  |  | // GetUntrustedBlockLogs retrieves the logs generated by the transactions included in a | 
					
						
							|  |  |  | // block. The retrieved logs are regarded as untrusted and will not be stored in the | 
					
						
							|  |  |  | // database. This function should only be used in light client checkpoint syncing. | 
					
						
							|  |  |  | func GetUntrustedBlockLogs(ctx context.Context, odr OdrBackend, header *types.Header) ([][]*types.Log, error) { | 
					
						
							|  |  |  | 	// Retrieve the potentially incomplete receipts from disk or network | 
					
						
							|  |  |  | 	hash, number := header.Hash(), header.Number.Uint64() | 
					
						
							|  |  |  | 	receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) | 
					
						
							|  |  |  | 	if receipts == nil { | 
					
						
							|  |  |  | 		r := &ReceiptsRequest{Hash: hash, Number: number, Header: header, Untrusted: true} | 
					
						
							|  |  |  | 		if err := odr.Retrieve(ctx, r); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		receipts = r.Receipts | 
					
						
							|  |  |  | 		// Untrusted receipts won't be stored in the database. Therefore | 
					
						
							|  |  |  | 		// derived fields computation is unnecessary. | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Return the logs without deriving any computed fields on the receipts | 
					
						
							|  |  |  | 	logs := make([][]*types.Log, len(receipts)) | 
					
						
							|  |  |  | 	for i, receipt := range receipts { | 
					
						
							|  |  |  | 		logs[i] = receipt.Logs | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return logs, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to | 
					
						
							|  |  |  | // the given bit index and section indexes. | 
					
						
							|  |  |  | func GetBloomBits(ctx context.Context, odr OdrBackend, bit uint, sections []uint64) ([][]byte, error) { | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 		reqIndex    []int | 
					
						
							|  |  |  | 		reqSections []uint64 | 
					
						
							|  |  |  | 		db          = odr.Database() | 
					
						
							|  |  |  | 		result      = make([][]byte, len(sections)) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	blooms, _, sectionHead := odr.BloomTrieIndexer().Sections() | 
					
						
							|  |  |  | 	for i, section := range sections { | 
					
						
							|  |  |  | 		sectionHead := rawdb.ReadCanonicalHash(db, (section+1)*odr.IndexerConfig().BloomSize-1) | 
					
						
							|  |  |  | 		// If we don't have the canonical hash stored for this section head number, | 
					
						
							|  |  |  | 		// we'll still look for an entry with a zero sectionHead (we store it with | 
					
						
							|  |  |  | 		// zero section head too if we don't know it at the time of the retrieval) | 
					
						
							|  |  |  | 		if bloomBits, _ := rawdb.ReadBloomBits(db, bit, section, sectionHead); len(bloomBits) != 0 { | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 			result[i] = bloomBits | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 		// TODO(rjl493456442) Convert sectionIndex to BloomTrie relative index | 
					
						
							|  |  |  | 		if section >= blooms { | 
					
						
							|  |  |  | 			return nil, errNoTrustedBloomTrie | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		reqSections = append(reqSections, section) | 
					
						
							|  |  |  | 		reqIndex = append(reqIndex, i) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	// Find all bloombits in database, nothing to query via odr, return. | 
					
						
							|  |  |  | 	if reqSections == nil { | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		return result, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	// Send odr request to retrieve missing bloombits. | 
					
						
							|  |  |  | 	r := &BloomRequest{ | 
					
						
							|  |  |  | 		BloomTrieRoot:    GetBloomTrieRoot(db, blooms-1, sectionHead), | 
					
						
							|  |  |  | 		BloomTrieNum:     blooms - 1, | 
					
						
							|  |  |  | 		BitIdx:           bit, | 
					
						
							|  |  |  | 		SectionIndexList: reqSections, | 
					
						
							|  |  |  | 		Config:           odr.IndexerConfig(), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	if err := odr.Retrieve(ctx, r); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	for i, idx := range reqIndex { | 
					
						
							|  |  |  | 		result[idx] = r.BloomBits[i] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result, nil | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 13:41:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // GetTransaction retrieves a canonical transaction by hash and also returns its position in the chain | 
					
						
							|  |  |  | func GetTransaction(ctx context.Context, odr OdrBackend, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { | 
					
						
							|  |  |  | 	r := &TxStatusRequest{Hashes: []common.Hash{txHash}} | 
					
						
							|  |  |  | 	if err := odr.Retrieve(ctx, r); err != nil || r.Status[0].Status != core.TxStatusIncluded { | 
					
						
							|  |  |  | 		return nil, common.Hash{}, 0, 0, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-13 17:02:54 +08:00
										 |  |  | 	pos := r.Status[0].Lookup | 
					
						
							|  |  |  | 	// first ensure that we have the header, otherwise block body retrieval will fail | 
					
						
							|  |  |  | 	// also verify if this is a canonical block by getting the header by number and checking its hash | 
					
						
							|  |  |  | 	if header, err := GetHeaderByNumber(ctx, odr, pos.BlockIndex); err != nil || header.Hash() != pos.BlockHash { | 
					
						
							|  |  |  | 		return nil, common.Hash{}, 0, 0, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	body, err := GetBody(ctx, odr, pos.BlockHash, pos.BlockIndex) | 
					
						
							|  |  |  | 	if err != nil || uint64(len(body.Transactions)) <= pos.Index || body.Transactions[pos.Index].Hash() != txHash { | 
					
						
							|  |  |  | 		return nil, common.Hash{}, 0, 0, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return body.Transactions[pos.Index], pos.BlockHash, pos.BlockIndex, pos.Index, nil | 
					
						
							| 
									
										
										
										
											2019-05-13 13:41:10 +02:00
										 |  |  | } |