|
|
@ -34,13 +34,6 @@ import ( |
|
|
|
"github.com/ethereum/go-ethereum/rpc" |
|
|
|
"github.com/ethereum/go-ethereum/rpc" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
mux = new(event.TypeMux) |
|
|
|
|
|
|
|
db, _ = ethdb.NewMemDatabase() |
|
|
|
|
|
|
|
backend = &testBackend{mux, db} |
|
|
|
|
|
|
|
api = NewPublicFilterAPI(backend, false) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type testBackend struct { |
|
|
|
type testBackend struct { |
|
|
|
mux *event.TypeMux |
|
|
|
mux *event.TypeMux |
|
|
|
db ethdb.Database |
|
|
|
db ethdb.Database |
|
|
@ -81,6 +74,11 @@ func TestBlockSubscription(t *testing.T) { |
|
|
|
t.Parallel() |
|
|
|
t.Parallel() |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
|
|
|
|
mux = new(event.TypeMux) |
|
|
|
|
|
|
|
db, _ = ethdb.NewMemDatabase() |
|
|
|
|
|
|
|
backend = &testBackend{mux, db} |
|
|
|
|
|
|
|
api = NewPublicFilterAPI(backend, false) |
|
|
|
|
|
|
|
|
|
|
|
genesis = core.WriteGenesisBlockForTesting(db) |
|
|
|
genesis = core.WriteGenesisBlockForTesting(db) |
|
|
|
chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {}) |
|
|
|
chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {}) |
|
|
|
chainEvents = []core.ChainEvent{} |
|
|
|
chainEvents = []core.ChainEvent{} |
|
|
@ -130,6 +128,11 @@ func TestPendingTxFilter(t *testing.T) { |
|
|
|
t.Parallel() |
|
|
|
t.Parallel() |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
|
|
|
|
mux = new(event.TypeMux) |
|
|
|
|
|
|
|
db, _ = ethdb.NewMemDatabase() |
|
|
|
|
|
|
|
backend = &testBackend{mux, db} |
|
|
|
|
|
|
|
api = NewPublicFilterAPI(backend, false) |
|
|
|
|
|
|
|
|
|
|
|
transactions = []*types.Transaction{ |
|
|
|
transactions = []*types.Transaction{ |
|
|
|
types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), |
|
|
|
types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), |
|
|
|
types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), |
|
|
|
types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), |
|
|
@ -150,9 +153,13 @@ func TestPendingTxFilter(t *testing.T) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for { |
|
|
|
for { |
|
|
|
h := api.GetFilterChanges(fid0).([]common.Hash) |
|
|
|
results, err := api.GetFilterChanges(fid0) |
|
|
|
hashes = append(hashes, h...) |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
t.Fatalf("Unable to retrieve logs: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
h := results.([]common.Hash) |
|
|
|
|
|
|
|
hashes = append(hashes, h...) |
|
|
|
if len(hashes) >= len(transactions) { |
|
|
|
if len(hashes) >= len(transactions) { |
|
|
|
break |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
@ -167,11 +174,86 @@ func TestPendingTxFilter(t *testing.T) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TestLogFilterCreation test whether a given filter criteria makes sense.
|
|
|
|
|
|
|
|
// If not it must return an error.
|
|
|
|
|
|
|
|
func TestLogFilterCreation(t *testing.T) { |
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
mux = new(event.TypeMux) |
|
|
|
|
|
|
|
db, _ = ethdb.NewMemDatabase() |
|
|
|
|
|
|
|
backend = &testBackend{mux, db} |
|
|
|
|
|
|
|
api = NewPublicFilterAPI(backend, false) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
testCases = []struct { |
|
|
|
|
|
|
|
crit FilterCriteria |
|
|
|
|
|
|
|
success bool |
|
|
|
|
|
|
|
}{ |
|
|
|
|
|
|
|
// defaults
|
|
|
|
|
|
|
|
{FilterCriteria{}, true}, |
|
|
|
|
|
|
|
// valid block number range
|
|
|
|
|
|
|
|
{FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true}, |
|
|
|
|
|
|
|
// "mined" block range to pending
|
|
|
|
|
|
|
|
{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
|
|
|
|
|
|
|
|
{FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false}, |
|
|
|
|
|
|
|
// from block "higher" than to block
|
|
|
|
|
|
|
|
{FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, |
|
|
|
|
|
|
|
// from block "higher" than to block
|
|
|
|
|
|
|
|
{FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, |
|
|
|
|
|
|
|
// from block "higher" than to block
|
|
|
|
|
|
|
|
{FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false}, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i, test := range testCases { |
|
|
|
|
|
|
|
_, err := api.NewFilter(test.crit) |
|
|
|
|
|
|
|
if test.success && err != nil { |
|
|
|
|
|
|
|
t.Errorf("expected filter creation for case %d to success, got %v", i, err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if !test.success && err == nil { |
|
|
|
|
|
|
|
t.Errorf("expected testcase %d to fail with an error", i) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TestInvalidLogFilterCreation tests whether invalid filter log criteria results in an error
|
|
|
|
|
|
|
|
// when the filter is created.
|
|
|
|
|
|
|
|
func TestInvalidLogFilterCreation(t *testing.T) { |
|
|
|
|
|
|
|
t.Parallel() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
mux = new(event.TypeMux) |
|
|
|
|
|
|
|
db, _ = ethdb.NewMemDatabase() |
|
|
|
|
|
|
|
backend = &testBackend{mux, db} |
|
|
|
|
|
|
|
api = NewPublicFilterAPI(backend, false) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// different situations where log filter creation should fail.
|
|
|
|
|
|
|
|
// Reason: fromBlock > toBlock
|
|
|
|
|
|
|
|
testCases := []FilterCriteria{ |
|
|
|
|
|
|
|
0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, |
|
|
|
|
|
|
|
1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, |
|
|
|
|
|
|
|
2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i, test := range testCases { |
|
|
|
|
|
|
|
if _, err := api.NewFilter(test); err == nil { |
|
|
|
|
|
|
|
t.Errorf("Expected NewFilter for case #%d to fail", i) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TestLogFilter tests whether log filters match the correct logs that are posted to the event mux.
|
|
|
|
// TestLogFilter tests whether log filters match the correct logs that are posted to the event mux.
|
|
|
|
func TestLogFilter(t *testing.T) { |
|
|
|
func TestLogFilter(t *testing.T) { |
|
|
|
t.Parallel() |
|
|
|
t.Parallel() |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
|
|
|
|
mux = new(event.TypeMux) |
|
|
|
|
|
|
|
db, _ = ethdb.NewMemDatabase() |
|
|
|
|
|
|
|
backend = &testBackend{mux, db} |
|
|
|
|
|
|
|
api = NewPublicFilterAPI(backend, false) |
|
|
|
|
|
|
|
|
|
|
|
firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") |
|
|
|
firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") |
|
|
|
secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") |
|
|
|
secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") |
|
|
|
thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") |
|
|
|
thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") |
|
|
@ -180,8 +262,8 @@ func TestLogFilter(t *testing.T) { |
|
|
|
secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") |
|
|
|
secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") |
|
|
|
notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") |
|
|
|
notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// posted twice, once as vm.Logs and once as core.PendingLogsEvent
|
|
|
|
allLogs = vm.Logs{ |
|
|
|
allLogs = vm.Logs{ |
|
|
|
// Note, these are used for comparison of the test cases.
|
|
|
|
|
|
|
|
vm.NewLog(firstAddr, []common.Hash{}, []byte(""), 0), |
|
|
|
vm.NewLog(firstAddr, []common.Hash{}, []byte(""), 0), |
|
|
|
vm.NewLog(firstAddr, []common.Hash{firstTopic}, []byte(""), 1), |
|
|
|
vm.NewLog(firstAddr, []common.Hash{firstTopic}, []byte(""), 1), |
|
|
|
vm.NewLog(secondAddr, []common.Hash{firstTopic}, []byte(""), 1), |
|
|
|
vm.NewLog(secondAddr, []common.Hash{firstTopic}, []byte(""), 1), |
|
|
@ -189,45 +271,64 @@ func TestLogFilter(t *testing.T) { |
|
|
|
vm.NewLog(thirdAddress, []common.Hash{secondTopic}, []byte(""), 3), |
|
|
|
vm.NewLog(thirdAddress, []common.Hash{secondTopic}, []byte(""), 3), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expectedCase7 = vm.Logs{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]} |
|
|
|
|
|
|
|
expectedCase11 = vm.Logs{allLogs[1], allLogs[2], allLogs[1], allLogs[2]} |
|
|
|
|
|
|
|
|
|
|
|
testCases = []struct { |
|
|
|
testCases = []struct { |
|
|
|
crit FilterCriteria |
|
|
|
crit FilterCriteria |
|
|
|
expected vm.Logs |
|
|
|
expected vm.Logs |
|
|
|
id rpc.ID |
|
|
|
id rpc.ID |
|
|
|
}{ |
|
|
|
}{ |
|
|
|
// match all
|
|
|
|
// match all
|
|
|
|
{FilterCriteria{}, allLogs, ""}, |
|
|
|
0: {FilterCriteria{}, allLogs, ""}, |
|
|
|
// match none due to no matching addresses
|
|
|
|
// match none due to no matching addresses
|
|
|
|
{FilterCriteria{Addresses: []common.Address{common.Address{}, notUsedAddress}, Topics: [][]common.Hash{allLogs[0].Topics}}, vm.Logs{}, ""}, |
|
|
|
1: {FilterCriteria{Addresses: []common.Address{common.Address{}, notUsedAddress}, Topics: [][]common.Hash{allLogs[0].Topics}}, vm.Logs{}, ""}, |
|
|
|
// match logs based on addresses, ignore topics
|
|
|
|
// match logs based on addresses, ignore topics
|
|
|
|
{FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, |
|
|
|
2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, |
|
|
|
// match none due to no matching topics (match with address)
|
|
|
|
// match none due to no matching topics (match with address)
|
|
|
|
{FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{[]common.Hash{notUsedTopic}}}, vm.Logs{}, ""}, |
|
|
|
3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{[]common.Hash{notUsedTopic}}}, vm.Logs{}, ""}, |
|
|
|
// match logs based on addresses and topics
|
|
|
|
// match logs based on addresses and topics
|
|
|
|
{FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{[]common.Hash{firstTopic, secondTopic}}}, allLogs[3:5], ""}, |
|
|
|
4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{[]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
|
|
|
|
{FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{[]common.Hash{firstTopic, secondTopic}}}, allLogs[2:5], ""}, |
|
|
|
5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{[]common.Hash{firstTopic, secondTopic}}}, allLogs[2:5], ""}, |
|
|
|
// block numbers are ignored for filters created with New***Filter, these return all logs that match the given criterias when the state changes
|
|
|
|
// logs in the pending block
|
|
|
|
{FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, allLogs[:2], ""}, |
|
|
|
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
|
|
|
|
|
|
|
|
8: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""}, |
|
|
|
|
|
|
|
// all "mined" logs
|
|
|
|
|
|
|
|
9: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, |
|
|
|
|
|
|
|
// all "mined" logs with 1>= block num <=2 and topic secondTopic
|
|
|
|
|
|
|
|
10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{[]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{[]common.Hash{firstTopic}}}, expectedCase11, ""}, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
err error |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// create all filters
|
|
|
|
// create all filters
|
|
|
|
for i := range testCases { |
|
|
|
for i := range testCases { |
|
|
|
testCases[i].id = api.NewFilter(testCases[i].crit) |
|
|
|
testCases[i].id, _ = api.NewFilter(testCases[i].crit) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// raise events
|
|
|
|
// raise events
|
|
|
|
time.Sleep(1 * time.Second) |
|
|
|
time.Sleep(1 * time.Second) |
|
|
|
if err = mux.Post(allLogs); err != nil { |
|
|
|
if err := mux.Post(allLogs); err != nil { |
|
|
|
|
|
|
|
t.Fatal(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if err := mux.Post(core.PendingLogsEvent{Logs: allLogs}); err != nil { |
|
|
|
t.Fatal(err) |
|
|
|
t.Fatal(err) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for i, tt := range testCases { |
|
|
|
for i, tt := range testCases { |
|
|
|
var fetched []Log |
|
|
|
var fetched []Log |
|
|
|
for { // fetch all expected logs
|
|
|
|
for { // fetch all expected logs
|
|
|
|
fetched = append(fetched, api.GetFilterChanges(tt.id).([]Log)...) |
|
|
|
results, err := api.GetFilterChanges(tt.id) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
t.Fatalf("Unable to fetch logs: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fetched = append(fetched, results.([]Log)...) |
|
|
|
if len(fetched) >= len(tt.expected) { |
|
|
|
if len(fetched) >= len(tt.expected) { |
|
|
|
break |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
@ -247,7 +348,6 @@ func TestLogFilter(t *testing.T) { |
|
|
|
if !reflect.DeepEqual(fetched[l].Log, tt.expected[l]) { |
|
|
|
if !reflect.DeepEqual(fetched[l].Log, tt.expected[l]) { |
|
|
|
t.Errorf("invalid log on index %d for case %d", l, i) |
|
|
|
t.Errorf("invalid log on index %d for case %d", l, i) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -257,6 +357,11 @@ func TestPendingLogsSubscription(t *testing.T) { |
|
|
|
t.Parallel() |
|
|
|
t.Parallel() |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
|
|
|
|
mux = new(event.TypeMux) |
|
|
|
|
|
|
|
db, _ = ethdb.NewMemDatabase() |
|
|
|
|
|
|
|
backend = &testBackend{mux, db} |
|
|
|
|
|
|
|
api = NewPublicFilterAPI(backend, false) |
|
|
|
|
|
|
|
|
|
|
|
firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") |
|
|
|
firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") |
|
|
|
secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") |
|
|
|
secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") |
|
|
|
thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") |
|
|
|
thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") |
|
|
@ -319,7 +424,7 @@ func TestPendingLogsSubscription(t *testing.T) { |
|
|
|
// (some) events are posted.
|
|
|
|
// (some) events are posted.
|
|
|
|
for i := range testCases { |
|
|
|
for i := range testCases { |
|
|
|
testCases[i].c = make(chan []Log) |
|
|
|
testCases[i].c = make(chan []Log) |
|
|
|
testCases[i].sub = api.events.SubscribePendingLogs(testCases[i].crit, testCases[i].c) |
|
|
|
testCases[i].sub, _ = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for n, test := range testCases { |
|
|
|
for n, test := range testCases { |
|
|
|