mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
eth/filters,interfaces.go: Expand & modify TxFilterQuery
This commit is contained in:
parent
a92c854be5
commit
20eba82751
5 changed files with 82 additions and 49 deletions
|
|
@ -234,7 +234,7 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er
|
|||
func (api *PublicFilterAPI) NewReturnDataFilter(crit TxFilterCriteria) rpc.ID {
|
||||
var (
|
||||
retCh = make(chan []*types.ReturnData)
|
||||
retSub = api.events.SubscribeReturnData(retCh, ethereum.TxFilterQuery(crit))
|
||||
retSub = api.events.SubscribeReturnData(retCh, crit)
|
||||
)
|
||||
|
||||
api.filtersMu.Lock()
|
||||
|
|
@ -280,7 +280,7 @@ func (api *PublicFilterAPI) ReturnData(ctx context.Context, crit TxFilterCriteri
|
|||
|
||||
go func() {
|
||||
retCh := make(chan []*types.ReturnData)
|
||||
retSub := api.events.SubscribeReturnData(retCh, ethereum.TxFilterQuery(crit))
|
||||
retSub := api.events.SubscribeReturnData(retCh, crit)
|
||||
|
||||
for {
|
||||
select {
|
||||
|
|
@ -623,10 +623,16 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
|||
|
||||
// UnmarshalJSON sets *args fields with given data.
|
||||
func (args *TxFilterCriteria) UnmarshalJSON(data []byte) error {
|
||||
var err error
|
||||
var (
|
||||
err error
|
||||
from []common.Address
|
||||
to []common.Address
|
||||
)
|
||||
|
||||
type input struct {
|
||||
From interface{} `json:"from"`
|
||||
To interface{} `json:"to"`
|
||||
From interface{} `json:"from"`
|
||||
To interface{} `json:"to"`
|
||||
HasReturnData interface{} `json:"hasReturnData"`
|
||||
}
|
||||
|
||||
var raw input
|
||||
|
|
@ -638,17 +644,34 @@ func (args *TxFilterCriteria) UnmarshalJSON(data []byte) error {
|
|||
args.To = nil
|
||||
|
||||
if raw.From != nil {
|
||||
args.From, err = decodeAddresses(raw.From, "from")
|
||||
args.From = make(map[common.Address]struct{})
|
||||
from, err = decodeAddresses(raw.From, "from")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, addr := range from {
|
||||
args.From[addr] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if raw.To != nil {
|
||||
args.To, err = decodeAddresses(raw.To, "to")
|
||||
args.To = make(map[common.Address]struct{})
|
||||
to, err = decodeAddresses(raw.To, "to")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, addr := range to {
|
||||
args.To[addr] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if raw.HasReturnData != nil {
|
||||
switch hasReturnData := raw.HasReturnData.(type) {
|
||||
case bool:
|
||||
args.HasReturnData = hasReturnData
|
||||
default:
|
||||
return fmt.Errorf("Invalid HasReturnData field specified--must be true or false")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -656,7 +679,7 @@ func (args *TxFilterCriteria) UnmarshalJSON(data []byte) error {
|
|||
|
||||
// Decodes address field from JSON, which could be either
|
||||
// a single common.Address or an array []common.Address.
|
||||
// second arg is the name of the field being decoded, for error reporting.
|
||||
// Second arg is the name of the field being decoded, for error reporting.
|
||||
func decodeAddresses(addresses interface{}, field string) ([]common.Address, error) {
|
||||
decoded := []common.Address{}
|
||||
|
||||
|
|
|
|||
|
|
@ -276,34 +276,35 @@ Logs:
|
|||
return ret
|
||||
}
|
||||
|
||||
func filterTxs(txEvents []*core.TransactionEvent, from []common.Address, to []common.Address) (retData []*types.ReturnData) {
|
||||
func filterTxs(txEvents []*core.TransactionEvent, crit TxFilterCriteria) (retData []*types.ReturnData) {
|
||||
for _, ev := range txEvents {
|
||||
// check that From and To fields each match one address in the lists from and to, if specified
|
||||
|
||||
if from != nil {
|
||||
for _, addr := range from {
|
||||
if ev.From != nil && addr == *ev.From {
|
||||
goto checkRecipient
|
||||
}
|
||||
// if HasReturnData is true, filter out any transactions with no return data
|
||||
if crit.HasReturnData {
|
||||
if len(ev.RetData.Data) == 0 {
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
checkRecipient:
|
||||
if to != nil {
|
||||
for _, addr := range to {
|
||||
ev_to := ev.To
|
||||
if ev_to == nil { // contract creation
|
||||
ev_to = &common.Address{}
|
||||
}
|
||||
if addr == *ev_to {
|
||||
goto bothMatch
|
||||
}
|
||||
// check that From field of event matches an address in From, if specified
|
||||
if crit.From != nil && ev.From != nil {
|
||||
_, found := crit.From[*ev.From]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// check that To field of event matches an address in To, if specified
|
||||
if crit.To != nil {
|
||||
ev_to := ev.To
|
||||
if ev_to == nil {
|
||||
ev_to = &common.Address{}
|
||||
}
|
||||
_, found := crit.To[*ev.To]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
bothMatch:
|
||||
retData = append(retData, ev.RetData)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ type subscription struct {
|
|||
logs chan []*types.Log
|
||||
hashes chan common.Hash
|
||||
headers chan *types.Header
|
||||
txCrit ethereum.TxFilterQuery
|
||||
txCrit TxFilterCriteria
|
||||
retData chan []*types.ReturnData
|
||||
installed chan struct{} // closed when the filter is installed
|
||||
err chan error // closed when the filter is uninstalled
|
||||
|
|
@ -328,7 +328,7 @@ func (es *EventSystem) SubscribePendingTxEvents(hashes chan common.Hash) *Subscr
|
|||
|
||||
// SubscribeReturnData creates a subscription that captures return data for transactions
|
||||
// executed by a particular rpc client
|
||||
func (es *EventSystem) SubscribeReturnData(retCh chan []*types.ReturnData, crit ethereum.TxFilterQuery) *Subscription {
|
||||
func (es *EventSystem) SubscribeReturnData(retCh chan []*types.ReturnData, crit TxFilterCriteria) *Subscription {
|
||||
sub := &subscription{
|
||||
id: rpc.NewID(),
|
||||
typ: ReturnDataSubscription,
|
||||
|
|
@ -382,7 +382,7 @@ func (es *EventSystem) broadcast(filters filterIndex, ev interface{}) {
|
|||
case []*core.TransactionEvent:
|
||||
if len(e) > 0 {
|
||||
for _, f := range filters[ReturnDataSubscription] {
|
||||
if matchedTxs := filterTxs(e, f.txCrit.From, f.txCrit.To); len(matchedTxs) > 0 {
|
||||
if matchedTxs := filterTxs(e, f.txCrit); len(matchedTxs) > 0 {
|
||||
f.retData <- matchedTxs
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ func TestReturnDataFilter(t *testing.T) {
|
|||
firstRetData = common.Hex2Bytes("535353535353535353535353535353535353535353535353535353")
|
||||
secondRetData = common.Hex2Bytes("8888888888888888888888888888888888888888888888888888888888888888888888888888888888888")
|
||||
thirdRetData []byte = nil // no return data for this tx
|
||||
forthRetData = common.Hex2Bytes("0x77")
|
||||
forthRetData = common.Hex2Bytes("77")
|
||||
backend = &testBackend{mux, db, 0, txPreFeed, txPostFeed, rmLogsFeed, logsFeed, chainFeed}
|
||||
api = NewPublicFilterAPI(backend, false)
|
||||
)
|
||||
|
|
@ -320,24 +320,33 @@ func TestReturnDataFilter(t *testing.T) {
|
|||
{TxHash: retData[4].TxHash, RetData: &retData[4], From: &firstFromAddr, To: &secondToAddr},
|
||||
}
|
||||
|
||||
makeMap := func(addressList ...common.Address) map[common.Address]struct{} {
|
||||
addressSet := make(map[common.Address]struct{})
|
||||
for _, address := range addressList {
|
||||
addressSet[address] = struct{}{}
|
||||
}
|
||||
return addressSet
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
crit TxFilterCriteria
|
||||
expected []types.ReturnData
|
||||
id rpc.ID
|
||||
}{
|
||||
0: {TxFilterCriteria{From: []common.Address{secondFromAddr}}, []types.ReturnData{retData[1], retData[3]}, ""},
|
||||
1: {TxFilterCriteria{From: []common.Address{firstFromAddr}}, []types.ReturnData{retData[0], retData[2], retData[4]}, ""},
|
||||
2: {TxFilterCriteria{From: []common.Address{notUsedAddr}}, []types.ReturnData{}, ""},
|
||||
3: {TxFilterCriteria{From: []common.Address{notUsedAddr, secondFromAddr}}, []types.ReturnData{retData[1], retData[3]}, ""},
|
||||
4: {TxFilterCriteria{From: []common.Address{notUsedAddr, firstFromAddr, secondFromAddr}}, []types.ReturnData{retData[0], retData[1], retData[2], retData[3], retData[4]}, ""},
|
||||
5: {TxFilterCriteria{To: []common.Address{firstToAddr}}, []types.ReturnData{retData[0], retData[3]}, ""},
|
||||
6: {TxFilterCriteria{To: []common.Address{secondToAddr}}, []types.ReturnData{retData[1], retData[2], retData[4]}, ""},
|
||||
7: {TxFilterCriteria{To: []common.Address{firstToAddr, secondToAddr}}, []types.ReturnData{retData[0], retData[1], retData[2], retData[3], retData[4]}, ""},
|
||||
8: {TxFilterCriteria{To: []common.Address{notUsedAddr}}, []types.ReturnData{}, ""},
|
||||
9: {TxFilterCriteria{From: []common.Address{firstFromAddr}, To: []common.Address{secondToAddr}}, []types.ReturnData{retData[2], retData[4]}, ""},
|
||||
10: {TxFilterCriteria{From: []common.Address{notUsedAddr}, To: []common.Address{secondToAddr}}, []types.ReturnData{}, ""},
|
||||
11: {TxFilterCriteria{From: []common.Address{secondFromAddr}, To: []common.Address{secondToAddr, notUsedAddr}}, []types.ReturnData{retData[1]}, ""},
|
||||
0: {TxFilterCriteria{From: makeMap(secondFromAddr)}, []types.ReturnData{retData[1], retData[3]}, ""},
|
||||
1: {TxFilterCriteria{From: makeMap(firstFromAddr)}, []types.ReturnData{retData[0], retData[2], retData[4]}, ""},
|
||||
2: {TxFilterCriteria{From: makeMap(notUsedAddr)}, []types.ReturnData{}, ""},
|
||||
3: {TxFilterCriteria{From: makeMap(notUsedAddr, secondFromAddr)}, []types.ReturnData{retData[1], retData[3]}, ""},
|
||||
4: {TxFilterCriteria{From: makeMap(notUsedAddr, firstFromAddr, secondFromAddr)}, []types.ReturnData{retData[0], retData[1], retData[2], retData[3], retData[4]}, ""},
|
||||
5: {TxFilterCriteria{To: makeMap(firstToAddr)}, []types.ReturnData{retData[0], retData[3]}, ""},
|
||||
6: {TxFilterCriteria{To: makeMap(secondToAddr)}, []types.ReturnData{retData[1], retData[2], retData[4]}, ""},
|
||||
7: {TxFilterCriteria{To: makeMap(firstToAddr, secondToAddr)}, []types.ReturnData{retData[0], retData[1], retData[2], retData[3], retData[4]}, ""},
|
||||
8: {TxFilterCriteria{To: makeMap(notUsedAddr)}, []types.ReturnData{}, ""},
|
||||
9: {TxFilterCriteria{From: makeMap(firstFromAddr), To: makeMap(secondToAddr)}, []types.ReturnData{retData[2], retData[4]}, ""},
|
||||
10: {TxFilterCriteria{From: makeMap(notUsedAddr), To: makeMap(secondToAddr)}, []types.ReturnData{}, ""},
|
||||
11: {TxFilterCriteria{From: makeMap(secondFromAddr), To: makeMap(secondToAddr, notUsedAddr)}, []types.ReturnData{retData[1]}, ""},
|
||||
12: {TxFilterCriteria{}, []types.ReturnData{retData[0], retData[1], retData[2], retData[3], retData[4]}, ""},
|
||||
13: {TxFilterCriteria{HasReturnData: true}, []types.ReturnData{retData[0], retData[1], retData[3]}, ""},
|
||||
}
|
||||
|
||||
// create all filters
|
||||
|
|
@ -373,8 +382,7 @@ func TestReturnDataFilter(t *testing.T) {
|
|||
}
|
||||
|
||||
if len(fetched) != len(tt.expected) {
|
||||
t.Errorf("invalid number of return data events for case %d, want %d events, got %d", i, len(tt.expected), len(fetched))
|
||||
//return
|
||||
t.Fatalf("invalid number of return data events for case %d, want %d events, got %d", i, len(tt.expected), len(fetched))
|
||||
}
|
||||
|
||||
for j := range fetched {
|
||||
|
|
|
|||
|
|
@ -150,8 +150,9 @@ type FilterQuery struct {
|
|||
}
|
||||
|
||||
type TxFilterQuery struct {
|
||||
From []common.Address // restricts matches to transactions originating from specific addresses
|
||||
To []common.Address // restricts matches to transactions sent to specific addresses
|
||||
From map[common.Address]struct{} // restricts matches to transactions originating from specific addresses
|
||||
To map[common.Address]struct{} // restricts matches to transactions sent to specific addresses
|
||||
HasReturnData bool // restricts matches to transactions which executed a contract function returning data.
|
||||
}
|
||||
|
||||
// LogFilterer provides access to contract log events using a one-off query or continuous
|
||||
|
|
|
|||
Loading…
Reference in a new issue