multi: Display expired/missed tickets on webpage.
Revoked ticket count is replaced by separate counts for expired/missed tickets. /vspinfo API response remains unchanged.
This commit is contained in:
parent
fc1f7f2955
commit
54e243526e
@ -308,13 +308,14 @@ func (vdb *VspDatabase) Size() (uint64, error) {
|
|||||||
return size, err
|
return size, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountTickets returns the total number of voted, revoked, and currently voting
|
// CountTickets returns the total number of voted, expired, missed, and
|
||||||
// tickets. This func iterates over every ticket so should be used sparingly.
|
// currently voting tickets. This func iterates over every ticket so should be
|
||||||
func (vdb *VspDatabase) CountTickets() (int64, int64, int64, error) {
|
// used sparingly.
|
||||||
|
func (vdb *VspDatabase) CountTickets() (int64, int64, int64, int64, error) {
|
||||||
vdb.ticketsMtx.RLock()
|
vdb.ticketsMtx.RLock()
|
||||||
defer vdb.ticketsMtx.RUnlock()
|
defer vdb.ticketsMtx.RUnlock()
|
||||||
|
|
||||||
var voting, voted, revoked int64
|
var voting, voted, expired, missed int64
|
||||||
err := vdb.db.View(func(tx *bolt.Tx) error {
|
err := vdb.db.View(func(tx *bolt.Tx) error {
|
||||||
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
|
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
|
||||||
|
|
||||||
@ -325,8 +326,15 @@ func (vdb *VspDatabase) CountTickets() (int64, int64, int64, error) {
|
|||||||
switch TicketOutcome(tBkt.Get(outcomeK)) {
|
switch TicketOutcome(tBkt.Get(outcomeK)) {
|
||||||
case Voted:
|
case Voted:
|
||||||
voted++
|
voted++
|
||||||
case Revoked, Expired, Missed:
|
case Expired:
|
||||||
revoked++
|
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:
|
default:
|
||||||
voting++
|
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.
|
// GetUnconfirmedTickets returns tickets which are not yet confirmed.
|
||||||
|
|||||||
@ -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
|
// Use of this source code is governed by an ISC
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -228,8 +228,8 @@ func testFilterTickets(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testCountTickets(t *testing.T) {
|
func testCountTickets(t *testing.T) {
|
||||||
count := func(test string, expectedVoting, expectedVoted, expectedRevoked int64) {
|
count := func(test string, expectedVoting, expectedVoted, expectedExpired, expectedMissed int64) {
|
||||||
voting, voted, revoked, err := db.CountTickets()
|
voting, voted, expired, missed, err := db.CountTickets()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error counting tickets: %v", err)
|
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",
|
t.Fatalf("test %s: expected %d voted tickets, got %d",
|
||||||
test, expectedVoted, voted)
|
test, expectedVoted, voted)
|
||||||
}
|
}
|
||||||
if revoked != expectedRevoked {
|
if expired != expectedExpired {
|
||||||
t.Fatalf("test %s: expected %d revoked tickets, got %d",
|
t.Fatalf("test %s: expected %d expired tickets, got %d",
|
||||||
test, expectedRevoked, revoked)
|
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.
|
// 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.
|
// Insert a ticket with non-confirmed fee into the database.
|
||||||
// This should not be counted.
|
// This should not be counted.
|
||||||
@ -260,7 +264,7 @@ func testCountTickets(t *testing.T) {
|
|||||||
t.Fatalf("error storing ticket in database: %v", err)
|
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.
|
// Insert a ticket with confirmed fee into the database.
|
||||||
// This should be counted.
|
// This should be counted.
|
||||||
@ -271,7 +275,7 @@ func testCountTickets(t *testing.T) {
|
|||||||
t.Fatalf("error storing ticket in database: %v", err)
|
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.
|
// Insert a voted ticket into the database.
|
||||||
// This should be counted.
|
// This should be counted.
|
||||||
@ -283,17 +287,41 @@ func testCountTickets(t *testing.T) {
|
|||||||
t.Fatalf("error storing ticket in database: %v", err)
|
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.
|
// This should be counted.
|
||||||
ticket4 := exampleTicket()
|
ticket4 := exampleTicket()
|
||||||
ticket4.FeeTxStatus = FeeConfirmed
|
ticket4.FeeTxStatus = FeeConfirmed
|
||||||
ticket4.Outcome = Revoked
|
ticket4.Outcome = Expired
|
||||||
err = db.InsertNewTicket(ticket4)
|
err = db.InsertNewTicket(ticket4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error storing ticket in database: %v", err)
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
// Use of this source code is governed by an ISC
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -31,12 +31,14 @@ type cacheData struct {
|
|||||||
DatabaseSize string
|
DatabaseSize string
|
||||||
Voting int64
|
Voting int64
|
||||||
Voted int64
|
Voted int64
|
||||||
Revoked int64
|
Expired int64
|
||||||
|
Missed int64
|
||||||
VotingWalletsOnline int64
|
VotingWalletsOnline int64
|
||||||
TotalVotingWallets int64
|
TotalVotingWallets int64
|
||||||
BlockHeight uint32
|
BlockHeight uint32
|
||||||
NetworkProportion float32
|
NetworkProportion float32
|
||||||
RevokedProportion float32
|
ExpiredProportion float32
|
||||||
|
MissedProportion float32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cache) getData() cacheData {
|
func (c *cache) getData() cacheData {
|
||||||
@ -66,8 +68,8 @@ func (c *cache) update(db *database.VspDatabase, dcrd rpc.DcrdConnect,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get latest counts of voting, voted and revoked tickets.
|
// Get latest counts of voting, voted, expired and missed tickets.
|
||||||
voting, voted, revoked, err := db.CountTickets()
|
voting, voted, expired, missed, err := db.CountTickets()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -104,17 +106,20 @@ func (c *cache) update(db *database.VspDatabase, dcrd rpc.DcrdConnect,
|
|||||||
c.data.Voted = voted
|
c.data.Voted = voted
|
||||||
c.data.TotalVotingWallets = int64(len(clients) + len(failedConnections))
|
c.data.TotalVotingWallets = int64(len(clients) + len(failedConnections))
|
||||||
c.data.VotingWalletsOnline = int64(len(clients))
|
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.BlockHeight = bestBlock.Height
|
||||||
c.data.NetworkProportion = float32(voting) / float32(bestBlock.PoolSize)
|
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 {
|
if total == 0 {
|
||||||
c.data.RevokedProportion = 0
|
c.data.ExpiredProportion = 0
|
||||||
|
c.data.MissedProportion = 0
|
||||||
} else {
|
} else {
|
||||||
c.data.RevokedProportion = float32(revoked) / float32(total)
|
c.data.ExpiredProportion = float32(expired) / float32(total)
|
||||||
|
c.data.MissedProportion = float32(missed) / float32(total)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -13,10 +13,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-6 col-sm-4 col-lg-2 py-3">
|
<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">
|
<div class="stat-value">
|
||||||
{{ comma .WebApiCache.Revoked }}
|
{{ comma .WebApiCache.Expired }}
|
||||||
<span class="text-muted">({{ float32ToPercent .WebApiCache.RevokedProportion }})</span>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -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
|
// Use of this source code is governed by an ISC
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ func (s *Server) vspInfo(c *gin.Context) {
|
|||||||
Voted: cachedStats.Voted,
|
Voted: cachedStats.Voted,
|
||||||
TotalVotingWallets: cachedStats.TotalVotingWallets,
|
TotalVotingWallets: cachedStats.TotalVotingWallets,
|
||||||
VotingWalletsOnline: cachedStats.VotingWalletsOnline,
|
VotingWalletsOnline: cachedStats.VotingWalletsOnline,
|
||||||
Revoked: cachedStats.Revoked,
|
Revoked: cachedStats.Expired + cachedStats.Missed,
|
||||||
BlockHeight: cachedStats.BlockHeight,
|
BlockHeight: cachedStats.BlockHeight,
|
||||||
NetworkProportion: cachedStats.NetworkProportion,
|
NetworkProportion: cachedStats.NetworkProportion,
|
||||||
}, c)
|
}, c)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user