* Delay fee broadcast and adding tickets to wallets. - Adds a `background` package which implements a dcrd notification handler. On each blockconnected notification, tickets with 6+ confirmations are marked confirmed, relevant fee transactions are broadcast, and any fees with 6+ confirmations have their tickets added to voting wallets. - VSP fee is now an absolute value measured in DCR rather than a percentage. This simplifies the code and is more appropriate for an MVP. We can re-add percentage based fees later. - Database code for tickets is now simplified to just "Insert/Update", rather than having functions for updating particular fields. - Pay fee response no longer includes the fee tx hash, because we dont necessarily broadcast the fee tx straight away. * Const for required confs
134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"reflect"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
var (
|
|
testDb = "test.db"
|
|
db *VspDatabase
|
|
)
|
|
|
|
func exampleTicket() Ticket {
|
|
return Ticket{
|
|
Hash: "Hash",
|
|
CommitmentAddress: "Address",
|
|
FeeAddressIndex: 12345,
|
|
FeeAddress: "FeeAddress",
|
|
VSPFee: 0.1,
|
|
FeeExpiration: 4,
|
|
Confirmed: false,
|
|
VoteChoices: map[string]string{"AgendaID": "Choice"},
|
|
VotingWIF: "VotingKey",
|
|
FeeTxHex: "FeeTransction",
|
|
FeeTxHash: "",
|
|
FeeConfirmed: true,
|
|
}
|
|
}
|
|
|
|
// TestDatabase runs all database tests.
|
|
func TestDatabase(t *testing.T) {
|
|
// Ensure we are starting with a clean environment.
|
|
os.Remove(testDb)
|
|
|
|
// All sub-tests to run.
|
|
tests := map[string]func(*testing.T){
|
|
"testInsertNewTicket": testInsertNewTicket,
|
|
"testGetTicketByHash": testGetTicketByHash,
|
|
}
|
|
|
|
for testName, test := range tests {
|
|
// Create a new blank database for each sub-test.
|
|
var err error
|
|
var wg sync.WaitGroup
|
|
ctx, cancel := context.WithCancel(context.TODO())
|
|
db, err = Open(ctx, &wg, testDb)
|
|
if err != nil {
|
|
t.Fatalf("error creating test database: %v", err)
|
|
}
|
|
|
|
// Run the sub-test.
|
|
t.Run(testName, test)
|
|
|
|
// Request database shutdown and wait for it to complete.
|
|
cancel()
|
|
wg.Wait()
|
|
|
|
os.Remove(testDb)
|
|
}
|
|
}
|
|
|
|
func testInsertNewTicket(t *testing.T) {
|
|
// Insert a ticket into the database.
|
|
ticket := exampleTicket()
|
|
err := db.InsertNewTicket(ticket)
|
|
if err != nil {
|
|
t.Fatalf("error storing ticket in database: %v", err)
|
|
}
|
|
|
|
// Inserting a ticket with the same hash should fail.
|
|
err = db.InsertNewTicket(ticket)
|
|
if err == nil {
|
|
t.Fatal("expected an error inserting ticket with duplicate hash")
|
|
}
|
|
|
|
// Inserting a ticket with empty hash should fail.
|
|
ticket.Hash = ""
|
|
err = db.InsertNewTicket(ticket)
|
|
if err == nil {
|
|
t.Fatal("expected an error inserting ticket with no hash")
|
|
}
|
|
}
|
|
|
|
func testGetTicketByHash(t *testing.T) {
|
|
ticket := exampleTicket()
|
|
// Insert a ticket into the database.
|
|
err := db.InsertNewTicket(ticket)
|
|
if err != nil {
|
|
t.Fatalf("error storing ticket in database: %v", err)
|
|
}
|
|
|
|
// Retrieve ticket from database.
|
|
retrieved, found, err := db.GetTicketByHash(ticket.Hash)
|
|
if err != nil {
|
|
t.Fatalf("error retrieving ticket by ticket hash: %v", err)
|
|
}
|
|
if !found {
|
|
t.Fatal("expected found==true")
|
|
}
|
|
|
|
// Check ticket fields match expected.
|
|
if retrieved.Hash != ticket.Hash ||
|
|
retrieved.CommitmentAddress != ticket.CommitmentAddress ||
|
|
retrieved.FeeAddressIndex != ticket.FeeAddressIndex ||
|
|
retrieved.FeeAddress != ticket.FeeAddress ||
|
|
retrieved.VSPFee != ticket.VSPFee ||
|
|
retrieved.FeeExpiration != ticket.FeeExpiration ||
|
|
retrieved.Confirmed != ticket.Confirmed ||
|
|
!reflect.DeepEqual(retrieved.VoteChoices, ticket.VoteChoices) ||
|
|
retrieved.VotingWIF != ticket.VotingWIF ||
|
|
retrieved.FeeTxHex != ticket.FeeTxHex ||
|
|
retrieved.FeeTxHash != ticket.FeeTxHash ||
|
|
retrieved.FeeConfirmed != ticket.FeeConfirmed {
|
|
t.Fatal("retrieved ticket value didnt match expected")
|
|
}
|
|
|
|
// Check found==false when requesting a non-existent ticket.
|
|
_, found, err = db.GetTicketByHash("Not a real ticket hash")
|
|
if err != nil {
|
|
t.Fatalf("error retrieving ticket by ticket hash: %v", err)
|
|
}
|
|
if found {
|
|
t.Fatal("expected found==false")
|
|
}
|
|
}
|
|
|
|
// TODO: Add tests for UpdateTicket, CountTickets, GetUnconfirmedTickets,
|
|
// GetPendingFees, GetUnconfirmedFees.
|
|
|
|
// TODO: Add tests for ticket.FeeExpired.
|