github.com/status-im/status-go@v1.1.0/protocol/ens/verifier.go (about) 1 package ens 2 3 import ( 4 "database/sql" 5 "time" 6 7 "go.uber.org/zap" 8 9 gethcommon "github.com/ethereum/go-ethereum/common" 10 "github.com/status-im/status-go/eth-node/types" 11 enstypes "github.com/status-im/status-go/eth-node/types/ens" 12 "github.com/status-im/status-go/protocol/common" 13 ) 14 15 type Verifier struct { 16 node types.Node 17 online bool 18 persistence *Persistence 19 logger *zap.Logger 20 timesource common.TimeSource 21 subscriptions []chan []*VerificationRecord 22 rpcEndpoint string 23 contractAddress string 24 quit chan struct{} 25 } 26 27 func New(node types.Node, logger *zap.Logger, timesource common.TimeSource, db *sql.DB, rpcEndpoint, contractAddress string) *Verifier { 28 persistence := NewPersistence(db) 29 return &Verifier{ 30 node: node, 31 logger: logger, 32 persistence: persistence, 33 timesource: timesource, 34 rpcEndpoint: rpcEndpoint, 35 contractAddress: contractAddress, 36 quit: make(chan struct{}), 37 } 38 } 39 40 func (v *Verifier) Start() error { 41 go v.verifyLoop() 42 return nil 43 } 44 45 func (v *Verifier) Stop() error { 46 close(v.quit) 47 48 return nil 49 } 50 51 // ENSVerified adds an already verified entry to the ens table 52 func (v *Verifier) ENSVerified(pk, ensName string, clock uint64) error { 53 54 // Add returns nil if no record was available 55 oldRecord, err := v.Add(pk, ensName, clock) 56 if err != nil { 57 return err 58 } 59 60 var record *VerificationRecord 61 62 if oldRecord != nil { 63 record = oldRecord 64 } else { 65 record = &VerificationRecord{PublicKey: pk, Name: ensName, Clock: clock} 66 } 67 68 record.VerifiedAt = clock 69 record.Verified = true 70 records := []*VerificationRecord{record} 71 err = v.persistence.UpdateRecords(records) 72 if err != nil { 73 return err 74 } 75 v.publish(records) 76 return nil 77 } 78 79 func (v *Verifier) GetVerifiedRecord(pk string) (*VerificationRecord, error) { 80 return v.persistence.GetVerifiedRecord(pk) 81 } 82 83 func (v *Verifier) Add(pk, ensName string, clock uint64) (*VerificationRecord, error) { 84 record := VerificationRecord{PublicKey: pk, Name: ensName, Clock: clock} 85 return v.persistence.AddRecord(record) 86 } 87 88 func (v *Verifier) SetOnline(online bool) { 89 v.online = online 90 } 91 92 func (v *Verifier) verifyLoop() { 93 94 ticker := time.NewTicker(30 * time.Second) 95 for { 96 select { 97 98 case <-v.quit: 99 ticker.Stop() 100 return 101 case <-ticker.C: 102 if !v.online || v.rpcEndpoint == "" || v.contractAddress == "" { 103 continue 104 } 105 err := v.verify(v.rpcEndpoint, v.contractAddress) 106 if err != nil { 107 v.logger.Error("verify loop failed", zap.Error(err)) 108 } 109 110 } 111 } 112 } 113 114 func (v *Verifier) Subscribe() chan []*VerificationRecord { 115 c := make(chan []*VerificationRecord) 116 v.subscriptions = append(v.subscriptions, c) 117 return c 118 } 119 120 func (v *Verifier) publish(records []*VerificationRecord) { 121 v.logger.Info("publishing records", zap.Any("records", records)) 122 // Publish on channels, drop if buffer is full 123 for _, s := range v.subscriptions { 124 select { 125 case s <- records: 126 default: 127 v.logger.Warn("ens subscription channel full, dropping message") 128 } 129 } 130 131 } 132 133 func (v *Verifier) ReverseResolve(address gethcommon.Address) (string, error) { 134 verifier := v.node.NewENSVerifier(v.logger) 135 return verifier.ReverseResolve(address, v.rpcEndpoint) 136 } 137 138 // Verify verifies that a registered ENS name matches the expected public key 139 func (v *Verifier) verify(rpcEndpoint, contractAddress string) error { 140 v.logger.Debug("verifying ENS Names", zap.String("endpoint", rpcEndpoint)) 141 verifier := v.node.NewENSVerifier(v.logger) 142 143 var ensDetails []enstypes.ENSDetails 144 145 // Now in seconds 146 now := v.timesource.GetCurrentTime() / 1000 147 ensToBeVerified, err := v.persistence.GetENSToBeVerified(now) 148 if err != nil { 149 return err 150 } 151 152 recordsMap := make(map[string]*VerificationRecord) 153 154 for _, r := range ensToBeVerified { 155 recordsMap[r.PublicKey] = r 156 ensDetails = append(ensDetails, enstypes.ENSDetails{ 157 PublicKeyString: r.PublicKey[2:], 158 Name: r.Name, 159 }) 160 v.logger.Debug("verifying ens name", zap.Any("record", r)) 161 } 162 163 ensResponse, err := verifier.CheckBatch(ensDetails, rpcEndpoint, contractAddress) 164 if err != nil { 165 v.logger.Error("failed to check batch", zap.Error(err)) 166 return err 167 } 168 169 var records []*VerificationRecord 170 171 for _, details := range ensResponse { 172 pk := "0x" + details.PublicKeyString 173 record := recordsMap[pk] 174 175 if details.Error == nil { 176 record.Verified = details.Verified 177 if !record.Verified { 178 record.VerificationRetries++ 179 } 180 } else { 181 v.logger.Warn("Failed to resolve ens name", 182 zap.String("name", details.Name), 183 zap.String("publicKey", details.PublicKeyString), 184 zap.Error(details.Error), 185 ) 186 record.VerificationRetries++ 187 } 188 record.VerifiedAt = now 189 record.CalculateNextRetry() 190 191 records = append(records, record) 192 } 193 194 err = v.persistence.UpdateRecords(records) 195 if err != nil { 196 197 v.logger.Error("failed to update records", zap.Error(err)) 198 return err 199 } 200 201 v.publish(records) 202 203 return nil 204 }