-
Notifications
You must be signed in to change notification settings - Fork 246
/
verifier.go
198 lines (161 loc) · 4.6 KB
/
verifier.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package ens
import (
"database/sql"
"time"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/types"
enstypes "github.com/status-im/status-go/eth-node/types/ens"
"github.com/status-im/status-go/protocol/common"
)
type Verifier struct {
node types.Node
online bool
persistence *Persistence
logger *zap.Logger
timesource common.TimeSource
subscriptions []chan []*VerificationRecord
rpcEndpoint string
contractAddress string
quit chan struct{}
}
func New(node types.Node, logger *zap.Logger, timesource common.TimeSource, db *sql.DB, rpcEndpoint, contractAddress string) *Verifier {
persistence := NewPersistence(db)
return &Verifier{
node: node,
logger: logger,
persistence: persistence,
timesource: timesource,
rpcEndpoint: rpcEndpoint,
contractAddress: contractAddress,
quit: make(chan struct{}),
}
}
func (v *Verifier) Start() error {
go v.verifyLoop()
return nil
}
func (v *Verifier) Stop() error {
close(v.quit)
return nil
}
// ENSVerified adds an already verified entry to the ens table
func (v *Verifier) ENSVerified(pk, ensName string, clock uint64) error {
// Add returns nil if no record was available
oldRecord, err := v.Add(pk, ensName, clock)
if err != nil {
return err
}
var record *VerificationRecord
if oldRecord != nil {
record = oldRecord
} else {
record = &VerificationRecord{PublicKey: pk, Name: ensName, Clock: clock}
}
record.VerifiedAt = clock
record.Verified = true
records := []*VerificationRecord{record}
err = v.persistence.UpdateRecords(records)
if err != nil {
return err
}
v.publish(records)
return nil
}
func (v *Verifier) GetVerifiedRecord(pk string) (*VerificationRecord, error) {
return v.persistence.GetVerifiedRecord(pk)
}
func (v *Verifier) Add(pk, ensName string, clock uint64) (*VerificationRecord, error) {
record := VerificationRecord{PublicKey: pk, Name: ensName, Clock: clock}
return v.persistence.AddRecord(record)
}
func (v *Verifier) SetOnline(online bool) {
v.online = online
}
func (v *Verifier) verifyLoop() {
ticker := time.NewTicker(30 * time.Second)
for {
select {
case <-v.quit:
ticker.Stop()
return
case <-ticker.C:
if !v.online || v.rpcEndpoint == "" || v.contractAddress == "" {
continue
}
err := v.verify(v.rpcEndpoint, v.contractAddress)
if err != nil {
v.logger.Error("verify loop failed", zap.Error(err))
}
}
}
}
func (v *Verifier) Subscribe() chan []*VerificationRecord {
c := make(chan []*VerificationRecord)
v.subscriptions = append(v.subscriptions, c)
return c
}
func (v *Verifier) publish(records []*VerificationRecord) {
v.logger.Info("publishing records", zap.Any("records", records))
// Publish on channels, drop if buffer is full
for _, s := range v.subscriptions {
select {
case s <- records:
default:
v.logger.Warn("ens subscription channel full, dropping message")
}
}
}
// Verify verifies that a registered ENS name matches the expected public key
func (v *Verifier) verify(rpcEndpoint, contractAddress string) error {
v.logger.Debug("verifying ENS Names", zap.String("endpoint", rpcEndpoint))
verifier := v.node.NewENSVerifier(v.logger)
var ensDetails []enstypes.ENSDetails
// Now in seconds
now := v.timesource.GetCurrentTime() / 1000
ensToBeVerified, err := v.persistence.GetENSToBeVerified(now)
if err != nil {
return err
}
recordsMap := make(map[string]*VerificationRecord)
for _, r := range ensToBeVerified {
recordsMap[r.PublicKey] = r
ensDetails = append(ensDetails, enstypes.ENSDetails{
PublicKeyString: r.PublicKey[2:],
Name: r.Name,
})
v.logger.Debug("verifying ens name", zap.Any("record", r))
}
ensResponse, err := verifier.CheckBatch(ensDetails, rpcEndpoint, contractAddress)
if err != nil {
v.logger.Error("failed to check batch", zap.Error(err))
return err
}
var records []*VerificationRecord
for _, details := range ensResponse {
pk := "0x" + details.PublicKeyString
record := recordsMap[pk]
if details.Error == nil {
record.Verified = details.Verified
if !record.Verified {
record.VerificationRetries++
}
} else {
v.logger.Warn("Failed to resolve ens name",
zap.String("name", details.Name),
zap.String("publicKey", details.PublicKeyString),
zap.Error(details.Error),
)
record.VerificationRetries++
}
record.VerifiedAt = now
record.CalculateNextRetry()
records = append(records, record)
}
err = v.persistence.UpdateRecords(records)
if err != nil {
v.logger.Error("failed to update records", zap.Error(err))
return err
}
v.publish(records)
return nil
}