diff --git a/docs/api.md b/docs/api.md index ef7bf83..a80174f 100644 --- a/docs/api.md +++ b/docs/api.md @@ -54,7 +54,8 @@ when a VSP is closed will result in an error. "voting":10, "voted":25, "revoked":3, - "blockheight":623212 + "blockheight":623212, + "estimatednetworkproportion":0.048478414 } ``` diff --git a/rpc/dcrd.go b/rpc/dcrd.go index 025a569..7e5b13f 100644 --- a/rpc/dcrd.go +++ b/rpc/dcrd.go @@ -224,17 +224,6 @@ func (c *DcrdRPC) CanTicketVote(rawTx *dcrdtypes.TxRawResult, ticketHash string, return live, nil } -// GetBestBlockHeight uses getblockcount RPC to query the height of the best -// block known by the dcrd instance. -func (c *DcrdRPC) GetBestBlockHeight() (int64, error) { - var height int64 - err := c.Call(c.ctx, "getblockcount", &height) - if err != nil { - return 0, err - } - return height, nil -} - // ParseBlockConnectedNotification extracts the block header from a // blockconnected JSON-RPC notification. func ParseBlockConnectedNotification(params json.RawMessage) (*wire.BlockHeader, error) { diff --git a/webapi/formatting.go b/webapi/formatting.go index 2e6a9eb..159868c 100644 --- a/webapi/formatting.go +++ b/webapi/formatting.go @@ -53,3 +53,7 @@ func indentJSON(input string) template.HTML { func atomsToDCR(atoms int64) string { return dcrutil.Amount(atoms).String() } + +func float32ToPercent(input float32) string { + return fmt.Sprintf("%.2f%%", input*100) +} diff --git a/webapi/homepage.go b/webapi/homepage.go index 08a4580..0b0b01c 100644 --- a/webapi/homepage.go +++ b/webapi/homepage.go @@ -21,18 +21,20 @@ import ( // vspStats 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 vspStats struct { - PubKey string - Voting int64 - Voted int64 - Revoked int64 - VSPFee float64 - Network string - UpdateTime string - SupportEmail string - VspClosed bool - Debug bool - Designation string - BlockHeight int64 + PubKey string + Voting int64 + Voted int64 + Revoked int64 + VSPFee float64 + Network string + UpdateTime string + SupportEmail string + VspClosed bool + Debug bool + Designation string + BlockHeight uint32 + NetworkProportion float32 + RevokedProportion float32 } var statsMtx sync.RWMutex @@ -80,7 +82,7 @@ func updateVSPStats(ctx context.Context, db *database.VspDatabase, return err } - blockHeight, err := dcrdClient.GetBestBlockHeight() + bestBlock, err := dcrdClient.GetBestBlockHeader() if err != nil { return err } @@ -92,7 +94,9 @@ func updateVSPStats(ctx context.Context, db *database.VspDatabase, stats.Voting = voting stats.Voted = voted stats.Revoked = revoked - stats.BlockHeight = blockHeight + stats.BlockHeight = bestBlock.Height + stats.NetworkProportion = float32(voting) / float32(bestBlock.PoolSize) + stats.RevokedProportion = float32(revoked) / float32(voted) return nil } diff --git a/webapi/public/css/vspd.css b/webapi/public/css/vspd.css index 0b6da3e..2c69ff3 100644 --- a/webapi/public/css/vspd.css +++ b/webapi/public/css/vspd.css @@ -53,6 +53,11 @@ body { color: #091440; } +.vsp-stats .stat-value .text-muted{ + font-size: 18px; + color: #8997A5; +} + footer { flex-shrink: 0; font-size: 0.8rem; diff --git a/webapi/templates/vsp-stats.html b/webapi/templates/vsp-stats.html index 9d7584c..2007d12 100644 --- a/webapi/templates/vsp-stats.html +++ b/webapi/templates/vsp-stats.html @@ -14,7 +14,10 @@
Revoked tickets
-
{{ .Revoked }}
+
+ {{ .Revoked }} + ({{ float32ToPercent .RevokedProportion }}) +
@@ -27,6 +30,11 @@
{{ .Network }}
+
+
Network Proportion
+
{{ float32ToPercent .NetworkProportion }}
+
+ {{ end }} diff --git a/webapi/types.go b/webapi/types.go index 7ee9e11..b1d18f6 100644 --- a/webapi/types.go +++ b/webapi/types.go @@ -5,17 +5,18 @@ package webapi type vspInfoResponse struct { - APIVersions []int64 `json:"apiversions"` - Timestamp int64 `json:"timestamp"` - PubKey []byte `json:"pubkey"` - FeePercentage float64 `json:"feepercentage"` - VspClosed bool `json:"vspclosed"` - Network string `json:"network"` - VspdVersion string `json:"vspdversion"` - Voting int64 `json:"voting"` - Voted int64 `json:"voted"` - Revoked int64 `json:"revoked"` - BlockHeight int64 `json:"blockheight"` + APIVersions []int64 `json:"apiversions"` + Timestamp int64 `json:"timestamp"` + PubKey []byte `json:"pubkey"` + FeePercentage float64 `json:"feepercentage"` + VspClosed bool `json:"vspclosed"` + Network string `json:"network"` + VspdVersion string `json:"vspdversion"` + Voting int64 `json:"voting"` + Voted int64 `json:"voted"` + Revoked int64 `json:"revoked"` + BlockHeight uint32 `json:"blockheight"` + NetworkProportion float32 `json:"estimatednetworkproportion"` } type feeAddressRequest struct { diff --git a/webapi/vspinfo.go b/webapi/vspinfo.go index 7ccc5df..7c6a141 100644 --- a/webapi/vspinfo.go +++ b/webapi/vspinfo.go @@ -15,16 +15,17 @@ import ( func vspInfo(c *gin.Context) { cachedStats := getVSPStats() sendJSONResponse(vspInfoResponse{ - APIVersions: []int64{3}, - Timestamp: time.Now().Unix(), - PubKey: signPubKey, - FeePercentage: cfg.VSPFee, - Network: cfg.NetParams.Name, - VspClosed: cfg.VspClosed, - VspdVersion: version.String(), - Voting: cachedStats.Voting, - Voted: cachedStats.Voted, - Revoked: cachedStats.Revoked, - BlockHeight: cachedStats.BlockHeight, + APIVersions: []int64{3}, + Timestamp: time.Now().Unix(), + PubKey: signPubKey, + FeePercentage: cfg.VSPFee, + Network: cfg.NetParams.Name, + VspClosed: cfg.VspClosed, + VspdVersion: version.String(), + Voting: cachedStats.Voting, + Voted: cachedStats.Voted, + Revoked: cachedStats.Revoked, + BlockHeight: cachedStats.BlockHeight, + NetworkProportion: cachedStats.NetworkProportion, }, c) } diff --git a/webapi/webapi.go b/webapi/webapi.go index feb12e9..e7a6176 100644 --- a/webapi/webapi.go +++ b/webapi/webapi.go @@ -177,13 +177,14 @@ func router(debugMode bool, cookieSecret []byte, dcrd rpc.DcrdConnect, wallets r // Add custom functions for use in templates. router.SetFuncMap(template.FuncMap{ - "txURL": txURL(cfg.BlockExplorerURL), - "addressURL": addressURL(cfg.BlockExplorerURL), - "blockURL": blockURL(cfg.BlockExplorerURL), - "dateTime": dateTime, - "stripWss": stripWss, - "indentJSON": indentJSON, - "atomsToDCR": atomsToDCR, + "txURL": txURL(cfg.BlockExplorerURL), + "addressURL": addressURL(cfg.BlockExplorerURL), + "blockURL": blockURL(cfg.BlockExplorerURL), + "dateTime": dateTime, + "stripWss": stripWss, + "indentJSON": indentJSON, + "atomsToDCR": atomsToDCR, + "float32ToPercent": float32ToPercent, }) router.LoadHTMLGlob("webapi/templates/*.html")