forked from cerc-io/plugeth
Merge pull request #16164 from karalabe/les-receipt-fix-optimal
eth, les, light: filter on logs only, derive receipts on demand
This commit is contained in:
commit
7f74bdf8dd
@ -428,10 +428,23 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumb
|
|||||||
}
|
}
|
||||||
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
|
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
||||||
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil
|
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
|
||||||
|
receipts := core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash))
|
||||||
|
if receipts == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
logs := make([][]*types.Log, len(receipts))
|
||||||
|
for i, receipt := range receipts {
|
||||||
|
logs[i] = receipt.Logs
|
||||||
|
}
|
||||||
|
return logs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
|
func (fb *filterBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
|
||||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
return event.NewSubscription(func(quit <-chan struct{}) error {
|
||||||
<-quit
|
<-quit
|
||||||
|
@ -104,6 +104,18 @@ func (b *EthApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash)
|
|||||||
return core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)), nil
|
return core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
|
||||||
|
receipts := core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash))
|
||||||
|
if receipts == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
logs := make([][]*types.Log, len(receipts))
|
||||||
|
for i, receipt := range receipts {
|
||||||
|
logs[i] = receipt.Logs
|
||||||
|
}
|
||||||
|
return logs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||||
return b.eth.blockchain.GetTdByHash(blockHash)
|
return b.eth.blockchain.GetTdByHash(blockHash)
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ type Backend interface {
|
|||||||
EventMux() *event.TypeMux
|
EventMux() *event.TypeMux
|
||||||
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
|
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
|
||||||
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
|
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
|
||||||
|
GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
|
||||||
|
|
||||||
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription
|
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription
|
||||||
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
|
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
|
||||||
@ -201,16 +202,28 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e
|
|||||||
// match the filter criteria. This function is called when the bloom filter signals a potential match.
|
// match the filter criteria. This function is called when the bloom filter signals a potential match.
|
||||||
func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs []*types.Log, err error) {
|
func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs []*types.Log, err error) {
|
||||||
// Get the logs of the block
|
// Get the logs of the block
|
||||||
receipts, err := f.backend.GetReceipts(ctx, header.Hash())
|
logsList, err := f.backend.GetLogs(ctx, header.Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var unfiltered []*types.Log
|
var unfiltered []*types.Log
|
||||||
for _, receipt := range receipts {
|
for _, logs := range logsList {
|
||||||
unfiltered = append(unfiltered, receipt.Logs...)
|
unfiltered = append(unfiltered, logs...)
|
||||||
}
|
}
|
||||||
logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics)
|
logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics)
|
||||||
if len(logs) > 0 {
|
if len(logs) > 0 {
|
||||||
|
// We have matching logs, check if we need to resolve full logs via the light client
|
||||||
|
if logs[0].TxHash == (common.Hash{}) {
|
||||||
|
receipts, err := f.backend.GetReceipts(ctx, header.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
unfiltered = unfiltered[:0]
|
||||||
|
for _, receipt := range receipts {
|
||||||
|
unfiltered = append(unfiltered, receipt.Logs...)
|
||||||
|
}
|
||||||
|
logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics)
|
||||||
|
}
|
||||||
return logs, nil
|
return logs, nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -375,19 +375,35 @@ func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.
|
|||||||
// Get the logs of the block
|
// Get the logs of the block
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
receipts, err := es.backend.GetReceipts(ctx, header.Hash())
|
logsList, err := es.backend.GetLogs(ctx, header.Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var unfiltered []*types.Log
|
var unfiltered []*types.Log
|
||||||
for _, receipt := range receipts {
|
for _, logs := range logsList {
|
||||||
for _, log := range receipt.Logs {
|
for _, log := range logs {
|
||||||
logcopy := *log
|
logcopy := *log
|
||||||
logcopy.Removed = remove
|
logcopy.Removed = remove
|
||||||
unfiltered = append(unfiltered, &logcopy)
|
unfiltered = append(unfiltered, &logcopy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logs := filterLogs(unfiltered, nil, nil, addresses, topics)
|
logs := filterLogs(unfiltered, nil, nil, addresses, topics)
|
||||||
|
if len(logs) > 0 && logs[0].TxHash == (common.Hash{}) {
|
||||||
|
// We have matching but non-derived logs
|
||||||
|
receipts, err := es.backend.GetReceipts(ctx, header.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
unfiltered = unfiltered[:0]
|
||||||
|
for _, receipt := range receipts {
|
||||||
|
for _, log := range receipt.Logs {
|
||||||
|
logcopy := *log
|
||||||
|
logcopy.Removed = remove
|
||||||
|
unfiltered = append(unfiltered, &logcopy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logs = filterLogs(unfiltered, nil, nil, addresses, topics)
|
||||||
|
}
|
||||||
return logs
|
return logs
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -69,8 +69,19 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumbe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
|
func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
|
||||||
num := core.GetBlockNumber(b.db, blockHash)
|
number := core.GetBlockNumber(b.db, blockHash)
|
||||||
return core.GetBlockReceipts(b.db, blockHash, num), nil
|
return core.GetBlockReceipts(b.db, blockHash, number), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *testBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
|
||||||
|
number := core.GetBlockNumber(b.db, blockHash)
|
||||||
|
receipts := core.GetBlockReceipts(b.db, blockHash, number)
|
||||||
|
|
||||||
|
logs := make([][]*types.Log, len(receipts))
|
||||||
|
for i, receipt := range receipts {
|
||||||
|
logs[i] = receipt.Logs
|
||||||
|
}
|
||||||
|
return logs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
|
func (b *testBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
|
||||||
|
@ -1032,15 +1032,19 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
||||||
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
|
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
|
||||||
tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash)
|
tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash)
|
||||||
if tx == nil {
|
if tx == nil {
|
||||||
return nil, errors.New("unknown transaction")
|
return nil, errors.New("unknown transaction")
|
||||||
}
|
}
|
||||||
receipt, _, _, _ := core.GetReceipt(s.b.ChainDb(), hash) // Old receipts don't have the lookup data available
|
receipts, err := s.b.GetReceipts(ctx, blockHash)
|
||||||
if receipt == nil {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(receipts) <= int(index) {
|
||||||
return nil, errors.New("unknown receipt")
|
return nil, errors.New("unknown receipt")
|
||||||
}
|
}
|
||||||
|
receipt := receipts[index]
|
||||||
|
|
||||||
var signer types.Signer = types.FrontierSigner{}
|
var signer types.Signer = types.FrontierSigner{}
|
||||||
if tx.Protected() {
|
if tx.Protected() {
|
||||||
|
@ -87,6 +87,10 @@ func (b *LesApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash)
|
|||||||
return light.GetBlockReceipts(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash))
|
return light.GetBlockReceipts(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
|
||||||
|
return light.GetBlockLogs(ctx, b.eth.odr, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash))
|
||||||
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||||
return b.eth.blockchain.GetTdByHash(blockHash)
|
return b.eth.blockchain.GetTdByHash(blockHash)
|
||||||
}
|
}
|
||||||
|
@ -126,15 +126,48 @@ func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint
|
|||||||
// GetBlockReceipts retrieves the receipts generated by the transactions included
|
// GetBlockReceipts retrieves the receipts generated by the transactions included
|
||||||
// in a block given by its hash.
|
// in a block given by its hash.
|
||||||
func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) {
|
func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) {
|
||||||
|
// Retrieve the potentially incomplete receipts from disk or network
|
||||||
receipts := core.GetBlockReceipts(odr.Database(), hash, number)
|
receipts := core.GetBlockReceipts(odr.Database(), hash, number)
|
||||||
if receipts != nil {
|
if receipts == nil {
|
||||||
return receipts, nil
|
r := &ReceiptsRequest{Hash: hash, Number: number}
|
||||||
|
if err := odr.Retrieve(ctx, r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
receipts = r.Receipts
|
||||||
}
|
}
|
||||||
r := &ReceiptsRequest{Hash: hash, Number: number}
|
// If the receipts are incomplete, fill the derived fields
|
||||||
if err := odr.Retrieve(ctx, r); err != nil {
|
if len(receipts) > 0 && receipts[0].TxHash == (common.Hash{}) {
|
||||||
return nil, err
|
block, err := GetBlock(ctx, odr, hash, number)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
genesis := core.GetCanonicalHash(odr.Database(), 0)
|
||||||
|
config, _ := core.GetChainConfig(odr.Database(), genesis)
|
||||||
|
|
||||||
|
core.SetReceiptsData(config, block, receipts)
|
||||||
|
core.WriteBlockReceipts(odr.Database(), hash, number, receipts)
|
||||||
}
|
}
|
||||||
return r.Receipts, nil
|
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
|
||||||
|
receipts := core.GetBlockReceipts(odr.Database(), hash, number)
|
||||||
|
if receipts == nil {
|
||||||
|
r := &ReceiptsRequest{Hash: hash, Number: number}
|
||||||
|
if err := odr.Retrieve(ctx, r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
receipts = r.Receipts
|
||||||
|
}
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes
|
// GetBloomBits retrieves a batch of compressed bloomBits vectors belonging to the given bit index and section indexes
|
||||||
|
Loading…
Reference in New Issue
Block a user