diff --git a/database/ticket.go b/database/ticket.go index cf9b121..c1578f1 100644 --- a/database/ticket.go +++ b/database/ticket.go @@ -17,6 +17,7 @@ type Ticket struct { BlockHeight int64 `json:"blockheight"` VoteBits uint16 `json:"votebits"` VotingKey string `json:"votingkey"` + VSPFee float64 `json:"vspfee"` Expiration int64 `json:"expiration"` } @@ -147,3 +148,70 @@ func (vdb *VspDatabase) GetTicketByHash(hash string) (Ticket, error) { return ticket, err } + +func (vdb *VspDatabase) UpdateVoteBits(hash string, voteBits uint16) error { + return vdb.db.View(func(tx *bolt.Tx) error { + ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK) + key := []byte(hash) + + ticketBytes := ticketBkt.Get(key) + 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.VoteBits = voteBits + + ticketBytes, err = json.Marshal(ticket) + if err != nil { + return fmt.Errorf("could not marshal ticket: %v", err) + } + + // Delete existing ticket + err = ticketBkt.Delete(key) + if err != nil { + return fmt.Errorf("failed to delete ticket: %v", err) + } + + // Add updated ticket + return ticketBkt.Put(key, ticketBytes) + }) +} + +func (vdb *VspDatabase) UpdateExpireAndFee(hash string, expiration int64, vspFee float64) error { + return vdb.db.View(func(tx *bolt.Tx) error { + ticketBkt := tx.Bucket(vspBktK).Bucket(ticketBktK) + key := []byte(hash) + + ticketBytes := ticketBkt.Get(key) + 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.Expiration = expiration + ticket.VSPFee = vspFee + + ticketBytes, err = json.Marshal(ticket) + if err != nil { + return fmt.Errorf("could not marshal ticket: %v", err) + } + + // Delete existing ticket + err = ticketBkt.Delete(key) + if err != nil { + return fmt.Errorf("failed to delete ticket: %v", err) + } + + // Add updated ticket + return ticketBkt.Put(key, ticketBytes) + }) +} diff --git a/webapi/methods.go b/webapi/methods.go index 84ddba9..b8fdfc0 100644 --- a/webapi/methods.go +++ b/webapi/methods.go @@ -85,28 +85,41 @@ func feeAddress(c *gin.Context) { return } - /* - // TODO - DB - deal with cached responses - ticket, err := db.GetTicketByHash(ticketHashStr) - if err != nil && !errors.Is(err, database.ErrNoTicketFound) { - c.AbortWithError(http.StatusInternalServerError, errors.New("database error")) - return - } - if err == nil { - // TODO - deal with expiration - if signature == ticket.CommitmentSignature { - sendJSONResponse(feeAddressResponse{ - Timestamp: time.Now().Unix(), - CommitmentSignature: ticket.CommitmentSignature, - FeeAddress: ticket.FeeAddress, - Expiration: ticket.Expiration, - }, http.StatusOK, c) - return + // Check for existing response + ticket, err := db.GetTicketByHash(ticketHashStr) + if err != nil && !errors.Is(err, database.ErrNoTicketFound) { + c.AbortWithError(http.StatusInternalServerError, errors.New("database error")) + return + } + if err == nil { + // Ticket already exists + if signature == ticket.CommitmentSignature { + now := time.Now() + expire := ticket.Expiration + VSPFee := ticket.VSPFee + if now.After(time.Unix(ticket.Expiration, 0)) { + expire = now.Add(defaultFeeAddressExpiration).Unix() + VSPFee = cfg.VSPFee + + err = db.UpdateExpireAndFee(ticketHashStr, expire, VSPFee) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, errors.New("database error")) + return + } } - c.AbortWithError(http.StatusBadRequest, errors.New("invalid signature")) + sendJSONResponse(feeAddressResponse{ + Timestamp: now.Unix(), + Request: feeAddressRequest, + FeeAddress: ticket.FeeAddress, + Fee: VSPFee, + Expiration: expire, + }, c) + return } - */ + c.AbortWithError(http.StatusBadRequest, errors.New("invalid signature")) + return + } walletClient, err := walletRPC() if err != nil { @@ -206,6 +219,7 @@ func feeAddress(c *gin.Context) { SDiff: blockHeader.SBits, BlockHeight: int64(blockHeader.Height), VoteBits: dcrutil.BlockValid, + VSPFee: cfg.VSPFee, Expiration: expire, // VotingKey: set during payfee } @@ -221,6 +235,7 @@ func feeAddress(c *gin.Context) { Timestamp: now.Unix(), Request: feeAddressRequest, FeeAddress: newAddress, + Fee: cfg.VSPFee, Expiration: expire, }, c) } @@ -448,6 +463,12 @@ func setVoteBits(c *gin.Context) { return } + err = db.UpdateVoteBits(txHash.String(), voteBits) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, errors.New("database error")) + return + } + // TODO: DB - error if given timestamp is older than any previous requests // TODO: DB - store setvotebits receipt in log