diff --git a/config.go b/config.go index 3852a1e..9e988f5 100644 --- a/config.go +++ b/config.go @@ -183,12 +183,12 @@ func loadConfig() (*config, error) { preParser := flags.NewParser(&preCfg, flags.HelpFlag) _, err := preParser.Parse() if err != nil { - if e, ok := err.(*flags.Error); ok && e.Type != flags.ErrHelp { - return nil, err - } else if ok && e.Type == flags.ErrHelp { + var e *flags.Error + if errors.As(err, &e) && e.Type == flags.ErrHelp { fmt.Fprintln(os.Stdout, err) os.Exit(0) } + return nil, err } appName := filepath.Base(os.Args[0]) @@ -214,7 +214,7 @@ func loadConfig() (*config, error) { // Create the home directory if it doesn't already exist. err = os.MkdirAll(cfg.HomeDir, 0700) if err != nil { - err := fmt.Errorf("failed to create home directory: %v", err) + err := fmt.Errorf("failed to create home directory: %w", err) fmt.Fprintln(os.Stderr, err) return nil, err } @@ -241,13 +241,14 @@ func loadConfig() (*config, error) { err = flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile) if err != nil { - return nil, fmt.Errorf("error parsing config file: %v", err) + return nil, fmt.Errorf("error parsing config file: %w", err) } // Parse command line options again to ensure they take precedence. _, err = parser.Parse() if err != nil { - if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp { + var e *flags.Error + if !errors.As(err, &e) || e.Type != flags.ErrHelp { fmt.Fprintln(os.Stderr, usageMessage) } return nil, err @@ -304,7 +305,7 @@ func loadConfig() (*config, error) { cfg.DcrdCert = cleanAndExpandPath(cfg.DcrdCert) cfg.dcrdCert, err = ioutil.ReadFile(cfg.DcrdCert) if err != nil { - return nil, fmt.Errorf("failed to read dcrd cert file: %v", err) + return nil, fmt.Errorf("failed to read dcrd cert file: %w", err) } // Ensure the dcrwallet RPC username is set. @@ -356,7 +357,7 @@ func loadConfig() (*config, error) { certs[i] = cleanAndExpandPath(certs[i]) cfg.walletCerts[i], err = ioutil.ReadFile(certs[i]) if err != nil { - return nil, fmt.Errorf("failed to read dcrwallet cert file: %v", err) + return nil, fmt.Errorf("failed to read dcrwallet cert file: %w", err) } } @@ -376,7 +377,7 @@ func loadConfig() (*config, error) { dataDir := filepath.Join(cfg.HomeDir, "data", cfg.netParams.Name) err = os.MkdirAll(dataDir, 0700) if err != nil { - return nil, fmt.Errorf("failed to create data directory: %v", err) + return nil, fmt.Errorf("failed to create data directory: %w", err) } // Initialize loggers and log rotation. @@ -398,13 +399,13 @@ func loadConfig() (*config, error) { // Ensure provided value is a valid key for the selected network. _, err = hdkeychain.NewKeyFromString(cfg.FeeXPub, cfg.netParams.Params) if err != nil { - return nil, fmt.Errorf("failed to parse feexpub: %v", err) + return nil, fmt.Errorf("failed to parse feexpub: %w", err) } // Create new database. err = database.CreateNew(cfg.dbPath, cfg.FeeXPub) if err != nil { - return nil, fmt.Errorf("error creating db file %s: %v", cfg.dbPath, err) + return nil, fmt.Errorf("error creating db file %s: %w", cfg.dbPath, err) } // Exit with success diff --git a/database/database.go b/database/database.go index 62f4431..3ed2905 100644 --- a/database/database.go +++ b/database/database.go @@ -72,13 +72,13 @@ func writeHotBackupFile(db *bolt.DB) error { return tx.CopyFile(tempPath, backupFileMode) }) if err != nil { - return fmt.Errorf("tx.CopyFile: %v", err) + return fmt.Errorf("tx.CopyFile: %w", err) } // Rename temporary file to actual backup file. err = os.Rename(tempPath, backupPath) if err != nil { - return fmt.Errorf("os.Rename: %v", err) + return fmt.Errorf("os.Rename: %w", err) } log.Tracef("Database backup written to %s", backupPath) @@ -95,7 +95,7 @@ func CreateNew(dbFile, feeXPub string) error { db, err := bolt.Open(dbFile, 0600, &bolt.Options{Timeout: 1 * time.Second}) if err != nil { - return fmt.Errorf("unable to open db file: %v", err) + return fmt.Errorf("unable to open db file: %w", err) } defer db.Close() @@ -105,7 +105,7 @@ func CreateNew(dbFile, feeXPub string) error { // Create parent bucket. vspBkt, err := tx.CreateBucket(vspBktK) if err != nil { - return fmt.Errorf("failed to create %s bucket: %v", string(vspBktK), err) + return fmt.Errorf("failed to create %s bucket: %w", string(vspBktK), err) } // Initialize with database version 1. @@ -121,7 +121,7 @@ func CreateNew(dbFile, feeXPub string) error { // Generate ed25519 key _, signKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { - return fmt.Errorf("failed to generate signing key: %v", err) + return fmt.Errorf("failed to generate signing key: %w", err) } err = vspBkt.Put(privateKeyK, signKey.Seed()) if err != nil { @@ -150,13 +150,13 @@ func CreateNew(dbFile, feeXPub string) error { // Create ticket bucket. _, err = vspBkt.CreateBucket(ticketBktK) if err != nil { - return fmt.Errorf("failed to create %s bucket: %v", string(ticketBktK), err) + return fmt.Errorf("failed to create %s bucket: %w", string(ticketBktK), err) } // Create vote change bucket. _, err = vspBkt.CreateBucket(voteChangeBktK) if err != nil { - return fmt.Errorf("failed to create %s bucket: %v", string(voteChangeBktK), err) + return fmt.Errorf("failed to create %s bucket: %w", string(voteChangeBktK), err) } return nil @@ -185,7 +185,7 @@ func Open(ctx context.Context, shutdownWg *sync.WaitGroup, dbFile string, backup db, err := bolt.Open(dbFile, 0600, &bolt.Options{Timeout: 1 * time.Second}) if err != nil { - return nil, fmt.Errorf("unable to open db file: %v", err) + return nil, fmt.Errorf("unable to open db file: %w", err) } log.Debugf("Opened database file %s", dbFile) diff --git a/database/ticket.go b/database/ticket.go index 242d099..54a9427 100644 --- a/database/ticket.go +++ b/database/ticket.go @@ -99,7 +99,7 @@ func (vdb *VspDatabase) InsertNewTicket(ticket Ticket) error { var t Ticket err := json.Unmarshal(v, &t) if err != nil { - return fmt.Errorf("could not unmarshal ticket: %v", err) + return fmt.Errorf("could not unmarshal ticket: %w", err) } if t.FeeAddress == ticket.FeeAddress { @@ -118,7 +118,7 @@ func (vdb *VspDatabase) InsertNewTicket(ticket Ticket) error { ticketBytes, err := json.Marshal(ticket) if err != nil { - return fmt.Errorf("could not marshal ticket: %v", err) + return fmt.Errorf("could not marshal ticket: %w", err) } return ticketBkt.Put(hashBytes, ticketBytes) @@ -134,7 +134,7 @@ func (vdb *VspDatabase) DeleteTicket(ticket Ticket) error { err := ticketBkt.Delete([]byte(ticket.Hash)) if err != nil { - return fmt.Errorf("could not delete ticket: %v", err) + return fmt.Errorf("could not delete ticket: %w", err) } return nil @@ -156,7 +156,7 @@ func (vdb *VspDatabase) UpdateTicket(ticket Ticket) error { ticketBytes, err := json.Marshal(ticket) if err != nil { - return fmt.Errorf("could not marshal ticket: %v", err) + return fmt.Errorf("could not marshal ticket: %w", err) } return ticketBkt.Put(hashBytes, ticketBytes) @@ -179,7 +179,7 @@ func (vdb *VspDatabase) GetTicketByHash(ticketHash string) (Ticket, bool, error) err := json.Unmarshal(ticketBytes, &ticket) if err != nil { - return fmt.Errorf("could not unmarshal ticket: %v", err) + return fmt.Errorf("could not unmarshal ticket: %w", err) } found = true @@ -202,7 +202,7 @@ func (vdb *VspDatabase) CountTickets() (int64, int64, int64, error) { var ticket Ticket err := json.Unmarshal(v, &ticket) if err != nil { - return fmt.Errorf("could not unmarshal ticket: %v", err) + return fmt.Errorf("could not unmarshal ticket: %w", err) } if ticket.FeeTxStatus == FeeConfirmed { @@ -276,7 +276,7 @@ func (vdb *VspDatabase) filterTickets(filter func(Ticket) bool) ([]Ticket, error var ticket Ticket err := json.Unmarshal(v, &ticket) if err != nil { - return fmt.Errorf("could not unmarshal ticket: %v", err) + return fmt.Errorf("could not unmarshal ticket: %w", err) } if filter(ticket) { diff --git a/database/votechange.go b/database/votechange.go index f23deec..bae1a9a 100644 --- a/database/votechange.go +++ b/database/votechange.go @@ -32,14 +32,14 @@ func (vdb *VspDatabase) SaveVoteChange(ticketHash string, record VoteChangeRecor // Serialize record for storage in the database. recordBytes, err := json.Marshal(record) if err != nil { - return fmt.Errorf("could not marshal vote change record: %v", err) + return fmt.Errorf("could not marshal vote change record: %w", err) } // Create or get a bucket for this ticket. bkt, err := tx.Bucket(vspBktK).Bucket(voteChangeBktK). CreateBucketIfNotExists([]byte(ticketHash)) if err != nil { - return fmt.Errorf("failed to create vote change bucket (ticketHash=%s): %v", + return fmt.Errorf("failed to create vote change bucket (ticketHash=%s): %w", ticketHash, err) } @@ -60,7 +60,7 @@ func (vdb *VspDatabase) SaveVoteChange(ticketHash string, record VoteChangeRecor return nil }) if err != nil { - return fmt.Errorf("error iterating over vote change bucket: %v", err) + return fmt.Errorf("error iterating over vote change bucket: %w", err) } // If bucket is at (or over) the limit of max allowed records, remove @@ -70,7 +70,7 @@ func (vdb *VspDatabase) SaveVoteChange(ticketHash string, record VoteChangeRecor binary.LittleEndian.PutUint32(keyBytes, lowest) err = bkt.Delete(keyBytes) if err != nil { - return fmt.Errorf("failed to delete old vote change record: %v", err) + return fmt.Errorf("failed to delete old vote change record: %w", err) } } @@ -87,7 +87,7 @@ func (vdb *VspDatabase) SaveVoteChange(ticketHash string, record VoteChangeRecor // Insert record. err = bkt.Put(keyBytes, recordBytes) if err != nil { - return fmt.Errorf("could not store vote change record: %v", err) + return fmt.Errorf("could not store vote change record: %w", err) } return nil @@ -112,7 +112,7 @@ func (vdb *VspDatabase) GetVoteChanges(ticketHash string) (map[uint32]VoteChange var record VoteChangeRecord err := json.Unmarshal(v, &record) if err != nil { - return fmt.Errorf("could not unmarshal vote change record: %v", err) + return fmt.Errorf("could not unmarshal vote change record: %w", err) } records[binary.LittleEndian.Uint32(k)] = record @@ -120,7 +120,7 @@ func (vdb *VspDatabase) GetVoteChanges(ticketHash string) (map[uint32]VoteChange return nil }) if err != nil { - return fmt.Errorf("error iterating over vote change bucket: %v", err) + return fmt.Errorf("error iterating over vote change bucket: %w", err) } return nil diff --git a/rpc/dcrd.go b/rpc/dcrd.go index dbf84f1..71b0cff 100644 --- a/rpc/dcrd.go +++ b/rpc/dcrd.go @@ -49,7 +49,7 @@ func SetupDcrd(user, pass, addr string, cert []byte, n wsrpc.Notifier) DcrdConne func (d *DcrdConnect) Client(ctx context.Context, netParams *chaincfg.Params) (*DcrdRPC, error) { c, newConnection, err := d.dial(ctx) if err != nil { - return nil, fmt.Errorf("dcrd connection error: %v", err) + return nil, fmt.Errorf("dcrd connection error: %w", err) } // If this is a reused connection, we don't need to validate the dcrd config @@ -63,7 +63,7 @@ func (d *DcrdConnect) Client(ctx context.Context, netParams *chaincfg.Params) (* err = c.Call(ctx, "version", &verMap) if err != nil { d.Close() - return nil, fmt.Errorf("dcrd version check failed: %v", err) + return nil, fmt.Errorf("dcrd version check failed: %w", err) } ver, exists := verMap["dcrdjsonrpcapi"] @@ -84,7 +84,7 @@ func (d *DcrdConnect) Client(ctx context.Context, netParams *chaincfg.Params) (* err = c.Call(ctx, "getcurrentnet", &netID) if err != nil { d.Close() - return nil, fmt.Errorf("dcrd getcurrentnet check failed: %v", err) + return nil, fmt.Errorf("dcrd getcurrentnet check failed: %w", err) } if netID != netParams.Net { d.Close() @@ -96,7 +96,7 @@ func (d *DcrdConnect) Client(ctx context.Context, netParams *chaincfg.Params) (* err = c.Call(ctx, "getinfo", &info) if err != nil { d.Close() - return nil, fmt.Errorf("dcrd getinfo check failed: %v", err) + return nil, fmt.Errorf("dcrd getinfo check failed: %w", err) } if !info.TxIndex { d.Close() diff --git a/rpc/dcrwallet.go b/rpc/dcrwallet.go index 679df6e..3dc6606 100644 --- a/rpc/dcrwallet.go +++ b/rpc/dcrwallet.go @@ -164,12 +164,12 @@ func (c *WalletRPC) AddTicketForVoting(votingWIF, blockHash, txHex string) error scanFrom := 0 err := c.Call(c.ctx, "importprivkey", nil, votingWIF, label, rescan, scanFrom) if err != nil { - return fmt.Errorf("importprivkey failed: %v", err) + return fmt.Errorf("importprivkey failed: %w", err) } err = c.Call(c.ctx, "addtransaction", nil, blockHash, txHex) if err != nil { - return fmt.Errorf("addtransaction failed: %v", err) + return fmt.Errorf("addtransaction failed: %w", err) } return nil diff --git a/webapi/addressgenerator.go b/webapi/addressgenerator.go index 5ea5cad..edb997b 100644 --- a/webapi/addressgenerator.go +++ b/webapi/addressgenerator.go @@ -57,7 +57,7 @@ func (m *addressGenerator) NextAddress() (string, uint32, error) { m.lastUsedIndex++ key, err = m.external.Child(m.lastUsedIndex) if err != nil { - if err == hdkeychain.ErrInvalidChild { + if errors.Is(err, hdkeychain.ErrInvalidChild) { invalidChildren++ log.Warnf("Generating address for index %d failed: %v", m.lastUsedIndex, err) // If this happens 3 times, something is seriously wrong, so diff --git a/webapi/webapi.go b/webapi/webapi.go index 92c53e7..6e1ae70 100644 --- a/webapi/webapi.go +++ b/webapi/webapi.go @@ -9,6 +9,7 @@ import ( "crypto/ed25519" "encoding/base64" "encoding/json" + "errors" "fmt" "net" "net/http" @@ -62,34 +63,34 @@ func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *s // Get keys for signing API responses from the database. signPrivKey, signPubKey, err = vdb.KeyPair() if err != nil { - return fmt.Errorf("db.Keypair error: %v", err) + return fmt.Errorf("db.Keypair error: %w", err) } // Populate cached VSP stats before starting webserver. err = updateVSPStats(vdb, config) if err != nil { - return fmt.Errorf("could not initialize VSP stats cache: %v", err) + return fmt.Errorf("could not initialize VSP stats cache: %w", err) } // Get the last used address index and the feeXpub from the database, and // use them to initialize the address generator. idx, err := vdb.GetLastAddressIndex() if err != nil { - return fmt.Errorf("db.GetLastAddressIndex error: %v", err) + return fmt.Errorf("db.GetLastAddressIndex error: %w", err) } feeXPub, err := vdb.GetFeeXPub() if err != nil { - return fmt.Errorf("db.GetFeeXPub error: %v", err) + return fmt.Errorf("db.GetFeeXPub error: %w", err) } addrGen, err = newAddressGenerator(feeXPub, config.NetParams, idx) if err != nil { - return fmt.Errorf("failed to initialize fee address generator: %v", err) + return fmt.Errorf("failed to initialize fee address generator: %w", err) } // Get the secret key used to initialize the cookie store. cookieSecret, err := vdb.GetCookieSecret() if err != nil { - return fmt.Errorf("db.GetCookieSecret error: %v", err) + return fmt.Errorf("db.GetCookieSecret error: %w", err) } // Create TCP listener. @@ -130,7 +131,7 @@ func Start(ctx context.Context, requestShutdownChan chan struct{}, shutdownWg *s // If the server dies for any reason other than ErrServerClosed (from // graceful server.Shutdown), log the error and request vspd be // shutdown. - if err != nil && err != http.ErrServerClosed { + if err != nil && !errors.Is(err, http.ErrServerClosed) { log.Errorf("Unexpected webserver error: %v", err) requestShutdownChan <- struct{}{} }