| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { | 
					
						
							|  |  |  | 	db := odr.Database() | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 	hash := rawdb.ReadCanonicalHash(db, number) | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	if (hash != common.Hash{}) { | 
					
						
							|  |  |  | 		// if there is a canonical hash, there is a header too | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		header := rawdb.ReadHeader(db, hash, number) | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 		if header == nil { | 
					
						
							|  |  |  | 			panic("Canonical hash present but header not found") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return header, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		chtCount, sectionHeadNum uint64 | 
					
						
							|  |  |  | 		sectionHead              common.Hash | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if odr.ChtIndexer() != nil { | 
					
						
							|  |  |  | 		chtCount, sectionHeadNum, sectionHead = odr.ChtIndexer().Sections() | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		// if the CHT was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too | 
					
						
							|  |  |  | 		for chtCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { | 
					
						
							|  |  |  | 			chtCount-- | 
					
						
							|  |  |  | 			if chtCount > 0 { | 
					
						
							| 
									
										
										
										
											2018-08-28 15:08:16 +08:00
										 |  |  | 				sectionHeadNum = chtCount*odr.IndexerConfig().ChtSize - 1 | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 				sectionHead = odr.ChtIndexer().SectionHead(chtCount - 1) | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 				canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-28 15:08:16 +08:00
										 |  |  | 	if number >= chtCount*odr.IndexerConfig().ChtSize { | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 		return nil, ErrNoTrustedCht | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-28 15:08:16 +08:00
										 |  |  | 	r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	if (hash != common.Hash{}) { | 
					
						
							|  |  |  | 		return hash, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	header, err := GetHeaderByNumber(ctx, odr, number) | 
					
						
							|  |  |  | 	if header != nil { | 
					
						
							|  |  |  | 		return header.Hash(), nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return common.Hash{}, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	r := &BlockRequest{Hash: hash, Number: number} | 
					
						
							|  |  |  | 	if err := odr.Retrieve(ctx, r); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return r.Rlp, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetBody retrieves the block body (transactons, uncles) corresponding to the | 
					
						
							|  |  |  | // 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 | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 	header := rawdb.ReadHeader(odr.Database(), hash, number) | 
					
						
							| 
									
										
										
										
											2016-10-14 05:47:09 +02:00
										 |  |  | 	if header == nil { | 
					
						
							|  |  |  | 		return nil, ErrNoHeader | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	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 { | 
					
						
							|  |  |  | 		r := &ReceiptsRequest{Hash: hash, Number: number} | 
					
						
							|  |  |  | 		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
										 |  |  | 	} | 
					
						
							|  |  |  | 	// 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 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | // GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes | 
					
						
							|  |  |  | func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxList []uint64) ([][]byte, error) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2018-08-28 15:08:16 +08:00
										 |  |  | 		db      = odr.Database() | 
					
						
							|  |  |  | 		result  = make([][]byte, len(sectionIdxList)) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		reqList []uint64 | 
					
						
							|  |  |  | 		reqIdx  []int | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		bloomTrieCount, sectionHeadNum uint64 | 
					
						
							|  |  |  | 		sectionHead                    common.Hash | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if odr.BloomTrieIndexer() != nil { | 
					
						
							|  |  |  | 		bloomTrieCount, sectionHeadNum, sectionHead = odr.BloomTrieIndexer().Sections() | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		canonicalHash := rawdb.ReadCanonicalHash(db, sectionHeadNum) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		// if the BloomTrie was injected as a trusted checkpoint, we have no canonical hash yet so we accept zero hash too | 
					
						
							|  |  |  | 		for bloomTrieCount > 0 && canonicalHash != sectionHead && canonicalHash != (common.Hash{}) { | 
					
						
							|  |  |  | 			bloomTrieCount-- | 
					
						
							|  |  |  | 			if bloomTrieCount > 0 { | 
					
						
							| 
									
										
										
										
											2018-08-28 15:08:16 +08:00
										 |  |  | 				sectionHeadNum = bloomTrieCount*odr.IndexerConfig().BloomTrieSize - 1 | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 				sectionHead = odr.BloomTrieIndexer().SectionHead(bloomTrieCount - 1) | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 				canonicalHash = rawdb.ReadCanonicalHash(db, sectionHeadNum) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, sectionIdx := range sectionIdxList { | 
					
						
							| 
									
										
										
										
											2018-08-28 15:08:16 +08:00
										 |  |  | 		sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*odr.IndexerConfig().BloomSize-1) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		// 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) | 
					
						
							| 
									
										
										
										
											2018-05-07 14:35:06 +03:00
										 |  |  | 		bloomBits, err := rawdb.ReadBloomBits(db, bitIdx, sectionIdx, sectionHead) | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			result[i] = bloomBits | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-08-28 15:08:16 +08:00
										 |  |  | 			// TODO(rjl493456442) Convert sectionIndex to BloomTrie relative index | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 			if sectionIdx >= bloomTrieCount { | 
					
						
							|  |  |  | 				return nil, ErrNoTrustedBloomTrie | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			reqList = append(reqList, sectionIdx) | 
					
						
							|  |  |  | 			reqIdx = append(reqIdx, i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if reqList == nil { | 
					
						
							|  |  |  | 		return result, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 15:08:16 +08:00
										 |  |  | 	r := &BloomRequest{BloomTrieRoot: GetBloomTrieRoot(db, bloomTrieCount-1, sectionHead), BloomTrieNum: bloomTrieCount - 1, | 
					
						
							| 
									
										
										
										
											2018-09-20 14:11:14 +03:00
										 |  |  | 		BitIdx: bitIdx, SectionIndexList: reqList, Config: odr.IndexerConfig()} | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	if err := odr.Retrieve(ctx, r); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		for i, idx := range reqIdx { | 
					
						
							|  |  |  | 			result[idx] = r.BloomBits[i] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return result, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		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 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if body, err := GetBody(ctx, odr, pos.BlockHash, pos.BlockIndex); err != nil || uint64(len(body.Transactions)) <= pos.Index || body.Transactions[pos.Index].Hash() != txHash { | 
					
						
							|  |  |  | 			return nil, common.Hash{}, 0, 0, err | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return body.Transactions[pos.Index], pos.BlockHash, pos.BlockIndex, pos.Index, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |