vspd/database/ticket.go
Jamie Holdstock ac488464c0
Rework client/server authentication. (#58)
* Rework client/server authentication.

- Remove Signature from all requests, and instead expect a signature in HTTP header "VSP-Client-Signature".
- Remove CommitmentSignatures from the database.
- Use a bool flag to indicate when a ticket is missing from the database rather than an error.

This commit introduces a lot of duplication into each of the authenticated HTTP handlers. This should be removed in future work which moves the authentication to a dedicated middleware.

* Introduce auth and rpc middleware.

This removed the duplication added in the previous commit, and also removes the duplication of RPC client error handling.
2020-05-26 14:14:38 +01:00

188 lines
4.5 KiB
Go

package database
import (
"encoding/json"
"errors"
"fmt"
"time"
bolt "go.etcd.io/bbolt"
)
type Ticket struct {
Hash string `json:"hash"`
CommitmentAddress string `json:"commitmentaddress"`
FeeAddress string `json:"feeaddress"`
SDiff float64 `json:"sdiff"`
BlockHeight int64 `json:"blockheight"`
VoteChoices map[string]string `json:"votechoices"`
VotingKey string `json:"votingkey"`
VSPFee float64 `json:"vspfee"`
FeeExpiration int64 `json:"feeexpiration"`
FeeTxHash string `json:"feetxhash"`
}
func (t *Ticket) FeeExpired() bool {
now := time.Now()
return now.After(time.Unix(t.FeeExpiration, 0))
}
var (
ErrNoTicketFound = errors.New("no ticket found")
)
func (vdb *VspDatabase) InsertTicket(ticket Ticket) error {
hashBytes := []byte(ticket.Hash)
return vdb.db.Update(func(tx *bolt.Tx) error {
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
if ticketBkt.Get(hashBytes) != nil {
return fmt.Errorf("ticket already exists with hash %s", ticket.Hash)
}
// TODO: Error if a ticket already exists with the same fee address.
ticketBytes, err := json.Marshal(ticket)
if err != nil {
return err
}
return ticketBkt.Put(hashBytes, ticketBytes)
})
}
func (vdb *VspDatabase) SetTicketVotingKey(ticketHash, votingKey string, voteChoices map[string]string, feeTxHash string) error {
return vdb.db.Update(func(tx *bolt.Tx) error {
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
hashBytes := []byte(ticketHash)
ticketBytes := ticketBkt.Get(hashBytes)
if ticketBytes == nil {
return ErrNoTicketFound
}
var ticket Ticket
err := json.Unmarshal(ticketBytes, &ticket)
if err != nil {
return fmt.Errorf("could not unmarshal ticket: %v", err)
}
ticket.VotingKey = votingKey
ticket.VoteChoices = voteChoices
ticket.FeeTxHash = feeTxHash
ticketBytes, err = json.Marshal(ticket)
if err != nil {
return fmt.Errorf("could not marshal ticket: %v", err)
}
return ticketBkt.Put(hashBytes, ticketBytes)
})
}
func (vdb *VspDatabase) GetTicketByHash(ticketHash string) (Ticket, bool, error) {
var ticket Ticket
var found bool
err := vdb.db.View(func(tx *bolt.Tx) error {
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
ticketBytes := ticketBkt.Get([]byte(ticketHash))
if ticketBytes == nil {
return nil
}
err := json.Unmarshal(ticketBytes, &ticket)
if err != nil {
return fmt.Errorf("could not unmarshal ticket: %v", err)
}
found = true
return nil
})
return ticket, found, err
}
func (vdb *VspDatabase) UpdateVoteChoices(ticketHash string, voteChoices map[string]string) error {
return vdb.db.Update(func(tx *bolt.Tx) error {
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
hashBytes := []byte(ticketHash)
ticketBytes := ticketBkt.Get(hashBytes)
if ticketBytes == nil {
return ErrNoTicketFound
}
var ticket Ticket
err := json.Unmarshal(ticketBytes, &ticket)
if err != nil {
return fmt.Errorf("could not unmarshal ticket: %v", err)
}
ticket.VoteChoices = voteChoices
ticketBytes, err = json.Marshal(ticket)
if err != nil {
return fmt.Errorf("could not marshal ticket: %v", err)
}
return ticketBkt.Put(hashBytes, ticketBytes)
})
}
func (vdb *VspDatabase) UpdateExpireAndFee(ticketHash string, expiration int64, vspFee float64) error {
return vdb.db.Update(func(tx *bolt.Tx) error {
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
hashBytes := []byte(ticketHash)
ticketBytes := ticketBkt.Get(hashBytes)
if ticketBytes == nil {
return ErrNoTicketFound
}
var ticket Ticket
err := json.Unmarshal(ticketBytes, &ticket)
if err != nil {
return fmt.Errorf("could not unmarshal ticket: %v", err)
}
ticket.FeeExpiration = expiration
ticket.VSPFee = vspFee
ticketBytes, err = json.Marshal(ticket)
if err != nil {
return fmt.Errorf("could not marshal ticket: %v", err)
}
return ticketBkt.Put(hashBytes, ticketBytes)
})
}
func (vdb *VspDatabase) CountTickets() (int, int, error) {
var total, feePaid int
err := vdb.db.View(func(tx *bolt.Tx) error {
ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK)
return ticketBkt.ForEach(func(k, v []byte) error {
total++
var ticket Ticket
err := json.Unmarshal(v, &ticket)
if err != nil {
return fmt.Errorf("could not unmarshal ticket: %v", err)
}
if ticket.FeeTxHash != "" {
feePaid++
}
return nil
})
})
if err != nil {
return 0, 0, err
}
return total, feePaid, nil
}