Skip to content

Commit dd59271

Browse files
author
dcb9
committed
Add eth filter
1 parent 4348be9 commit dd59271

12 files changed

+321
-71
lines changed

pkg/eth/filter.go

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package eth
2+
3+
import (
4+
"math/big"
5+
"sync"
6+
"sync/atomic"
7+
)
8+
9+
type FilterType int
10+
11+
const (
12+
NewFilterTy FilterType = iota
13+
NewBlockFilterTy
14+
NewPendingTransactionFilterTy
15+
)
16+
17+
type Filter struct {
18+
ID uint64
19+
Type FilterType
20+
Request interface{}
21+
LastBlockNum *big.Int
22+
Data sync.Map
23+
}
24+
25+
type FilterSimulator struct {
26+
filters sync.Map
27+
maxFilterID *uint64
28+
}
29+
30+
func NewFilterSimulator() *FilterSimulator {
31+
id := uint64(0)
32+
return &FilterSimulator{
33+
maxFilterID: &id,
34+
}
35+
}
36+
37+
func (f *FilterSimulator) New(ty FilterType, req ...interface{}) *Filter {
38+
id := atomic.AddUint64(f.maxFilterID, 1)
39+
filter := &Filter{ID: id, Type: ty}
40+
if ty == NewFilterTy {
41+
filter.Request = req[0]
42+
}
43+
44+
f.filters.Store(id, filter)
45+
46+
return filter
47+
}
48+
49+
func (f *FilterSimulator) Uninstall(filterID uint64) {
50+
f.filters.Delete(filterID)
51+
}
52+
53+
func (f *FilterSimulator) Filter(filterID uint64) (value interface{}, ok bool) {
54+
return f.filters.Load(filterID)
55+
}

pkg/eth/rpc_types.go

