status-im/status-go

View on GitHub
protocol/ens/persistence.go

Summary

Maintainability
A
0 mins
Test Coverage
C
74%
package ens

import (
    "context"
    "database/sql"
    "errors"
)

type Persistence struct {
    db *sql.DB
}

func NewPersistence(db *sql.DB) *Persistence {
    return &Persistence{db: db}
}

func (p *Persistence) GetENSToBeVerified(now uint64) ([]*VerificationRecord, error) {
    rows, err := p.db.Query(`SELECT public_key, name, verified, verified_at, clock, verification_retries, next_retry FROM ens_verification_records WHERE NOT(verified) AND verification_retries < ? AND next_retry <= ?`, maxRetries, now)
    if err != nil {
        return nil, err
    }

    var records []*VerificationRecord
    for rows.Next() {
        var record VerificationRecord
        err := rows.Scan(&record.PublicKey, &record.Name, &record.Verified, &record.VerifiedAt, &record.Clock, &record.VerificationRetries, &record.NextRetry)
        if err != nil {
            return nil, err
        }
        records = append(records, &record)
    }

    return records, nil
}

func (p *Persistence) UpdateRecords(records []*VerificationRecord) (err error) {
    var tx *sql.Tx
    tx, err = p.db.BeginTx(context.Background(), &sql.TxOptions{})
    if err != nil {
        return err
    }

    defer func() {
        if err == nil {
            err = tx.Commit()
            return
        }
        // don't shadow original error
        _ = tx.Rollback()
    }()

    for _, record := range records {
        var stmt *sql.Stmt
        stmt, err = tx.Prepare(`UPDATE ens_verification_records SET verified = ?, verified_at = ?, verification_retries = ?, next_retry = ? WHERE public_key = ?`)
        if err != nil {
            return err
        }
        defer stmt.Close()
        _, err = stmt.Exec(record.Verified, record.VerifiedAt, record.VerificationRetries, record.NextRetry, record.PublicKey)
        if err != nil {
            return err
        }

    }

    return nil
}

// AddRecord adds a record or return the latest available if already in the database and
// hasn't changed
func (p *Persistence) AddRecord(record VerificationRecord) (response *VerificationRecord, err error) {
    if !record.Valid() {
        err = errors.New("invalid ens record")
        return
    }
    var tx *sql.Tx
    tx, err = p.db.BeginTx(context.Background(), &sql.TxOptions{})
    if err != nil {
        return
    }

    defer func() {
        if err == nil {
            err = tx.Commit()
            return
        }
        // don't shadow original error
        _ = tx.Rollback()
    }()

    dbRecord := &VerificationRecord{PublicKey: record.PublicKey}

    err = tx.QueryRow(`SELECT name, clock, verified FROM ens_verification_records WHERE public_key = ?`, record.PublicKey).Scan(&dbRecord.Name, &dbRecord.Clock, &dbRecord.Verified)
    if err != nil && err != sql.ErrNoRows {
        return
    }

    if dbRecord.Clock >= record.Clock || dbRecord.Name == record.Name {
        response = dbRecord
        return
    }

    _, err = tx.Exec(`INSERT INTO ens_verification_records(public_key, name, clock) VALUES (?,?,?)`, record.PublicKey, record.Name, record.Clock)
    return
}

func (p *Persistence) GetVerifiedRecord(publicKey string) (*VerificationRecord, error) {
    record := &VerificationRecord{}
    err := p.db.QueryRow(`SELECT name, clock FROM ens_verification_records WHERE verified AND public_key =  ?`, publicKey).Scan(&record.Name, &record.Clock)
    switch err {
    case sql.ErrNoRows:
        return nil, nil
    case nil:
        return record, nil
    }

    return nil, err

}