vspd/webapi/cache.go
jholdstock 6acc5be10c Add dcrd to VSP status.
This renames "Voting wallet status" to "VSP status" and it now includes the status of the local dcrd instance. This change impacts both the /admin page of the UI, and the response of the /admin/status API endpoint.
2021-11-16 14:33:39 +00:00

111 lines
2.4 KiB
Go

// Copyright (c) 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package webapi
import (
"context"
"encoding/base64"
"errors"
"sync"
"time"
"github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/vspd/database"
"github.com/decred/vspd/rpc"
"github.com/dustin/go-humanize"
)
// apiCache is used to cache values which are commonly used by the API, so
// repeated web requests don't repeatedly trigger DB or RPC calls.
type apiCache struct {
UpdateTime string
PubKey string
DatabaseSize string
Voting int64
Voted int64
Revoked int64
BlockHeight uint32
NetworkProportion float32
RevokedProportion float32
}
var cacheMtx sync.RWMutex
var cache apiCache
func getCache() apiCache {
cacheMtx.RLock()
defer cacheMtx.RUnlock()
return cache
}
// initCache creates the struct which holds the cached VSP stats, and
// initializes it with static values.
func initCache() {
cacheMtx.Lock()
defer cacheMtx.Unlock()
cache = apiCache{
PubKey: base64.StdEncoding.EncodeToString(signPubKey),
}
}
// updateCache updates the dynamic values in the cache (ticket counts and best
// block height).
func updateCache(ctx context.Context, db *database.VspDatabase,
dcrd rpc.DcrdConnect, netParams *chaincfg.Params) error {
dbSize, err := db.Size()
if err != nil {
return err
}
// Get latest counts of voting, voted and revoked tickets.
voting, voted, revoked, err := db.CountTickets()
if err != nil {
return err
}
// Get latest best block height.
dcrdClient, _, err := dcrd.Client(ctx, netParams)
if err != nil {
return err
}
bestBlock, err := dcrdClient.GetBestBlockHeader()
if err != nil {
return err
}
if bestBlock.PoolSize == 0 {
return errors.New("dcr node reports a network ticket pool size of zero")
}
cacheMtx.Lock()
defer cacheMtx.Unlock()
cache.UpdateTime = dateTime(time.Now().Unix())
cache.DatabaseSize = humanize.Bytes(dbSize)
cache.Voting = voting
cache.Voted = voted
cache.Revoked = revoked
cache.BlockHeight = bestBlock.Height
cache.NetworkProportion = float32(voting) / float32(bestBlock.PoolSize)
// Prevent dividing by zero when pool has no voted tickets.
switch voted {
case 0:
if revoked == 0 {
cache.RevokedProportion = 0
} else {
cache.RevokedProportion = 1
}
default:
cache.RevokedProportion = float32(revoked) / float32(voted)
}
return nil
}