+33-3
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,7 @@ func (r *UninstallFilterRequest) UnmarshalJSON(data []byte) error {
291291
// the filter id
292292
type GetFilterChangesRequest string
293293

294-
//For filters created with eth_newBlockFilter the return are block hashes (DATA, 32 Bytes),
295-
// e.g. ["0x3454645634534..."].
296-
type GetFilterChangesResponse []string
294+
type GetFilterChangesResponse []interface{}
297295

298296
func (r *GetFilterChangesRequest) UnmarshalJSON(data []byte) error {
299297
var params []string
@@ -387,3 +385,35 @@ func (r *GetBlockByNumberRequest) UnmarshalJSON(data []byte) error {
387385

388386
return nil
389387
}
388+
389+
// ========== eth_newFilter ============= //
390+
391+
type NewFilterRequest struct {
392+
FromBlock json.RawMessage `json:"fromBlock"`
393+
ToBlock json.RawMessage `json:"toBlock"`
394+
Address json.RawMessage `json:"address"`
395+
Topics []interface{} `json:"topics"`
396+
}
397+
398+
func (r *NewFilterRequest) UnmarshalJSON(data []byte) error {
399+
var params []json.RawMessage
400+
if err := json.Unmarshal(data, &params); err != nil {
401+
return err
402+
}
403+
404+
if len(params) == 0 {
405+
return errors.New("params must be set")
406+
}
407+
type Req NewFilterRequest
408+
var req Req
409+
410+
if err := json.Unmarshal(params[0], &req); err != nil {
411+
return err
412+
}
413+
414+
*r = NewFilterRequest(req)
415+
416+
return nil
417+
}
418+
419+
type NewFilterResponse string

pkg/qtum/method.go

+7
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,10 @@ func (m *Method) Generate(blockNum int, maxTries *int) (resp GenerateResponse, e
8989
err = m.Request(MethodGenerate, &req, &resp)
9090
return
9191
}
92+
93+
func (m *Method) SearchLogs(req *SearchLogsRequest) (receipts SearchLogsResponse, err error) {
94+
if err := m.Request(MethodSearchLogs, req, &receipts); err != nil {
95+
return nil, err
96+
}
97+
return
98+
}

pkg/qtum/rpc_types.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ type (
599599
FromBlock *big.Int
600600
ToBlock *big.Int
601601
Addresses []string
602+
Topics []interface{}
602603
}
603604

604605
SearchLogsResponse []TransactionReceiptStruct
@@ -612,13 +613,21 @@ func (r *SearchLogsRequest) MarshalJSON() ([]byte, error) {
612613
4. "topics" (string, optional) An array of values from which at least one must appear in the log entries. The order is important, if you want to leave topics out use null, e.g. ["null", "0x00..."].
613614
5. "minconf" (uint, optional, default=0) Minimal number of confirmations before a log is returned
614615
*/
615-
return json.Marshal([]interface{}{
616+
data := []interface{}{
616617
r.FromBlock,
617618
r.ToBlock,
618619
map[string][]string{
619620
"addresses": r.Addresses,
620621
},
621-
})
622+
}
623+
624+
if len(r.Topics) > 0 {
625+
data = append(data, map[string][]interface{}{
626+
"topics": r.Topics,
627+
})
628+
}
629+
630+
return json.Marshal(data)
622631
}
623632

624633
// ========== GetAccountInfo ============= //

pkg/transformer/eth_call.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (p *ProxyETHCall) ToRequest(ethreq *eth.CallRequest) (*qtum.CallContractReq
5757

5858
return &qtum.CallContractRequest{
5959
To: ethreq.To,
60-
From: ethreq.From,
60+
From: from,
6161
Data: ethreq.Data,
6262
GasLimit: gasLimit,
6363
}, nil

pkg/transformer/eth_getFilterChanges.go

+118-10
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package transformer
22

33
import (
4+
"encoding/json"
45
"math/big"
56

7+
"github.com/pkg/errors"
8+
69
"github.com/dcb9/janus/pkg/eth"
710
"github.com/dcb9/janus/pkg/qtum"
811
"github.com/dcb9/janus/pkg/utils"
@@ -12,7 +15,7 @@ import (
1215
// ProxyETHGetFilterChanges implements ETHProxy
1316
type ProxyETHGetFilterChanges struct {
1417
*qtum.Qtum
15-
blockFilter *BlockFilterSimulator
18+
filter *eth.FilterSimulator
1619
}
1720

1821
func (p *ProxyETHGetFilterChanges) Method() string {
@@ -25,20 +28,38 @@ func (p *ProxyETHGetFilterChanges) Request(rawreq *eth.JSONRPCRequest) (interfac
2528
return nil, err
2629
}
2730

28-
return p.request(&req)
31+
filterID, err := hexutil.DecodeUint64(string(req))
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
_filter, ok := p.filter.Filter(filterID)
37+
if !ok {
38+
return nil, errors.New("Invalid filter id")
39+
}
40+
filter := _filter.(*eth.Filter)
41+
42+
switch filter.Type {
43+
case eth.NewFilterTy:
44+
return p.requestFilter(filter)
45+
case eth.NewBlockFilterTy:
46+
return p.requestBlockFilter(filter)
47+
case eth.NewPendingTransactionFilterTy:
48+
fallthrough
49+
default:
50+
51+
return nil, errors.New("Unknown filter type")
52+
}
2953
}
3054

31-
func (p *ProxyETHGetFilterChanges) request(ethreq *eth.GetFilterChangesRequest) (qtumresp eth.GetFilterChangesResponse, err error) {
55+
func (p *ProxyETHGetFilterChanges) requestBlockFilter(filter *eth.Filter) (qtumresp eth.GetFilterChangesResponse, err error) {
3256
qtumresp = make(eth.GetFilterChangesResponse, 0)
33-
filterID, err := hexutil.DecodeUint64(string(*ethreq))
34-
if err != nil {
35-
return qtumresp, err
36-
}
3757

38-
lastBlockNumber, err := p.blockFilter.GetBlockNumber(filterID)
39-
if err != nil {
40-
return qtumresp, err
58+
_lastBlockNumber, ok := filter.Data.Load("lastBlockNumber")
59+
if !ok {
60+
return qtumresp, errors.New("Could not get lastBlockNumber")
4161
}
62+
lastBlockNumber := _lastBlockNumber.(uint64)
4263

4364
blockCountBigInt, err := p.GetBlockCount()
4465
if err != nil {
@@ -61,5 +82,92 @@ func (p *ProxyETHGetFilterChanges) request(ethreq *eth.GetFilterChangesRequest)
6182
}
6283

6384
qtumresp = hashes
85+
filter.Data.Store("lastBlockNumber", blockCount)
6486
return
6587
}
88+
func (p *ProxyETHGetFilterChanges) requestFilter(filter *eth.Filter) (qtumresp eth.GetFilterChangesResponse, err error) {
89+
qtumresp = make(eth.GetFilterChangesResponse, 0)
90+
91+
_lastBlockNumber, ok := filter.Data.Load("lastBlockNumber")
92+
if !ok {
93+
return qtumresp, errors.New("Could not get lastBlockNumber")
94+
}
95+
lastBlockNumber := _lastBlockNumber.(uint64)
96+
97+
blockCountBigInt, err := p.GetBlockCount()
98+
if err != nil {
99+
return qtumresp, err
100+
}
101+
blockCount := blockCountBigInt.Uint64()
102+
103+
differ := blockCount - lastBlockNumber
104+
105+
if differ == 0 {
106+
return eth.GetFilterChangesResponse{}, nil
107+
}
108+
109+
searchLogsReq, err := p.toSearchLogsReq(filter, big.NewInt(int64(lastBlockNumber+1)), big.NewInt(int64(blockCount)))
110+
if err != nil {
111+
return nil, err
112+
}
113+
114+
return p.doSearchLogs(searchLogsReq)
115+
}
116+
117+
func (p *ProxyETHGetFilterChanges) doSearchLogs(req *qtum.SearchLogsRequest) (eth.GetFilterChangesResponse, error) {
118+
resp, err := p.SearchLogs(req)
119+
if err != nil {
120+
return nil, err
121+
}
122+
123+
receiptToResult := func(receipt *qtum.TransactionReceiptStruct) []interface{} {
124+
logs := getEthLogs(receipt)
125+
res := make([]interface{}, len(logs))
126+
for i, _ := range res {
127+
res[i] = logs[i]
128+
}
129+
return res
130+
}
131+
results := make(eth.GetFilterChangesResponse, 0)
132+
for _, receipt := range resp {
133+
r := qtum.TransactionReceiptStruct(receipt)
134+
results = append(results, receiptToResult(&r)...)
135+
}
136+
137+
return results, nil
138+
}
139+
140+
func (p *ProxyETHGetFilterChanges) toSearchLogsReq(filter *eth.Filter, from, to *big.Int) (*qtum.SearchLogsRequest, error) {
141+
ethreq := filter.Request.(*eth.NewFilterRequest)
142+
var err error
143+
var addresses []string
144+
if ethreq.Address != nil {
145+
if isString(ethreq.Address) {
146+
var addr string
147+
if err = json.Unmarshal(ethreq.Address, &addr); err != nil {
148+
return nil, err
149+
}
150+
addresses = append(addresses, addr)
151+
} else {
152+
if err = json.Unmarshal(ethreq.Address, &addresses); err != nil {
153+
return nil, err
154+
}
155+
}
156+
for i, _ := range addresses {
157+
addresses[i] = utils.RemoveHexPrefix(addresses[i])
158+
}
159+
}
160+
161+
qtumreq := &qtum.SearchLogsRequest{
162+
Addresses: addresses,
163+
FromBlock: from,
164+
ToBlock: to,
165+
}
166+
167+
topics, ok := filter.Data.Load("topics")
168+
if ok {
169+
qtumreq.Topics = topics.([]interface{})
170+
}
171+
172+
return qtumreq, nil
173+
}

pkg/transformer/eth_getFilterLogs.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package transformer
2+
3+
// ProxyETHGetFilterLogs implements ETHProxy
4+
type ProxyETHGetFilterLogs struct {
5+
*ProxyETHGetFilterChanges
6+
}
7+
8+
func (p *ProxyETHGetFilterLogs) Method() string {
9+
return "eth_getFilterLogs"
10+
}

pkg/transformer/eth_getLogs.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ func (p *ProxyETHGetLogs) Request(rawreq *eth.JSONRPCRequest) (interface{}, erro
3939
}
4040

4141
func (p *ProxyETHGetLogs) request(req *qtum.SearchLogsRequest) (*eth.GetLogsResponse, error) {
42-
var receipts qtum.SearchLogsResponse
43-
if err := p.Qtum.Request(qtum.MethodSearchLogs, req, &receipts); err != nil {
42+
receipts, err := p.SearchLogs(req)
43+
if err != nil {
4444
return nil, err
4545
}
4646

0 commit comments

Comments
 (0)