@ -19,7 +19,6 @@ package filters
import (
import (
"context"
"context"
"errors"
"errors"
"fmt"
"math/big"
"math/big"
"math/rand"
"math/rand"
"reflect"
"reflect"
@ -27,15 +26,12 @@ import (
"testing"
"testing"
"time"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/ethapi"
@ -125,10 +121,6 @@ func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash, number uint
return logs , nil
return logs , nil
}
}
func ( b * testBackend ) Pending ( ) ( * types . Block , types . Receipts , * state . StateDB ) {
return b . pendingBlock , b . pendingReceipts , nil
}
func ( b * testBackend ) SubscribeNewTxsEvent ( ch chan <- core . NewTxsEvent ) event . Subscription {
func ( b * testBackend ) SubscribeNewTxsEvent ( ch chan <- core . NewTxsEvent ) event . Subscription {
return b . txFeed . Subscribe ( ch )
return b . txFeed . Subscribe ( ch )
}
}
@ -181,15 +173,6 @@ func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) {
b . pendingReceipts = receipts
b . pendingReceipts = receipts
}
}
func ( b * testBackend ) notifyPending ( logs [ ] * types . Log ) {
genesis := & core . Genesis {
Config : params . TestChainConfig ,
}
_ , blocks , _ := core . GenerateChainWithGenesis ( genesis , ethash . NewFaker ( ) , 2 , func ( i int , b * core . BlockGen ) { } )
b . setPending ( blocks [ 1 ] , [ ] * types . Receipt { { Logs : logs } } )
b . chainFeed . Send ( core . ChainEvent { Block : blocks [ 0 ] } )
}
func newTestFilterSystem ( t testing . TB , db ethdb . Database , cfg Config ) ( * testBackend , * FilterSystem ) {
func newTestFilterSystem ( t testing . TB , db ethdb . Database , cfg Config ) ( * testBackend , * FilterSystem ) {
backend := & testBackend { db : db }
backend := & testBackend { db : db }
sys := NewFilterSystem ( backend , cfg )
sys := NewFilterSystem ( backend , cfg )
@ -207,7 +190,7 @@ func TestBlockSubscription(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
backend , sys = newTestFilterSystem ( t , db , Config { } )
backend , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
genesis = & core . Genesis {
genesis = & core . Genesis {
Config : params . TestChainConfig ,
Config : params . TestChainConfig ,
BaseFee : big . NewInt ( params . InitialBaseFee ) ,
BaseFee : big . NewInt ( params . InitialBaseFee ) ,
@ -262,7 +245,7 @@ func TestPendingTxFilter(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
backend , sys = newTestFilterSystem ( t , db , Config { } )
backend , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
transactions = [ ] * types . Transaction {
transactions = [ ] * types . Transaction {
types . NewTransaction ( 0 , common . HexToAddress ( "0xb794f5ea0ba39494ce83a213fffba74279579268" ) , new ( big . Int ) , 0 , new ( big . Int ) , nil ) ,
types . NewTransaction ( 0 , common . HexToAddress ( "0xb794f5ea0ba39494ce83a213fffba74279579268" ) , new ( big . Int ) , 0 , new ( big . Int ) , nil ) ,
@ -318,7 +301,7 @@ func TestPendingTxFilterFullTx(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
backend , sys = newTestFilterSystem ( t , db , Config { } )
backend , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
transactions = [ ] * types . Transaction {
transactions = [ ] * types . Transaction {
types . NewTransaction ( 0 , common . HexToAddress ( "0xb794f5ea0ba39494ce83a213fffba74279579268" ) , new ( big . Int ) , 0 , new ( big . Int ) , nil ) ,
types . NewTransaction ( 0 , common . HexToAddress ( "0xb794f5ea0ba39494ce83a213fffba74279579268" ) , new ( big . Int ) , 0 , new ( big . Int ) , nil ) ,
@ -374,7 +357,7 @@ func TestLogFilterCreation(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
_ , sys = newTestFilterSystem ( t , db , Config { } )
_ , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
testCases = [ ] struct {
testCases = [ ] struct {
crit FilterCriteria
crit FilterCriteria
@ -386,8 +369,6 @@ func TestLogFilterCreation(t *testing.T) {
{ FilterCriteria { FromBlock : big . NewInt ( 1 ) , ToBlock : big . NewInt ( 2 ) } , true } ,
{ FilterCriteria { FromBlock : big . NewInt ( 1 ) , ToBlock : big . NewInt ( 2 ) } , true } ,
// "mined" block range to pending
// "mined" block range to pending
{ FilterCriteria { FromBlock : big . NewInt ( 1 ) , ToBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) } , true } ,
{ FilterCriteria { FromBlock : big . NewInt ( 1 ) , ToBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) } , true } ,
// new mined and pending blocks
{ FilterCriteria { FromBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) , ToBlock : big . NewInt ( rpc . PendingBlockNumber . Int64 ( ) ) } , true } ,
// from block "higher" than to block
// from block "higher" than to block
{ FilterCriteria { FromBlock : big . NewInt ( 2 ) , ToBlock : big . NewInt ( 1 ) } , false } ,
{ FilterCriteria { FromBlock : big . NewInt ( 2 ) , ToBlock : big . NewInt ( 1 ) } , false } ,
// from block "higher" than to block
// from block "higher" than to block
@ -423,7 +404,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
_ , sys = newTestFilterSystem ( t , db , Config { } )
_ , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
)
)
// different situations where log filter creation should fail.
// different situations where log filter creation should fail.
@ -449,7 +430,7 @@ func TestInvalidGetLogsRequest(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
_ , sys = newTestFilterSystem ( t , db , Config { } )
_ , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
blockHash = common . HexToHash ( "0x1111111111111111111111111111111111111111111111111111111111111111" )
blockHash = common . HexToHash ( "0x1111111111111111111111111111111111111111111111111111111111111111" )
)
)
@ -475,7 +456,7 @@ func TestInvalidGetRangeLogsRequest(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
_ , sys = newTestFilterSystem ( t , db , Config { } )
_ , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
)
)
if _ , err := api . GetLogs ( context . Background ( ) , FilterCriteria { FromBlock : big . NewInt ( 2 ) , ToBlock : big . NewInt ( 1 ) } ) ; err != errInvalidBlockRange {
if _ , err := api . GetLogs ( context . Background ( ) , FilterCriteria { FromBlock : big . NewInt ( 2 ) , ToBlock : big . NewInt ( 1 ) } ) ; err != errInvalidBlockRange {
@ -490,7 +471,7 @@ func TestLogFilter(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
backend , sys = newTestFilterSystem ( t , db , Config { } )
backend , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
firstAddr = common . HexToAddress ( "0x1111111111111111111111111111111111111111" )
firstAddr = common . HexToAddress ( "0x1111111111111111111111111111111111111111" )
secondAddr = common . HexToAddress ( "0x2222222222222222222222222222222222222222" )
secondAddr = common . HexToAddress ( "0x2222222222222222222222222222222222222222" )
@ -509,9 +490,6 @@ func TestLogFilter(t *testing.T) {
{ Address : thirdAddress , Topics : [ ] common . Hash { secondTopic } , BlockNumber : 3 } ,
{ Address : thirdAddress , Topics : [ ] common . Hash { secondTopic } , BlockNumber : 3 } ,
}
}
expectedCase7 = [ ] * types . Log { allLogs [ 3 ] , allLogs [ 4 ] , allLogs [ 0 ] , allLogs [ 1 ] , allLogs [ 2 ] , allLogs [ 3 ] , allLogs [ 4 ] }
expectedCase11 = [ ] * types . Log { allLogs [ 1 ] , allLogs [ 2 ] , allLogs [ 1 ] , allLogs [ 2 ] }
testCases = [ ] struct {
testCases = [ ] struct {
crit FilterCriteria
crit FilterCriteria
expected [ ] * types . Log
expected [ ] * types . Log
@ -529,20 +507,14 @@ func TestLogFilter(t *testing.T) {
4 : { FilterCriteria { Addresses : [ ] common . Address { thirdAddress } , Topics : [ ] [ ] common . Hash { { firstTopic , secondTopic } } } , allLogs [ 3 : 5 ] , "" } ,
4 : { FilterCriteria { Addresses : [ ] common . Address { thirdAddress } , Topics : [ ] [ ] common . Hash { { firstTopic , secondTopic } } } , allLogs [ 3 : 5 ] , "" } ,
// match logs based on multiple addresses and "or" topics
// match logs based on multiple addresses and "or" topics
5 : { FilterCriteria { Addresses : [ ] common . Address { secondAddr , thirdAddress } , Topics : [ ] [ ] common . Hash { { firstTopic , secondTopic } } } , allLogs [ 2 : 5 ] , "" } ,
5 : { FilterCriteria { Addresses : [ ] common . Address { secondAddr , thirdAddress } , Topics : [ ] [ ] common . Hash { { firstTopic , secondTopic } } } , allLogs [ 2 : 5 ] , "" } ,
// logs in the pending block
6 : { FilterCriteria { Addresses : [ ] common . Address { firstAddr } , FromBlock : big . NewInt ( rpc . PendingBlockNumber . Int64 ( ) ) , ToBlock : big . NewInt ( rpc . PendingBlockNumber . Int64 ( ) ) } , allLogs [ : 2 ] , "" } ,
// mined logs with block num >= 2 or pending logs
7 : { FilterCriteria { FromBlock : big . NewInt ( 2 ) , ToBlock : big . NewInt ( rpc . PendingBlockNumber . Int64 ( ) ) } , expectedCase7 , "" } ,
// all "mined" logs with block num >= 2
// all "mined" logs with block num >= 2
8 : { FilterCriteria { FromBlock : big . NewInt ( 2 ) , ToBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) } , allLogs [ 3 : ] , "" } ,
6 : { FilterCriteria { FromBlock : big . NewInt ( 2 ) , ToBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) } , allLogs [ 3 : ] , "" } ,
// all "mined" logs
// all "mined" logs
9 : { FilterCriteria { ToBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) } , allLogs , "" } ,
7 : { FilterCriteria { ToBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) } , allLogs , "" } ,
// all "mined" logs with 1>= block num <=2 and topic secondTopic
// all "mined" logs with 1>= block num <=2 and topic secondTopic
10 : { FilterCriteria { FromBlock : big . NewInt ( 1 ) , ToBlock : big . NewInt ( 2 ) , Topics : [ ] [ ] common . Hash { { secondTopic } } } , allLogs [ 3 : 4 ] , "" } ,
8 : { FilterCriteria { FromBlock : big . NewInt ( 1 ) , ToBlock : big . NewInt ( 2 ) , Topics : [ ] [ ] common . Hash { { secondTopic } } } , allLogs [ 3 : 4 ] , "" } ,
// all "mined" and pending logs with topic firstTopic
11 : { FilterCriteria { FromBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) , ToBlock : big . NewInt ( rpc . PendingBlockNumber . Int64 ( ) ) , Topics : [ ] [ ] common . Hash { { firstTopic } } } , expectedCase11 , "" } ,
// match all logs due to wildcard topic
// match all logs due to wildcard topic
12 : { FilterCriteria { Topics : [ ] [ ] common . Hash { nil } } , allLogs [ 1 : ] , "" } ,
9 : { FilterCriteria { Topics : [ ] [ ] common . Hash { nil } } , allLogs [ 1 : ] , "" } ,
}
}
)
)
@ -557,16 +529,13 @@ func TestLogFilter(t *testing.T) {
t . Fatal ( "Logs event not delivered" )
t . Fatal ( "Logs event not delivered" )
}
}
// set pending logs
backend . notifyPending ( allLogs )
for i , tt := range testCases {
for i , tt := range testCases {
var fetched [ ] * types . Log
var fetched [ ] * types . Log
timeout := time . Now ( ) . Add ( 1 * time . Second )
timeout := time . Now ( ) . Add ( 1 * time . Second )
for { // fetch all expected logs
for { // fetch all expected logs
results , err := api . GetFilterChanges ( tt . id )
results , err := api . GetFilterChanges ( tt . id )
if err != nil {
if err != nil {
t . Fatalf ( "Unable to fetch logs: %v" , err )
t . Fatalf ( "test %d: unable to fetch logs: %v" , i , err )
}
}
fetched = append ( fetched , results . ( [ ] * types . Log ) ... )
fetched = append ( fetched , results . ( [ ] * types . Log ) ... )
@ -597,326 +566,6 @@ func TestLogFilter(t *testing.T) {
}
}
}
}
// TestPendingLogsSubscription tests if a subscription receives the correct pending logs that are posted to the event feed.
func TestPendingLogsSubscription ( t * testing . T ) {
t . Parallel ( )
var (
db = rawdb . NewMemoryDatabase ( )
backend , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , false )
firstAddr = common . HexToAddress ( "0x1111111111111111111111111111111111111111" )
secondAddr = common . HexToAddress ( "0x2222222222222222222222222222222222222222" )
thirdAddress = common . HexToAddress ( "0x3333333333333333333333333333333333333333" )
notUsedAddress = common . HexToAddress ( "0x9999999999999999999999999999999999999999" )
firstTopic = common . HexToHash ( "0x1111111111111111111111111111111111111111111111111111111111111111" )
secondTopic = common . HexToHash ( "0x2222222222222222222222222222222222222222222222222222222222222222" )
thirdTopic = common . HexToHash ( "0x3333333333333333333333333333333333333333333333333333333333333333" )
fourthTopic = common . HexToHash ( "0x4444444444444444444444444444444444444444444444444444444444444444" )
notUsedTopic = common . HexToHash ( "0x9999999999999999999999999999999999999999999999999999999999999999" )
allLogs = [ ] [ ] * types . Log {
{ { Address : firstAddr , Topics : [ ] common . Hash { } , BlockNumber : 0 } } ,
{ { Address : firstAddr , Topics : [ ] common . Hash { firstTopic } , BlockNumber : 1 } } ,
{ { Address : secondAddr , Topics : [ ] common . Hash { firstTopic } , BlockNumber : 2 } } ,
{ { Address : thirdAddress , Topics : [ ] common . Hash { secondTopic } , BlockNumber : 3 } } ,
{ { Address : thirdAddress , Topics : [ ] common . Hash { secondTopic } , BlockNumber : 4 } } ,
{
{ Address : thirdAddress , Topics : [ ] common . Hash { firstTopic } , BlockNumber : 5 } ,
{ Address : thirdAddress , Topics : [ ] common . Hash { thirdTopic } , BlockNumber : 5 } ,
{ Address : thirdAddress , Topics : [ ] common . Hash { fourthTopic } , BlockNumber : 5 } ,
{ Address : firstAddr , Topics : [ ] common . Hash { firstTopic } , BlockNumber : 5 } ,
} ,
}
pendingBlockNumber = big . NewInt ( rpc . PendingBlockNumber . Int64 ( ) )
testCases = [ ] struct {
crit ethereum . FilterQuery
expected [ ] * types . Log
c chan [ ] * types . Log
sub * Subscription
err chan error
} {
// match all
{
ethereum . FilterQuery { FromBlock : pendingBlockNumber , ToBlock : pendingBlockNumber } ,
flattenLogs ( allLogs ) ,
nil , nil , nil ,
} ,
// match none due to no matching addresses
{
ethereum . FilterQuery { Addresses : [ ] common . Address { { } , notUsedAddress } , Topics : [ ] [ ] common . Hash { nil } , FromBlock : pendingBlockNumber , ToBlock : pendingBlockNumber } ,
nil ,
nil , nil , nil ,
} ,
// match logs based on addresses, ignore topics
{
ethereum . FilterQuery { Addresses : [ ] common . Address { firstAddr } , FromBlock : pendingBlockNumber , ToBlock : pendingBlockNumber } ,
append ( flattenLogs ( allLogs [ : 2 ] ) , allLogs [ 5 ] [ 3 ] ) ,
nil , nil , nil ,
} ,
// match none due to no matching topics (match with address)
{
ethereum . FilterQuery { Addresses : [ ] common . Address { secondAddr } , Topics : [ ] [ ] common . Hash { { notUsedTopic } } , FromBlock : pendingBlockNumber , ToBlock : pendingBlockNumber } ,
nil ,
nil , nil , nil ,
} ,
// match logs based on addresses and topics
{
ethereum . FilterQuery { Addresses : [ ] common . Address { thirdAddress } , Topics : [ ] [ ] common . Hash { { firstTopic , secondTopic } } , FromBlock : pendingBlockNumber , ToBlock : pendingBlockNumber } ,
append ( flattenLogs ( allLogs [ 3 : 5 ] ) , allLogs [ 5 ] [ 0 ] ) ,
nil , nil , nil ,
} ,
// match logs based on multiple addresses and "or" topics
{
ethereum . FilterQuery { Addresses : [ ] common . Address { secondAddr , thirdAddress } , Topics : [ ] [ ] common . Hash { { firstTopic , secondTopic } } , FromBlock : pendingBlockNumber , ToBlock : pendingBlockNumber } ,
append ( flattenLogs ( allLogs [ 2 : 5 ] ) , allLogs [ 5 ] [ 0 ] ) ,
nil , nil , nil ,
} ,
// multiple pending logs, should match only 2 topics from the logs in block 5
{
ethereum . FilterQuery { Addresses : [ ] common . Address { thirdAddress } , Topics : [ ] [ ] common . Hash { { firstTopic , fourthTopic } } , FromBlock : pendingBlockNumber , ToBlock : pendingBlockNumber } ,
[ ] * types . Log { allLogs [ 5 ] [ 0 ] , allLogs [ 5 ] [ 2 ] } ,
nil , nil , nil ,
} ,
// match none due to only matching new mined logs
{
ethereum . FilterQuery { } ,
nil ,
nil , nil , nil ,
} ,
// match none due to only matching mined logs within a specific block range
{
ethereum . FilterQuery { FromBlock : big . NewInt ( 1 ) , ToBlock : big . NewInt ( 2 ) } ,
nil ,
nil , nil , nil ,
} ,
// match all due to matching mined and pending logs
{
ethereum . FilterQuery { FromBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) , ToBlock : big . NewInt ( rpc . PendingBlockNumber . Int64 ( ) ) } ,
flattenLogs ( allLogs ) ,
nil , nil , nil ,
} ,
// match none due to matching logs from a specific block number to new mined blocks
{
ethereum . FilterQuery { FromBlock : big . NewInt ( 1 ) , ToBlock : big . NewInt ( rpc . LatestBlockNumber . Int64 ( ) ) } ,
nil ,
nil , nil , nil ,
} ,
}
)
// create all subscriptions, this ensures all subscriptions are created before the events are posted.
// on slow machines this could otherwise lead to missing events when the subscription is created after
// (some) events are posted.
for i := range testCases {
testCases [ i ] . c = make ( chan [ ] * types . Log )
testCases [ i ] . err = make ( chan error , 1 )
var err error
testCases [ i ] . sub , err = api . events . SubscribeLogs ( testCases [ i ] . crit , testCases [ i ] . c )
if err != nil {
t . Fatalf ( "SubscribeLogs %d failed: %v\n" , i , err )
}
}
for n , test := range testCases {
i := n
tt := test
go func ( ) {
defer tt . sub . Unsubscribe ( )
var fetched [ ] * types . Log
timeout := time . After ( 1 * time . Second )
fetchLoop :
for {
select {
case logs := <- tt . c :
// Do not break early if we've fetched greater, or equal,
// to the number of logs expected. This ensures we do not
// deadlock the filter system because it will do a blocking
// send on this channel if another log arrives.
fetched = append ( fetched , logs ... )
case <- timeout :
break fetchLoop
}
}
if len ( fetched ) != len ( tt . expected ) {
tt . err <- fmt . Errorf ( "invalid number of logs for case %d, want %d log(s), got %d" , i , len ( tt . expected ) , len ( fetched ) )
return
}
for l := range fetched {
if fetched [ l ] . Removed {
tt . err <- fmt . Errorf ( "expected log not to be removed for log %d in case %d" , l , i )
return
}
if ! reflect . DeepEqual ( fetched [ l ] , tt . expected [ l ] ) {
tt . err <- fmt . Errorf ( "invalid log on index %d for case %d\n" , l , i )
return
}
}
tt . err <- nil
} ( )
}
// set pending logs
var flattenLogs [ ] * types . Log
for _ , logs := range allLogs {
flattenLogs = append ( flattenLogs , logs ... )
}
backend . notifyPending ( flattenLogs )
for i := range testCases {
err := <- testCases [ i ] . err
if err != nil {
t . Fatalf ( "test %d failed: %v" , i , err )
}
<- testCases [ i ] . sub . Err ( )
}
}
func TestLightFilterLogs ( t * testing . T ) {
t . Parallel ( )
var (
db = rawdb . NewMemoryDatabase ( )
backend , sys = newTestFilterSystem ( t , db , Config { } )
api = NewFilterAPI ( sys , true )
signer = types . HomesteadSigner { }
firstAddr = common . HexToAddress ( "0x1111111111111111111111111111111111111111" )
secondAddr = common . HexToAddress ( "0x2222222222222222222222222222222222222222" )
thirdAddress = common . HexToAddress ( "0x3333333333333333333333333333333333333333" )
notUsedAddress = common . HexToAddress ( "0x9999999999999999999999999999999999999999" )
firstTopic = common . HexToHash ( "0x1111111111111111111111111111111111111111111111111111111111111111" )
secondTopic = common . HexToHash ( "0x2222222222222222222222222222222222222222222222222222222222222222" )
// posted twice, once as regular logs and once as pending logs.
allLogs = [ ] * types . Log {
// Block 1
{ Address : firstAddr , Topics : [ ] common . Hash { } , Data : [ ] byte { } , BlockNumber : 2 , Index : 0 } ,
// Block 2
{ Address : firstAddr , Topics : [ ] common . Hash { firstTopic } , Data : [ ] byte { } , BlockNumber : 3 , Index : 0 } ,
{ Address : secondAddr , Topics : [ ] common . Hash { firstTopic } , Data : [ ] byte { } , BlockNumber : 3 , Index : 1 } ,
{ Address : thirdAddress , Topics : [ ] common . Hash { secondTopic } , Data : [ ] byte { } , BlockNumber : 3 , Index : 2 } ,
// Block 3
{ Address : thirdAddress , Topics : [ ] common . Hash { secondTopic } , Data : [ ] byte { } , BlockNumber : 4 , Index : 0 } ,
}
testCases = [ ] struct {
crit FilterCriteria
expected [ ] * types . Log
id rpc . ID
} {
// match all
0 : { FilterCriteria { } , allLogs , "" } ,
// match none due to no matching addresses
1 : { FilterCriteria { Addresses : [ ] common . Address { { } , notUsedAddress } , Topics : [ ] [ ] common . Hash { nil } } , [ ] * types . Log { } , "" } ,
// match logs based on addresses, ignore topics
2 : { FilterCriteria { Addresses : [ ] common . Address { firstAddr } } , allLogs [ : 2 ] , "" } ,
// match logs based on addresses and topics
3 : { FilterCriteria { Addresses : [ ] common . Address { thirdAddress } , Topics : [ ] [ ] common . Hash { { firstTopic , secondTopic } } } , allLogs [ 3 : 5 ] , "" } ,
// all logs with block num >= 3
4 : { FilterCriteria { FromBlock : big . NewInt ( 3 ) , ToBlock : big . NewInt ( 5 ) } , allLogs [ 1 : ] , "" } ,
// all logs
5 : { FilterCriteria { FromBlock : big . NewInt ( 0 ) , ToBlock : big . NewInt ( 5 ) } , allLogs , "" } ,
// all logs with 1>= block num <=2 and topic secondTopic
6 : { FilterCriteria { FromBlock : big . NewInt ( 2 ) , ToBlock : big . NewInt ( 3 ) , Topics : [ ] [ ] common . Hash { { secondTopic } } } , allLogs [ 3 : 4 ] , "" } ,
}
key , _ = crypto . GenerateKey ( )
addr = crypto . PubkeyToAddress ( key . PublicKey )
genesis = & core . Genesis { Config : params . TestChainConfig ,
Alloc : types . GenesisAlloc {
addr : { Balance : big . NewInt ( params . Ether ) } ,
} ,
}
receipts = [ ] * types . Receipt { {
Logs : [ ] * types . Log { allLogs [ 0 ] } ,
} , {
Logs : [ ] * types . Log { allLogs [ 1 ] , allLogs [ 2 ] , allLogs [ 3 ] } ,
} , {
Logs : [ ] * types . Log { allLogs [ 4 ] } ,
} }
)
_ , blocks , _ := core . GenerateChainWithGenesis ( genesis , ethash . NewFaker ( ) , 4 , func ( i int , b * core . BlockGen ) {
if i == 0 {
return
}
receipts [ i - 1 ] . Bloom = types . CreateBloom ( types . Receipts { receipts [ i - 1 ] } )
b . AddUncheckedReceipt ( receipts [ i - 1 ] )
tx , _ := types . SignTx ( types . NewTx ( & types . LegacyTx { Nonce : uint64 ( i - 1 ) , To : & common . Address { } , Value : big . NewInt ( 1000 ) , Gas : params . TxGas , GasPrice : b . BaseFee ( ) , Data : nil } ) , signer , key )
b . AddTx ( tx )
} )
for i , block := range blocks {
rawdb . WriteBlock ( db , block )
rawdb . WriteCanonicalHash ( db , block . Hash ( ) , block . NumberU64 ( ) )
rawdb . WriteHeadBlockHash ( db , block . Hash ( ) )
if i > 0 {
rawdb . WriteReceipts ( db , block . Hash ( ) , block . NumberU64 ( ) , [ ] * types . Receipt { receipts [ i - 1 ] } )
}
}
// create all filters
for i := range testCases {
id , err := api . NewFilter ( testCases [ i ] . crit )
if err != nil {
t . Fatal ( err )
}
testCases [ i ] . id = id
}
// raise events
time . Sleep ( 1 * time . Second )
for _ , block := range blocks {
backend . chainFeed . Send ( core . ChainEvent { Block : block , Hash : common . Hash { } , Logs : allLogs } )
}
for i , tt := range testCases {
var fetched [ ] * types . Log
timeout := time . Now ( ) . Add ( 1 * time . Second )
for { // fetch all expected logs
results , err := api . GetFilterChanges ( tt . id )
if err != nil {
t . Fatalf ( "Unable to fetch logs: %v" , err )
}
fetched = append ( fetched , results . ( [ ] * types . Log ) ... )
if len ( fetched ) >= len ( tt . expected ) {
break
}
// check timeout
if time . Now ( ) . After ( timeout ) {
break
}
time . Sleep ( 100 * time . Millisecond )
}
if len ( fetched ) != len ( tt . expected ) {
t . Errorf ( "invalid number of logs for case %d, want %d log(s), got %d" , i , len ( tt . expected ) , len ( fetched ) )
return
}
for l := range fetched {
if fetched [ l ] . Removed {
t . Errorf ( "expected log not to be removed for log %d in case %d" , l , i )
}
expected := * tt . expected [ l ]
blockNum := expected . BlockNumber - 1
expected . BlockHash = blocks [ blockNum ] . Hash ( )
expected . TxHash = blocks [ blockNum ] . Transactions ( ) [ 0 ] . Hash ( )
if ! reflect . DeepEqual ( fetched [ l ] , & expected ) {
t . Errorf ( "invalid log on index %d for case %d" , l , i )
}
}
}
}
// TestPendingTxFilterDeadlock tests if the event loop hangs when pending
// TestPendingTxFilterDeadlock tests if the event loop hangs when pending
// txes arrive at the same time that one of multiple filters is timing out.
// txes arrive at the same time that one of multiple filters is timing out.
// Please refer to #22131 for more details.
// Please refer to #22131 for more details.
@ -927,7 +576,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) {
var (
var (
db = rawdb . NewMemoryDatabase ( )
db = rawdb . NewMemoryDatabase ( )
backend , sys = newTestFilterSystem ( t , db , Config { Timeout : timeout } )
backend , sys = newTestFilterSystem ( t , db , Config { Timeout : timeout } )
api = NewFilterAPI ( sys , false )
api = NewFilterAPI ( sys )
done = make ( chan struct { } )
done = make ( chan struct { } )
)
)
@ -979,11 +628,3 @@ func TestPendingTxFilterDeadlock(t *testing.T) {
}
}
}
}
}
}
func flattenLogs ( pl [ ] [ ] * types . Log ) [ ] * types . Log {
var logs [ ] * types . Log
for _ , l := range pl {
logs = append ( logs , l ... )
}
return logs
}