Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,10 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumb
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
}

func (fb *filterBackend) HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) {
return fb.bc.GetHeaderByHash(blockHash), nil
}

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
}
Expand Down
79 changes: 58 additions & 21 deletions eth/filters/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ import (
"github.com/XinFinOrg/XDPoSChain/rpc"
)

var (
errExceedMaxTopics = errors.New("exceed max topics")
)

// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
const maxTopics = 4

var (
deadline = 5 * time.Minute // consider a filter inactive if it has not been polled for within deadline
)
Expand Down Expand Up @@ -99,7 +106,7 @@ func (api *PublicFilterAPI) timeoutLoop() {
// NewPendingTransactionFilter creates a filter that fetches pending transaction hashes
// as transactions enter the pending state.
//
// It is part of the filter package because this filter can be used throug the
// It is part of the filter package because this filter can be used through the
// `eth_getFilterChanges` polling method that is also used for log filters.
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newpendingtransactionfilter
Expand Down Expand Up @@ -269,14 +276,8 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc
}

// FilterCriteria represents a request to create a new filter.
//
// TODO(karalabe): Kill this in favor of ethereum.FilterQuery.
type FilterCriteria struct {
FromBlock *big.Int
ToBlock *big.Int
Addresses []common.Address
Topics [][]common.Hash
}
// Same as ethereum.FilterQuery but with UnmarshalJSON() method.
type FilterCriteria ethereum.FilterQuery

// NewFilter creates a new filter and returns the filter id. It can be
// used to retrieve logs when the state changes. This method cannot be
Expand Down Expand Up @@ -327,15 +328,42 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) {
// Convert the RPC block numbers into internal representations
if crit.FromBlock == nil {
crit.FromBlock = big.NewInt(rpc.LatestBlockNumber.Int64())
if len(crit.Topics) > maxTopics {
return nil, errExceedMaxTopics
}
if crit.ToBlock == nil {
crit.ToBlock = big.NewInt(rpc.LatestBlockNumber.Int64())

var (
fromBlock int64
toBlock int64
)

if crit.BlockHash != nil {
// look up block number from block hash
header, err := api.backend.HeaderByHash(ctx, *crit.BlockHash)
if err != nil {
return nil, err
}
if header == nil {
return nil, errors.New("unknown block")
}
fromBlock = int64(header.Number.Int64())
toBlock = fromBlock
} else {
// Convert the RPC block numbers into internal representations
if crit.FromBlock == nil {
fromBlock = int64(rpc.LatestBlockNumber)
} else {
fromBlock = crit.FromBlock.Int64()
}
if crit.ToBlock == nil {
toBlock = int64(rpc.LatestBlockNumber)
} else {
toBlock = crit.ToBlock.Int64()
}
}

// Create and run the filter to get all the logs
filter := New(api.backend, crit.FromBlock.Int64(), crit.ToBlock.Int64(), crit.Addresses, crit.Topics)
filter := New(api.backend, fromBlock, toBlock, crit.Addresses, crit.Topics)

logs, err := filter.Logs(ctx)
if err != nil {
Expand Down Expand Up @@ -451,7 +479,8 @@ func returnLogs(logs []*types.Log) []*types.Log {
// UnmarshalJSON sets *args fields with given data.
func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
type input struct {
From *rpc.BlockNumber `json:"fromBlock"`
BlockHash *common.Hash `json:"blockHash"`
FromBlock *rpc.BlockNumber `json:"fromBlock"`
ToBlock *rpc.BlockNumber `json:"toBlock"`
Addresses interface{} `json:"address"`
Topics []interface{} `json:"topics"`
Expand All @@ -462,12 +491,20 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
return err
}

if raw.From != nil {
args.FromBlock = big.NewInt(raw.From.Int64())
}
if raw.BlockHash != nil {
if raw.FromBlock != nil || raw.ToBlock != nil {
// BlockHash is mutually exclusive with FromBlock/ToBlock criteria
return fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other")
}
args.BlockHash = raw.BlockHash
} else {
if raw.FromBlock != nil {
args.FromBlock = big.NewInt(raw.FromBlock.Int64())
}

if raw.ToBlock != nil {
args.ToBlock = big.NewInt(raw.ToBlock.Int64())
if raw.ToBlock != nil {
args.ToBlock = big.NewInt(raw.ToBlock.Int64())
}
}

args.Addresses = []common.Address{}
Expand Down
1 change: 1 addition & 0 deletions eth/filters/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Backend interface {
ChainDb() ethdb.Database
EventMux() *event.TypeMux
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
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)

Expand Down
34 changes: 33 additions & 1 deletion eth/filters/filter_system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package filters
import (
"context"
"fmt"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big"
"math/rand"
"reflect"
Expand All @@ -31,6 +30,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/bloombits"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/event"
Expand Down Expand Up @@ -69,6 +69,11 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumbe
return core.GetHeader(b.db, hash, num), nil
}

func (b *testBackend) HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) {
num := core.GetBlockNumber(b.db, blockHash)
return core.GetHeader(b.db, blockHash, num), nil
}

func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
number := core.GetBlockNumber(b.db, blockHash)
return core.GetBlockReceipts(b.db, blockHash, number), nil
Expand Down Expand Up @@ -335,6 +340,33 @@ func TestInvalidLogFilterCreation(t *testing.T) {
}
}

func TestInvalidGetLogsRequest(t *testing.T) {
var (
mux = new(event.TypeMux)
db = rawdb.NewMemoryDatabase()
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed)
chainFeed = new(event.Feed)
backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed}
api = NewPublicFilterAPI(backend, false)
blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
)

// Reason: Cannot specify both BlockHash and FromBlock/ToBlock)
testCases := []FilterCriteria{
0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)},
1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)},
2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
}

for i, test := range testCases {
if _, err := api.GetLogs(context.Background(), test); err == nil {
t.Errorf("Expected Logs for case #%d to fail", i)
}
}
}

// TestLogFilter tests whether log filters match the correct logs that are posted to the event feed.
func TestLogFilter(t *testing.T) {
t.Parallel()
Expand Down
1 change: 1 addition & 0 deletions interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ type ContractCaller interface {

// FilterQuery contains options for contract log filtering.
type FilterQuery struct {
BlockHash *common.Hash // used by eth_getLogs, return logs only from block with this hash
FromBlock *big.Int // beginning of the queried range, nil means genesis block
ToBlock *big.Int // end of the range, nil means latest block
Addresses []common.Address // restricts matches to events created by specific contracts
Expand Down