diff --git a/accounts/abi/bind/backends/bor_simulated.go b/accounts/abi/bind/backends/bor_simulated.go new file mode 100644 index 0000000000000000000000000000000000000000..3f5480d6a57b0a7b7a158543eb5c3aeece017f0b --- /dev/null +++ b/accounts/abi/bind/backends/bor_simulated.go @@ -0,0 +1,31 @@ +package backends + +import ( + "context" + + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/core/rawdb" + "github.com/maticnetwork/bor/core/types" +) + +func (fb *filterBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { + number := rawdb.ReadHeaderNumber(fb.db, hash) + if number == nil { + return nil, nil + } + receipt := rawdb.ReadRawBorReceipt(fb.db, hash, *number) + if receipt == nil { + return nil, nil + } + + return receipt, nil +} + +func (fb *filterBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { + receipt, err := fb.GetBorBlockReceipt(ctx, hash) + if err != nil || receipt == nil { + return nil, err + } + + return receipt.Logs, nil +} diff --git a/eth/bor_api_backend.go b/eth/bor_api_backend.go index ac2c4ec7312e82517b7d2f8c1f9ebc72ad43c6db..5a13ea1a6034ed191df75b3170ea9d6dbfad33a4 100644 --- a/eth/bor_api_backend.go +++ b/eth/bor_api_backend.go @@ -33,14 +33,10 @@ func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash return receipt, nil } -// func (b *EthAPIBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { -// receipts := b.eth.blockchain.GetReceiptsByHash(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 (b *EthAPIBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { + receipt := b.eth.blockchain.GetBorReceiptByHash(hash) + if receipt == nil { + return nil, nil + } + return receipt.Logs, nil +} diff --git a/eth/filters/bor_api.go b/eth/filters/bor_api.go new file mode 100644 index 0000000000000000000000000000000000000000..b1d82e92a6fa4dd81c12e81a5789be8641587410 --- /dev/null +++ b/eth/filters/bor_api.go @@ -0,0 +1,35 @@ +package filters + +import ( + "context" + + "github.com/maticnetwork/bor/core/types" + "github.com/maticnetwork/bor/rpc" +) + +func (api *PublicFilterAPI) GetBorBlockLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) { + var filter *BorBlockLogsFilter + if crit.BlockHash != nil { + // Block filter requested, construct a single-shot filter + filter = NewBorBlockLogsFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics) + } else { + // Convert the RPC block numbers into internal representations + begin := rpc.LatestBlockNumber.Int64() + if crit.FromBlock != nil { + begin = crit.FromBlock.Int64() + } + end := rpc.LatestBlockNumber.Int64() + if crit.ToBlock != nil { + end = crit.ToBlock.Int64() + } + // Construct the range filter + filter = NewBorBlockLogsRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics) + } + + // Run the filter and return all the logs + logs, err := filter.Logs(ctx) + if err != nil { + return nil, err + } + return returnLogs(logs), err +} diff --git a/eth/filters/bor_filter.go b/eth/filters/bor_filter.go new file mode 100644 index 0000000000000000000000000000000000000000..6ddd8e784feb88ec75b7a89b8b55e2650e886da7 --- /dev/null +++ b/eth/filters/bor_filter.go @@ -0,0 +1,150 @@ +// Copyright 2014 The go-ethereum Authors +// 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/>. + +package filters + +import ( + "context" + "errors" + + "github.com/maticnetwork/bor/common" + "github.com/maticnetwork/bor/core/types" + "github.com/maticnetwork/bor/ethdb" + "github.com/maticnetwork/bor/rpc" +) + +// BorBlockLogsFilter can be used to retrieve and filter logs. +type BorBlockLogsFilter struct { + backend Backend + + db ethdb.Database + addresses []common.Address + topics [][]common.Hash + + block common.Hash // Block hash if filtering a single block + begin, end int64 // Range interval if filtering multiple blocks +} + +// NewBorBlockLogsRangeFilter creates a new filter which uses a bloom filter on blocks to +// figure out whether a particular block is interesting or not. +func NewBorBlockLogsRangeFilter(backend Backend, begin, end int64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { + // Create a generic filter and convert it into a range filter + filter := newBorBlockLogsFilter(backend, addresses, topics) + filter.begin = begin + filter.end = end + + return filter +} + +// NewBorBlockLogsFilter creates a new filter which directly inspects the contents of +// a block to figure out whether it is interesting or not. +func NewBorBlockLogsFilter(backend Backend, block common.Hash, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { + // Create a generic filter and convert it into a block filter + filter := newBorBlockLogsFilter(backend, addresses, topics) + filter.block = block + return filter +} + +// newBorBlockLogsFilter creates a generic filter that can either filter based on a block hash, +// or based on range queries. The search criteria needs to be explicitly set. +func newBorBlockLogsFilter(backend Backend, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { + return &BorBlockLogsFilter{ + backend: backend, + addresses: addresses, + topics: topics, + db: backend.ChainDb(), + } +} + +// Logs searches the blockchain for matching log entries, returning all from the +// first block that contains matches, updating the start of the filter accordingly. +func (f *BorBlockLogsFilter) Logs(ctx context.Context) ([]*types.Log, error) { + // If we're doing singleton block filtering, execute and return + if f.block != (common.Hash{}) { + receipt, err := f.backend.GetBorBlockReceipt(ctx, f.block) + if err != nil { + return nil, err + } + + if receipt == nil { + return nil, errors.New("unknown block") + } + return f.borBlockLogs(ctx, receipt) + } + + // Figure out the limits of the filter range + header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) + if header == nil { + return nil, nil + } + head := header.Number.Uint64() + + if f.begin == -1 { + f.begin = int64(nextSprintEnd(head)) + } + end := f.end + if f.end == -1 { + end = int64(head) + } + + // Gather all indexed logs, and finish with non indexed ones + return f.unindexedLogs(ctx, uint64(end)) +} + +// unindexedLogs returns the logs matching the filter criteria based on raw block +// iteration and bloom matching. +func (f *BorBlockLogsFilter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) { + var logs []*types.Log + + for ; f.begin <= int64(end); f.begin = f.begin + 64 { + header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin)) + if header == nil || err != nil { + return logs, err + } + + // get bor block receipt + receipt, err := f.backend.GetBorBlockReceipt(ctx, header.Hash()) + if receipt == nil || err != nil { + continue + } + + // filter bor block logs + found, err := f.borBlockLogs(ctx, receipt) + if err != nil { + return logs, err + } + logs = append(logs, found...) + } + return logs, nil +} + +// borBlockLogs returns the logs matching the filter criteria within a single block. +func (f *BorBlockLogsFilter) borBlockLogs(ctx context.Context, receipt *types.BorReceipt) (logs []*types.Log, err error) { + if bloomFilter(receipt.Bloom, f.addresses, f.topics) { + found := filterLogs(receipt.Logs, nil, nil, f.addresses, f.topics) + logs = append(logs, found...) + } + return logs, nil +} + +func nextSprintEnd(n uint64) uint64 { + m := n % 64 + if m == 0 { + return n + } + + return n + 64 - m +} diff --git a/eth/filters/filter.go b/eth/filters/filter.go index e143035744da80a9f514c546445432198a2faf0d..1b91e06eddf10520aa6a12700f41684ef308b0f9 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -36,6 +36,8 @@ type Backend interface { HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) + GetBorBlockReceipt(ctx context.Context, blockHash common.Hash) (*types.BorReceipt, error) + GetBorBlockLogs(ctx context.Context, blockHash common.Hash) ([]*types.Log, error) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 272aea858ec040de8b1f0978bb405e6f44beb309..a8a6c4b9e74d37542adf3b060d9f146b26dbbe1a 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -69,6 +69,7 @@ type Backend interface { // Bor API GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) + GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) // Transaction pool API SendTx(ctx context.Context, signedTx *types.Transaction) error diff --git a/les/api_backend.go b/les/api_backend.go index 86dc91ea205ae608efa37eb2323be9ea0e09cd01..1f0dc8abf0b4ff58f9f3e59cbc3eacec4adac0fa 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -291,3 +291,7 @@ func (b *LesApiBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end func (b *LesApiBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.BorReceipt, error) { return nil, errors.New("Not implemented") } + +func (b *LesApiBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { + return nil, errors.New("Not implemented") +}