-
Notifications
You must be signed in to change notification settings - Fork 0
/
api.go
156 lines (126 loc) · 3.6 KB
/
api.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package rpcfilters
import (
"errors"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/pborman/uuid"
)
type filter struct {
hashes []common.Hash
mu sync.Mutex
done chan struct{}
}
// AddHash adds a hash to the filter
func (f *filter) AddHash(hash common.Hash) {
f.mu.Lock()
defer f.mu.Unlock()
f.hashes = append(f.hashes, hash)
}
// PopHashes returns all the hashes stored in the filter and clears the filter contents
func (f *filter) PopHashes() []common.Hash {
f.mu.Lock()
defer f.mu.Unlock()
hashes := f.hashes
f.hashes = nil
return returnHashes(hashes)
}
func newFilter() *filter {
return &filter{
done: make(chan struct{}),
}
}
// PublicAPI represents filter API that is exported to `eth` namespace
type PublicAPI struct {
filters map[rpc.ID]*filter
filtersMu sync.Mutex
latestBlockChangedEvent *latestBlockChangedEvent
transactionSentToUpstreamEvent *transactionSentToUpstreamEvent
}
// NewPublicAPI returns a reference to the PublicAPI object
func NewPublicAPI(latestBlockChangedEvent *latestBlockChangedEvent,
transactionSentToUpstreamEvent *transactionSentToUpstreamEvent) *PublicAPI {
return &PublicAPI{
filters: make(map[rpc.ID]*filter),
latestBlockChangedEvent: latestBlockChangedEvent,
transactionSentToUpstreamEvent: transactionSentToUpstreamEvent,
}
}
// NewBlockFilter is an implemenation of `eth_newBlockFilter` API
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newblockfilter
func (api *PublicAPI) NewBlockFilter() rpc.ID {
api.filtersMu.Lock()
defer api.filtersMu.Unlock()
f := newFilter()
id := rpc.ID(uuid.New())
api.filters[id] = f
go func() {
id, s := api.latestBlockChangedEvent.Subscribe()
defer api.latestBlockChangedEvent.Unsubscribe(id)
for {
select {
case hash := <-s:
f.AddHash(hash)
case <-f.done:
return
}
}
}()
return id
}
// NewPendingTransactionFilter is an implementation of `eth_newPendingTransactionFilter` API
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newpendingtransactionfilter
func (api *PublicAPI) NewPendingTransactionFilter() rpc.ID {
api.filtersMu.Lock()
defer api.filtersMu.Unlock()
f := newFilter()
id := rpc.ID(uuid.New())
api.filters[id] = f
go func() {
id, s := api.transactionSentToUpstreamEvent.Subscribe()
defer api.transactionSentToUpstreamEvent.Unsubscribe(id)
for {
select {
case hash := <-s:
f.AddHash(hash)
case <-f.done:
return
}
}
}()
return id
}
// UninstallFilter is an implemenation of `eth_uninstallFilter` API
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_uninstallfilter
func (api *PublicAPI) UninstallFilter(id rpc.ID) bool {
api.filtersMu.Lock()
f, found := api.filters[id]
if found {
delete(api.filters, id)
}
api.filtersMu.Unlock()
if found {
close(f.done)
}
return found
}
// GetFilterChanges returns the hashes for the filter with the given id since
// last time it was called. This can be used for polling.
//
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterchanges
func (api *PublicAPI) GetFilterChanges(id rpc.ID) ([]common.Hash, error) {
api.filtersMu.Lock()
defer api.filtersMu.Unlock()
if f, found := api.filters[id]; found {
return f.PopHashes(), nil
}
return []common.Hash{}, errors.New("filter not found")
}
// returnHashes is a helper that will return an empty hash array case the given hash array is nil,
// otherwise the given hashes array is returned.
func returnHashes(hashes []common.Hash) []common.Hash {
if hashes == nil {
return []common.Hash{}
}
return hashes
}