From 60c9b1e88c6bbd418e7672b4a8b1e2032f4191f1 Mon Sep 17 00:00:00 2001 From: jholdstock Date: Mon, 4 Sep 2023 16:01:56 +0100 Subject: [PATCH] multi: Display expired/missed tickets on webpage. Revoked ticket count is replaced by separate counts for expired/missed tickets. /vspinfo API response remains unchanged. --- database/ticket.go | 22 +++++++++----- database/ticket_test.go | 54 +++++++++++++++++++++++++-------- webapi/cache.go | 25 +++++++++------ webapi/templates/vsp-stats.html | 14 +++++++-- webapi/vspinfo.go | 4 +-- 5 files changed, 84 insertions(+), 35 deletions(-) diff --git a/database/ticket.go b/database/ticket.go index da013d9b..48fce8d3 100644 --- a/database/ticket.go +++ b/database/ticket.go @@ -308,13 +308,14 @@ func (vdb *VspDatabase) Size() (uint64, error) { return size, err } -// CountTickets returns the total number of voted, revoked, and currently voting -// tickets. This func iterates over every ticket so should be used sparingly. -func (vdb *VspDatabase) CountTickets() (int64, int64, int64, error) { +// CountTickets returns the total number of voted, expired, missed, and +// currently voting tickets. This func iterates over every ticket so should be +// used sparingly. +func (vdb *VspDatabase) CountTickets() (int64, int64, int64, int64, error) { vdb.ticketsMtx.RLock() defer vdb.ticketsMtx.RUnlock() - var voting, voted, revoked int64 + var voting, voted, expired, missed int64 err := vdb.db.View(func(tx *bolt.Tx) error { ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK) @@ -325,8 +326,15 @@ func (vdb *VspDatabase) CountTickets() (int64, int64, int64, error) { switch TicketOutcome(tBkt.Get(outcomeK)) { case Voted: voted++ - case Revoked, Expired, Missed: - revoked++ + case Expired: + expired++ + case Missed: + missed++ + case Revoked: + // There shouldn't be any revoked tickets in the db, they + // should have been updated to expired/missed. Give benefit + // of doubt to VSP admin and count these as expired. + expired++ default: voting++ } @@ -336,7 +344,7 @@ func (vdb *VspDatabase) CountTickets() (int64, int64, int64, error) { }) }) - return voting, voted, revoked, err + return voting, voted, expired, missed, err } // GetUnconfirmedTickets returns tickets which are not yet confirmed. diff --git a/database/ticket_test.go b/database/ticket_test.go index 7cbd5f5e..f8edd07f 100644 --- a/database/ticket_test.go +++ b/database/ticket_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 The Decred developers +// Copyright (c) 2020-2023 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -228,8 +228,8 @@ func testFilterTickets(t *testing.T) { } func testCountTickets(t *testing.T) { - count := func(test string, expectedVoting, expectedVoted, expectedRevoked int64) { - voting, voted, revoked, err := db.CountTickets() + count := func(test string, expectedVoting, expectedVoted, expectedExpired, expectedMissed int64) { + voting, voted, expired, missed, err := db.CountTickets() if err != nil { t.Fatalf("error counting tickets: %v", err) } @@ -242,14 +242,18 @@ func testCountTickets(t *testing.T) { t.Fatalf("test %s: expected %d voted tickets, got %d", test, expectedVoted, voted) } - if revoked != expectedRevoked { - t.Fatalf("test %s: expected %d revoked tickets, got %d", - test, expectedRevoked, revoked) + if expired != expectedExpired { + t.Fatalf("test %s: expected %d expired tickets, got %d", + test, expectedExpired, expired) + } + if missed != expectedMissed { + t.Fatalf("test %s: expected %d missed tickets, got %d", + test, expectedMissed, missed) } } // Initial counts should all be zero. - count("empty db", 0, 0, 0) + count("empty db", 0, 0, 0, 0) // Insert a ticket with non-confirmed fee into the database. // This should not be counted. @@ -260,7 +264,7 @@ func testCountTickets(t *testing.T) { t.Fatalf("error storing ticket in database: %v", err) } - count("unconfirmed fee", 0, 0, 0) + count("unconfirmed fee", 0, 0, 0, 0) // Insert a ticket with confirmed fee into the database. // This should be counted. @@ -271,7 +275,7 @@ func testCountTickets(t *testing.T) { t.Fatalf("error storing ticket in database: %v", err) } - count("confirmed fee", 1, 0, 0) + count("confirmed fee", 1, 0, 0, 0) // Insert a voted ticket into the database. // This should be counted. @@ -283,17 +287,41 @@ func testCountTickets(t *testing.T) { t.Fatalf("error storing ticket in database: %v", err) } - count("voted", 1, 1, 0) + count("voted", 1, 1, 0, 0) - // Insert a revoked ticket into the database. + // Insert an expired ticket into the database. // This should be counted. ticket4 := exampleTicket() ticket4.FeeTxStatus = FeeConfirmed - ticket4.Outcome = Revoked + ticket4.Outcome = Expired err = db.InsertNewTicket(ticket4) if err != nil { t.Fatalf("error storing ticket in database: %v", err) } - count("revoked", 1, 1, 1) + count("expired", 1, 1, 1, 0) + + // Insert a missed ticket into the database. + // This should be counted. + ticket5 := exampleTicket() + ticket5.FeeTxStatus = FeeConfirmed + ticket5.Outcome = Missed + err = db.InsertNewTicket(ticket5) + if err != nil { + t.Fatalf("error storing ticket in database: %v", err) + } + + count("missed", 1, 1, 1, 1) + + // Insert a revoked ticket into the database. + // This should be counted as expired. + ticket6 := exampleTicket() + ticket6.FeeTxStatus = FeeConfirmed + ticket6.Outcome = Revoked + err = db.InsertNewTicket(ticket6) + if err != nil { + t.Fatalf("error storing ticket in database: %v", err) + } + + count("revoked", 1, 1, 2, 1) } diff --git a/webapi/cache.go b/webapi/cache.go index 4dd06002..a2e36224 100644 --- a/webapi/cache.go +++ b/webapi/cache.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 The Decred developers +// Copyright (c) 2020-2023 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -31,12 +31,14 @@ type cacheData struct { DatabaseSize string Voting int64 Voted int64 - Revoked int64 + Expired int64 + Missed int64 VotingWalletsOnline int64 TotalVotingWallets int64 BlockHeight uint32 NetworkProportion float32 - RevokedProportion float32 + ExpiredProportion float32 + MissedProportion float32 } func (c *cache) getData() cacheData { @@ -66,8 +68,8 @@ func (c *cache) update(db *database.VspDatabase, dcrd rpc.DcrdConnect, return err } - // Get latest counts of voting, voted and revoked tickets. - voting, voted, revoked, err := db.CountTickets() + // Get latest counts of voting, voted, expired and missed tickets. + voting, voted, expired, missed, err := db.CountTickets() if err != nil { return err } @@ -104,17 +106,20 @@ func (c *cache) update(db *database.VspDatabase, dcrd rpc.DcrdConnect, c.data.Voted = voted c.data.TotalVotingWallets = int64(len(clients) + len(failedConnections)) c.data.VotingWalletsOnline = int64(len(clients)) - c.data.Revoked = revoked + c.data.Expired = expired + c.data.Missed = missed c.data.BlockHeight = bestBlock.Height c.data.NetworkProportion = float32(voting) / float32(bestBlock.PoolSize) - total := voted + revoked + total := voted + expired + missed - // Prevent dividing by zero when pool has no voted/revoked tickets. + // Prevent dividing by zero when pool has no voted/expired/missed tickets. if total == 0 { - c.data.RevokedProportion = 0 + c.data.ExpiredProportion = 0 + c.data.MissedProportion = 0 } else { - c.data.RevokedProportion = float32(revoked) / float32(total) + c.data.ExpiredProportion = float32(expired) / float32(total) + c.data.MissedProportion = float32(missed) / float32(total) } return nil diff --git a/webapi/templates/vsp-stats.html b/webapi/templates/vsp-stats.html index 3db2fef6..3590244a 100644 --- a/webapi/templates/vsp-stats.html +++ b/webapi/templates/vsp-stats.html @@ -13,10 +13,18 @@
-
Revoked tickets
+
Expired tickets
- {{ comma .WebApiCache.Revoked }} - ({{ float32ToPercent .WebApiCache.RevokedProportion }}) + {{ comma .WebApiCache.Expired }} + ({{ float32ToPercent .WebApiCache.ExpiredProportion }}) +
+
+ +
+
Missed tickets
+
+ {{ comma .WebApiCache.Missed }} + ({{ float32ToPercent .WebApiCache.MissedProportion }})
diff --git a/webapi/vspinfo.go b/webapi/vspinfo.go index a8f876fd..2cb26c59 100644 --- a/webapi/vspinfo.go +++ b/webapi/vspinfo.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 The Decred developers +// Copyright (c) 2020-2023 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -28,7 +28,7 @@ func (s *Server) vspInfo(c *gin.Context) { Voted: cachedStats.Voted, TotalVotingWallets: cachedStats.TotalVotingWallets, VotingWalletsOnline: cachedStats.VotingWalletsOnline, - Revoked: cachedStats.Revoked, + Revoked: cachedStats.Expired + cachedStats.Missed, BlockHeight: cachedStats.BlockHeight, NetworkProportion: cachedStats.NetworkProportion, }, c)