Skip to content

Commit

Permalink
multi: Display expired/missed tickets on webpage.
Browse files Browse the repository at this point in the history
Revoked ticket count is replaced by separate counts for expired/missed
tickets.

/vspinfo API response remains unchanged.
  • Loading branch information
jholdstock committed Sep 4, 2023
1 parent fc1f7f2 commit 54e2435
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 35 deletions.
22 changes: 15 additions & 7 deletions database/ticket.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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++
}
Expand All @@ -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.
Expand Down
54 changes: 41 additions & 13 deletions database/ticket_test.go
Original file line number Diff line number Diff line change
@@ -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.

Expand Down Expand Up @@ -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)
}
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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)
}
25 changes: 15 additions & 10 deletions webapi/cache.go
Original file line number Diff line number Diff line change
@@ -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.

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
14 changes: 11 additions & 3 deletions webapi/templates/vsp-stats.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@
</div>

<div class="col-6 col-sm-4 col-lg-2 py-3">
<div class="stat-title">Revoked tickets</div>
<div class="stat-title">Expired tickets</div>
<div class="stat-value">
{{ comma .WebApiCache.Revoked }}
<span class="text-muted">({{ float32ToPercent .WebApiCache.RevokedProportion }})</span>
{{ comma .WebApiCache.Expired }}
<span class="text-muted">({{ float32ToPercent .WebApiCache.ExpiredProportion }})</span>
</div>
</div>

<div class="col-6 col-sm-4 col-lg-2 py-3">
<div class="stat-title">Missed tickets</div>
<div class="stat-value">
{{ comma .WebApiCache.Missed }}
<span class="text-muted">({{ float32ToPercent .WebApiCache.MissedProportion }})</span>
</div>
</div>

Expand Down
4 changes: 2 additions & 2 deletions webapi/vspinfo.go
Original file line number Diff line number Diff line change
@@ -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.

Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 54e2435

Please sign in to comment.