Clarify "setaltsig" terminology.

Stardardize "alt sig"/"alt signature"/"alt signing address" terminology to "alternate signing address".
This commit is contained in:
jholdstock 2021-11-14 12:50:31 +00:00 committed by Jamie Holdstock
parent b1a68a94fe
commit ab5aa4dd6d
17 changed files with 355 additions and 350 deletions

View File

@ -103,11 +103,11 @@ func blockConnected() {
funcName, ticket.Hash, err)
}
// This will not error if an alternate signature does not
// This will not error if an alternate signing address does not
// exist for ticket.
err = db.DeleteAltSig(ticket.Hash)
err = db.DeleteAltSignAddr(ticket.Hash)
if err != nil {
log.Errorf("%s: db.DeleteAltSig error (ticketHash=%s): %v",
log.Errorf("%s: db.DeleteAltSignAddr error (ticketHash=%s): %v",
funcName, ticket.Hash, err)
}
} else {

View File

@ -1,124 +0,0 @@
// Copyright (c) 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package database
import (
"errors"
"fmt"
bolt "go.etcd.io/bbolt"
)
// The keys used to store the altsig in the database.
var (
altSigAddrK = []byte("altsig")
reqK = []byte("req")
reqSigK = []byte("reqsig")
resK = []byte("res")
resSigK = []byte("ressig")
)
// AltSigData holds the information needed to prove that a client added an
// alternate signature address.
type AltSigData struct {
// AltSigAddr is the new alternate signature address. It is base 58
// encoded.
AltSigAddr string
// Req is the original request to set an alternate signature.
Req []byte
// ReqSig is the request's signature signed by the private key that
// corresponds to the address. It is base 64 encoded.
ReqSig string
// Res is the original response from the server to the alternate
// signature address.
Res []byte
// ResSig is the response's signature signed by the server. It is base
// 64 encoded.
ResSig string
}
// InsertAltSig will insert the provided ticket into the database. Returns an
// error if data for the ticket hash already exist.
//
// Passed data must have no empty fields.
func (vdb *VspDatabase) InsertAltSig(ticketHash string, data *AltSigData) error {
if data == nil {
return errors.New("alt sig data must not be nil for inserts")
}
if data.AltSigAddr == "" || len(data.Req) == 0 || data.ReqSig == "" ||
len(data.Res) == 0 || data.ResSig == "" {
return errors.New("alt sig data has empty parameters")
}
return vdb.db.Update(func(tx *bolt.Tx) error {
altSigBkt := tx.Bucket(vspBktK).Bucket(altSigBktK)
// Create a bucket for the new altsig. Returns an error if bucket
// already exists.
bkt, err := altSigBkt.CreateBucket([]byte(ticketHash))
if err != nil {
return fmt.Errorf("could not create bucket for altsig: %w", err)
}
if err := bkt.Put(altSigAddrK, []byte(data.AltSigAddr)); err != nil {
return err
}
if err := bkt.Put(reqK, data.Req); err != nil {
return err
}
if err := bkt.Put(reqSigK, []byte(data.ReqSig)); err != nil {
return err
}
if err := bkt.Put(resK, data.Res); err != nil {
return err
}
return bkt.Put(resSigK, []byte(data.ResSig))
})
}
// DeleteAltSig deletes an altsig from the database. Does not error if there is
// no altsig in the database.
func (vdb *VspDatabase) DeleteAltSig(ticketHash string) error {
return vdb.db.Update(func(tx *bolt.Tx) error {
altSigBkt := tx.Bucket(vspBktK).Bucket(altSigBktK)
// Don't attempt delete if doesn't exist.
bkt := altSigBkt.Bucket([]byte(ticketHash))
if bkt == nil {
return nil
}
err := altSigBkt.DeleteBucket([]byte(ticketHash))
if err != nil {
return fmt.Errorf("could not delete altsig: %w", err)
}
return nil
})
}
// AltSigData retrieves a ticket's alternate signature data. Existence of an
// alternate signature can be inferred by no error and nil data return.
func (vdb *VspDatabase) AltSigData(ticketHash string) (*AltSigData, error) {
var h *AltSigData
return h, vdb.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(vspBktK).Bucket(altSigBktK).Bucket([]byte(ticketHash))
if bkt == nil {
return nil
}
h = &AltSigData{
AltSigAddr: string(bkt.Get(altSigAddrK)),
Req: bkt.Get(reqK),
ReqSig: string(bkt.Get(reqSigK)),
Res: bkt.Get(resK),
ResSig: string(bkt.Get(resSigK)),
}
return nil
})
}

View File

@ -1,117 +0,0 @@
// Copyright (c) 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package database
import (
"reflect"
"testing"
)
func exampleAltSigData() *AltSigData {
return &AltSigData{
AltSigAddr: randString(35, addrCharset),
Req: randBytes(1000),
ReqSig: randString(96, sigCharset),
Res: randBytes(1000),
ResSig: randString(96, sigCharset),
}
}
func ensureData(t *testing.T, ticketHash string, wantData *AltSigData) {
t.Helper()
data, err := db.AltSigData(ticketHash)
if err != nil {
t.Fatalf("unexpected error fetching alt signature data: %v", err)
}
if !reflect.DeepEqual(wantData, data) {
t.Fatal("want data different than actual")
}
}
func testAltSigData(t *testing.T) {
ticketHash := randString(64, hexCharset)
// Not added yet so no values should exist in the db.
h, err := db.AltSigData(ticketHash)
if err != nil {
t.Fatalf("unexpected error fetching alt signature data: %v", err)
}
if h != nil {
t.Fatal("expected no data")
}
// Insert an altsig.
data := exampleAltSigData()
if err := db.InsertAltSig(ticketHash, data); err != nil {
t.Fatalf("unexpected error storing altsig in database: %v", err)
}
ensureData(t, ticketHash, data)
}
func testInsertAltSig(t *testing.T) {
ticketHash := randString(64, hexCharset)
// Not added yet so no values should exist in the db.
ensureData(t, ticketHash, nil)
data := exampleAltSigData()
// Clear alt sig addr for test.
data.AltSigAddr = ""
if err := db.InsertAltSig(ticketHash, data); err == nil {
t.Fatalf("expected error for insert blank address")
}
if err := db.InsertAltSig(ticketHash, nil); err == nil {
t.Fatalf("expected error for nil data")
}
// Still no change on errors.
ensureData(t, ticketHash, nil)
// Re-add alt sig addr.
data.AltSigAddr = randString(35, addrCharset)
// Insert an altsig.
if err := db.InsertAltSig(ticketHash, data); err != nil {
t.Fatalf("unexpected error storing altsig in database: %v", err)
}
ensureData(t, ticketHash, data)
// Further additions should error and not change the data.
secondData := exampleAltSigData()
secondData.AltSigAddr = data.AltSigAddr
if err := db.InsertAltSig(ticketHash, secondData); err == nil {
t.Fatalf("expected error for second altsig addition")
}
ensureData(t, ticketHash, data)
}
func testDeleteAltSig(t *testing.T) {
ticketHash := randString(64, hexCharset)
// Nothing to delete.
if err := db.DeleteAltSig(ticketHash); err != nil {
t.Fatalf("unexpected error deleting nonexistant altsig")
}
// Insert an altsig.
data := exampleAltSigData()
if err := db.InsertAltSig(ticketHash, data); err != nil {
t.Fatalf("unexpected error storing altsig in database: %v", err)
}
ensureData(t, ticketHash, data)
if err := db.DeleteAltSig(ticketHash); err != nil {
t.Fatalf("unexpected error deleting altsig: %v", err)
}
ensureData(t, ticketHash, nil)
}

123
database/altsignaddr.go Normal file
View File

@ -0,0 +1,123 @@
// Copyright (c) 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package database
import (
"errors"
"fmt"
bolt "go.etcd.io/bbolt"
)
// The keys used to store alternate signing addresses in the database.
var (
altSignAddrK = []byte("altsig")
reqK = []byte("req")
reqSigK = []byte("reqsig")
respK = []byte("res")
respSigK = []byte("ressig")
)
// AltSignAddrData holds the information needed to prove that a client added an
// alternate signing address.
type AltSignAddrData struct {
// AltSignAddr is the new alternate signing address. It is base 58 encoded.
AltSignAddr string
// Req is the original request to set an alternate signing address.
Req []byte
// ReqSig is the request's signature signed by the commitment address of the
// corresponding ticket. It is base 64 encoded.
ReqSig string
// Resp is the original response from the server to the alternate signing
// address.
Resp []byte
// RespSig is the response's signature signed by the server. It is base 64
// encoded.
RespSig string
}
// InsertAltSignAddr will insert the provided alternate signing address into the
// database. Returns an error if data for the ticket hash already exist.
//
// Passed data must have no empty fields.
func (vdb *VspDatabase) InsertAltSignAddr(ticketHash string, data *AltSignAddrData) error {
if data == nil {
return errors.New("alt sign addr data must not be nil for inserts")
}
if data.AltSignAddr == "" || len(data.Req) == 0 || data.ReqSig == "" ||
len(data.Resp) == 0 || data.RespSig == "" {
return errors.New("alt sign addr data has empty parameters")
}
return vdb.db.Update(func(tx *bolt.Tx) error {
altSignAddrBkt := tx.Bucket(vspBktK).Bucket(altSignAddrBktK)
// Create a bucket for the new alt sign addr. Returns an error if bucket
// already exists.
bkt, err := altSignAddrBkt.CreateBucket([]byte(ticketHash))
if err != nil {
return fmt.Errorf("could not create bucket for alt sign addr: %w", err)
}
if err := bkt.Put(altSignAddrK, []byte(data.AltSignAddr)); err != nil {
return err
}
if err := bkt.Put(reqK, data.Req); err != nil {
return err
}
if err := bkt.Put(reqSigK, []byte(data.ReqSig)); err != nil {
return err
}
if err := bkt.Put(respK, data.Resp); err != nil {
return err
}
return bkt.Put(respSigK, []byte(data.RespSig))
})
}
// DeleteAltSignAddr deletes an alternate signing address from the database.
// Does not error if there is no record in the database to delete.
func (vdb *VspDatabase) DeleteAltSignAddr(ticketHash string) error {
return vdb.db.Update(func(tx *bolt.Tx) error {
altSignAddrBkt := tx.Bucket(vspBktK).Bucket(altSignAddrBktK)
// Don't attempt delete if doesn't exist.
bkt := altSignAddrBkt.Bucket([]byte(ticketHash))
if bkt == nil {
return nil
}
err := altSignAddrBkt.DeleteBucket([]byte(ticketHash))
if err != nil {
return fmt.Errorf("could not delete altsignaddr: %w", err)
}
return nil
})
}
// AltSignAddrData retrieves a ticket's alternate signing data. Existence of an
// alternate signing address can be inferred by no error and nil data return.
func (vdb *VspDatabase) AltSignAddrData(ticketHash string) (*AltSignAddrData, error) {
var h *AltSignAddrData
return h, vdb.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(vspBktK).Bucket(altSignAddrBktK).Bucket([]byte(ticketHash))
if bkt == nil {
return nil
}
h = &AltSignAddrData{
AltSignAddr: string(bkt.Get(altSignAddrK)),
Req: bkt.Get(reqK),
ReqSig: string(bkt.Get(reqSigK)),
Resp: bkt.Get(respK),
RespSig: string(bkt.Get(respSigK)),
}
return nil
})
}

View File

@ -0,0 +1,118 @@
// Copyright (c) 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package database
import (
"reflect"
"testing"
)
func exampleAltSignAddrData() *AltSignAddrData {
return &AltSignAddrData{
AltSignAddr: randString(35, addrCharset),
Req: randBytes(1000),
ReqSig: randString(96, sigCharset),
Resp: randBytes(1000),
RespSig: randString(96, sigCharset),
}
}
// ensureData will confirm that the provided data exists in the database.
func ensureData(t *testing.T, ticketHash string, wantData *AltSignAddrData) {
t.Helper()
data, err := db.AltSignAddrData(ticketHash)
if err != nil {
t.Fatalf("unexpected error fetching alt sign address data: %v", err)
}
if !reflect.DeepEqual(wantData, data) {
t.Fatal("want data different than actual")
}
}
func testAltSignAddrData(t *testing.T) {
ticketHash := randString(64, hexCharset)
// Not added yet so no values should exist in the db.
h, err := db.AltSignAddrData(ticketHash)
if err != nil {
t.Fatalf("unexpected error fetching alt sign address data: %v", err)
}
if h != nil {
t.Fatal("expected no data")
}
// Insert an alt sign address.
data := exampleAltSignAddrData()
if err := db.InsertAltSignAddr(ticketHash, data); err != nil {
t.Fatalf("unexpected error storing alt sign addr in database: %v", err)
}
ensureData(t, ticketHash, data)
}
func testInsertAltSignAddr(t *testing.T) {
ticketHash := randString(64, hexCharset)
// Not added yet so no values should exist in the db.
ensureData(t, ticketHash, nil)
data := exampleAltSignAddrData()
// Clear alt sign addr for test.
data.AltSignAddr = ""
if err := db.InsertAltSignAddr(ticketHash, data); err == nil {
t.Fatalf("expected error for insert blank address")
}
if err := db.InsertAltSignAddr(ticketHash, nil); err == nil {
t.Fatalf("expected error for nil data")
}
// Still no change on errors.
ensureData(t, ticketHash, nil)
// Re-add alt sig addr.
data.AltSignAddr = randString(35, addrCharset)
// Insert an alt sign addr.
if err := db.InsertAltSignAddr(ticketHash, data); err != nil {
t.Fatalf("unexpected error storing alt sig addr in database: %v", err)
}
ensureData(t, ticketHash, data)
// Further additions should error and not change the data.
secondData := exampleAltSignAddrData()
secondData.AltSignAddr = data.AltSignAddr
if err := db.InsertAltSignAddr(ticketHash, secondData); err == nil {
t.Fatalf("expected error for second alt sig addr addition")
}
ensureData(t, ticketHash, data)
}
func testDeleteAltSignAddr(t *testing.T) {
ticketHash := randString(64, hexCharset)
// Nothing to delete.
if err := db.DeleteAltSignAddr(ticketHash); err != nil {
t.Fatalf("unexpected error deleting nonexistant alt sign addr")
}
// Insert an alt sign addr.
data := exampleAltSignAddrData()
if err := db.InsertAltSignAddr(ticketHash, data); err != nil {
t.Fatalf("unexpected error storing alt sign addr in database: %v", err)
}
ensureData(t, ticketHash, data)
if err := db.DeleteAltSignAddr(ticketHash); err != nil {
t.Fatalf("unexpected error deleting alt sign addr: %v", err)
}
ensureData(t, ticketHash, nil)
}

View File

@ -50,8 +50,8 @@ var (
privateKeyK = []byte("privatekey")
// lastaddressindex is the index of the last address used for fees.
lastAddressIndexK = []byte("lastaddressindex")
// altSigBktK stores alternate signatures.
altSigBktK = []byte("altsigbkt")
// altSignAddrBktK stores alternate signing addresses.
altSignAddrBktK = []byte("altsigbkt")
)
const (

View File

@ -1,4 +1,4 @@
// Copyright (c) 2020 The Decred developers
// Copyright (c) 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -24,9 +24,13 @@ const (
feeXPub = "feexpub"
maxVoteChangeRecords = 3
// addrCharset is a list of all valid DCR address characters.
addrCharset = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
hexCharset = "1234567890abcdef"
sigCharset = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/="
// hexCharset is a list of all valid hexadecimal characters.
hexCharset = "1234567890abcdef"
// sigCharset is a list of all valid request/response signature characters
// (base64 encoding).
sigCharset = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/="
)
var (
@ -72,9 +76,9 @@ func TestDatabase(t *testing.T) {
"testDeleteTicket": testDeleteTicket,
"testVoteChangeRecords": testVoteChangeRecords,
"testHTTPBackup": testHTTPBackup,
"testAltSigData": testAltSigData,
"testInsertAltSig": testInsertAltSig,
"testDeleteAltSig": testDeleteAltSig,
"testAltSignAddrData": testAltSignAddrData,
"testInsertAltSignAddr": testInsertAltSignAddr,
"testDeleteAltSignAddr": testDeleteAltSignAddr,
}
for testName, test := range tests {

View File

@ -10,22 +10,22 @@ import (
bolt "go.etcd.io/bbolt"
)
func altSigUpgrade(db *bolt.DB) error {
log.Infof("Upgrading database to version %d", altSigVersion)
func altSignAddrUpgrade(db *bolt.DB) error {
log.Infof("Upgrading database to version %d", altSignAddrVersion)
// Run the upgrade in a single database transaction so it can be safely
// rolled back if an error is encountered.
err := db.Update(func(tx *bolt.Tx) error {
vspBkt := tx.Bucket(vspBktK)
// Create altsig bucket.
_, err := vspBkt.CreateBucket(altSigBktK)
// Create alt sign addr bucket.
_, err := vspBkt.CreateBucket(altSignAddrBktK)
if err != nil {
return fmt.Errorf("failed to create %s bucket: %w", altSigBktK, err)
return fmt.Errorf("failed to create %s bucket: %w", altSignAddrBktK, err)
}
// Update database version.
err = vspBkt.Put(versionK, uint32ToBytes(altSigVersion))
err = vspBkt.Put(versionK, uint32ToBytes(altSignAddrVersion))
if err != nil {
return fmt.Errorf("failed to update db version: %w", err)
}

View File

@ -25,14 +25,14 @@ const (
// moves each ticket into its own bucket and does away with JSON encoding.
ticketBucketVersion = 3
// altSigVersion adds a bucket to store alternate signatures used to verify
// messages sent to the vspd.
altSigVersion = 4
// altSignAddrVersion adds a bucket to store alternate sign addresses used
// to verify messages sent to the vspd.
altSignAddrVersion = 4
// latestVersion is the latest version of the database that is understood by
// vspd. Databases with recorded versions higher than this will fail to open
// (meaning any upgrades prevent reverting to older software).
latestVersion = altSigVersion
latestVersion = altSignAddrVersion
)
// upgrades maps between old database versions and the upgrade function to
@ -40,7 +40,7 @@ const (
var upgrades = []func(tx *bolt.DB) error{
initialVersion: removeOldFeeTxUpgrade,
removeOldFeeTxVersion: ticketBucketUpgrade,
ticketBucketVersion: altSigUpgrade,
ticketBucketVersion: altSignAddrUpgrade,
}
// v1Ticket has the json tags required to unmarshal tickets stored in the

View File

@ -69,12 +69,12 @@ its voting wallets unless both of these calls have succeeded.**
Set an alternate signing address for a ticket. The ticket must be valid and will
be transmitted to the network if not found. If set, for all future requests
involving this ticket, the vsp will check that a signature is good for this
involving this ticket, the VSP will check that a signature is good for this
address and fallback to the commitment address if not. The address must be valid
for the network and a pay to secp256k1 ECDSA pubkey hash script. The address can
only be set once. Further requests to set a new address will be rejected.
- `POST /api/v3/setaltsig`
- `POST /api/v3/setaltsignaddr`
Request:
@ -84,7 +84,7 @@ only be set once. Further requests to set a new address will be rejected.
"tickethash":"1b9f5dc3b4872c47f66b148b0633647458123d72a0f0623a90890cc51a668737",
"tickethex":"0100000001a8...bfa6e4bf9c5ec1",
"parenthex":"0100000022a7...580771a3064710",
"altsigaddress":"Tsfkn6k9AoYgVZRV6ZzcgmuVSgCdJQt9JY2"
"altsignaddress":"Tsfkn6k9AoYgVZRV6ZzcgmuVSgCdJQt9JY2"
}
```

View File

@ -41,7 +41,7 @@ type searchResult struct {
Hash string
Found bool
Ticket database.Ticket
AltSig string
AltSignAddr string
VoteChanges map[uint32]database.VoteChangeRecord
MaxVoteChanges int
}
@ -169,16 +169,16 @@ func ticketSearch(c *gin.Context) {
return
}
altSigData, err := db.AltSigData(hash)
altSignAddrData, err := db.AltSignAddrData(hash)
if err != nil {
log.Errorf("db.AltSigData error (ticketHash=%s): %v", hash, err)
log.Errorf("db.AltSignAddrData error (ticketHash=%s): %v", hash, err)
c.String(http.StatusInternalServerError, "Error getting alt sig from db")
return
}
altSig := ""
if altSigData != nil {
altSig = altSigData.AltSigAddr
altSignAddr := ""
if altSignAddrData != nil {
altSignAddr = altSignAddrData.AltSignAddr
}
c.HTML(http.StatusOK, "admin.html", gin.H{
@ -186,7 +186,7 @@ func ticketSearch(c *gin.Context) {
Hash: hash,
Found: found,
Ticket: ticket,
AltSig: altSig,
AltSignAddr: altSignAddr,
VoteChanges: voteChanges,
MaxVoteChanges: cfg.MaxVoteChangeRecords,
},

View File

@ -359,17 +359,17 @@ func vspAuth() gin.HandlerFunc {
err = validateSignature(reqBytes, commitmentAddress, c)
if err != nil {
// Don't return an error straight away if sig validation fails -
// first check if we have an alternate sig address for this ticket.
altSigData, err := db.AltSigData(hash)
// first check if we have an alternate sign address for this ticket.
altSigData, err := db.AltSignAddrData(hash)
if err != nil {
log.Errorf("%s: db.AltSigData failed (ticketHash=%s): %v", funcName, hash, err)
log.Errorf("%s: db.AltSignAddrData failed (ticketHash=%s): %v", funcName, hash, err)
sendError(errInternalError, c)
return
}
// If we have no alternate sig, or if validating with the alt sig
// fails, return an error to the client.
if altSigData == nil || validateSignature(reqBytes, altSigData.AltSigAddr, c) != nil {
// If we have no alternate sign address, or if validating with the
// alt sign addr fails, return an error to the client.
if altSigData == nil || validateSignature(reqBytes, altSigData.AltSignAddr, c) != nil {
log.Warnf("%s: Bad signature (clientIP=%s, ticketHash=%s)", funcName, c.ClientIP(), hash)
sendError(errBadSignature, c)
return

View File

@ -25,10 +25,10 @@ type Node interface {
GetRawTransaction(txHash string) (*dcrdtypes.TxRawResult, error)
}
// setAltSig is the handler for "POST /api/v3/setaltsig".
func setAltSig(c *gin.Context) {
// setAltSignAddr is the handler for "POST /api/v3/setaltsignaddr".
func setAltSignAddr(c *gin.Context) {
const funcName = "setAltSig"
const funcName = "setAltSignAddr"
// Get values which have been added to context by middleware.
dcrdClient := c.MustGet(dcrdKey).(Node)
@ -45,23 +45,23 @@ func setAltSig(c *gin.Context) {
return
}
var request setAltSigRequest
var request setAltSignAddrRequest
if err := binding.JSON.BindBody(reqBytes, &request); err != nil {
log.Warnf("%s: Bad request (clientIP=%s): %v", funcName, c.ClientIP(), err)
sendErrorWithMsg(err.Error(), errBadRequest, c)
return
}
altSigAddr, ticketHash := request.AltSigAddress, request.TicketHash
altSignAddr, ticketHash := request.AltSignAddress, request.TicketHash
currentData, err := db.AltSigData(ticketHash)
currentData, err := db.AltSignAddrData(ticketHash)
if err != nil {
log.Errorf("%s: db.AltSigData (ticketHash=%s): %v", funcName, ticketHash, err)
log.Errorf("%s: db.AltSignAddrData (ticketHash=%s): %v", funcName, ticketHash, err)
sendError(errInternalError, c)
return
}
if currentData != nil {
msg := "alternate signature data already exists"
msg := "alternate sign address data already exists"
log.Warnf("%s: %s (ticketHash=%s)", funcName, msg, ticketHash)
sendErrorWithMsg(msg, errBadRequest, c)
return
@ -69,14 +69,14 @@ func setAltSig(c *gin.Context) {
}
// Fail fast if the pubkey doesn't decode properly.
addr, err := stdaddr.DecodeAddressV0(altSigAddr, cfg.NetParams)
addr, err := stdaddr.DecodeAddressV0(altSignAddr, cfg.NetParams)
if err != nil {
log.Warnf("%s: Alt sig address cannot be decoded (clientIP=%s): %v", funcName, c.ClientIP(), err)
log.Warnf("%s: Alt sign address cannot be decoded (clientIP=%s): %v", funcName, c.ClientIP(), err)
sendErrorWithMsg(err.Error(), errBadRequest, c)
return
}
if _, ok := addr.(*stdaddr.AddressPubKeyHashEcdsaSecp256k1V0); !ok {
log.Warnf("%s: Alt sig address is unexpected type (clientIP=%s, type=%T)", funcName, c.ClientIP(), addr)
log.Warnf("%s: Alt sign address is unexpected type (clientIP=%s, type=%T)", funcName, c.ClientIP(), addr)
sendErrorWithMsg("wrong type for alternate signing address", errBadRequest, c)
return
}
@ -103,28 +103,26 @@ func setAltSig(c *gin.Context) {
return
}
sigStr := c.GetHeader("VSP-Client-Signature")
// Send success response to client.
res, resSig := sendJSONResponse(setAltSigResponse{
resp, respSig := sendJSONResponse(setAltSignAddrResponse{
Timestamp: time.Now().Unix(),
Request: reqBytes,
}, c)
data := &database.AltSigData{
AltSigAddr: altSigAddr,
Req: reqBytes,
ReqSig: sigStr,
Res: []byte(res),
ResSig: resSig,
data := &database.AltSignAddrData{
AltSignAddr: altSignAddr,
Req: reqBytes,
ReqSig: c.GetHeader("VSP-Client-Signature"),
Resp: []byte(resp),
RespSig: respSig,
}
err = db.InsertAltSig(ticketHash, data)
err = db.InsertAltSignAddr(ticketHash, data)
if err != nil {
log.Errorf("%s: db.InsertAltSig error, failed to set alt data (ticketHash=%s): %v",
log.Errorf("%s: db.InsertAltSignAddr error (ticketHash=%s): %v",
funcName, ticketHash, err)
return
}
log.Debugf("%s: New alt sig pubkey set for ticket: (ticketHash=%s)", funcName, ticketHash)
log.Debugf("%s: New alt sign address set for ticket: (ticketHash=%s)", funcName, ticketHash)
}

View File

@ -27,8 +27,11 @@ import (
)
const (
sigCharset = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/="
// hexCharset is a list of all valid hexadecimal characters.
hexCharset = "1234567890abcdef"
// sigCharset is a list of all valid request/response signature characters
// (base64 encoding).
sigCharset = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/="
testDb = "test.db"
backupDb = "test.db-backup"
)
@ -115,19 +118,19 @@ func (n *testNode) GetRawTransaction(txHash string) (*dcrdtypes.TxRawResult, err
return nil, n.getRawTransactionErr
}
func TestSetAltSig(t *testing.T) {
func TestSetAltSignAddress(t *testing.T) {
const testAddr = "DsVoDXNQqyF3V83PJJ5zMdnB4pQuJHBAh15"
tests := []struct {
name string
dcrdClientErr bool
vspClosed bool
deformReq int
addr string
getRawTransactionErr error
canTicketNotVote bool
isExistingAltSig bool
canTicketVoteErr error
wantCode int
name string
dcrdClientErr bool
vspClosed bool
deformReq int
addr string
getRawTransactionErr error
canTicketNotVote bool
isExistingAltSignAddr bool
canTicketVoteErr error
wantCode int
}{{
name: "ok",
addr: testAddr,
@ -169,20 +172,20 @@ func TestSetAltSig(t *testing.T) {
canTicketNotVote: true,
wantCode: http.StatusBadRequest,
}, {
name: "hist at max",
addr: testAddr,
isExistingAltSig: true,
wantCode: http.StatusBadRequest,
name: "hist at max",
addr: testAddr,
isExistingAltSignAddr: true,
wantCode: http.StatusBadRequest,
}}
for _, test := range tests {
ticketHash := randString(64, hexCharset)
req := &setAltSigRequest{
Timestamp: time.Now().Unix(),
TicketHash: ticketHash,
TicketHex: randString(504, hexCharset),
ParentHex: randString(504, hexCharset),
AltSigAddress: test.addr,
req := &setAltSignAddrRequest{
Timestamp: time.Now().Unix(),
TicketHash: ticketHash,
TicketHex: randString(504, hexCharset),
ParentHex: randString(504, hexCharset),
AltSignAddress: test.addr,
}
reqSig := randString(504, hexCharset)
b, err := json.Marshal(req)
@ -190,16 +193,16 @@ func TestSetAltSig(t *testing.T) {
t.Fatal(err)
}
if test.isExistingAltSig {
data := &database.AltSigData{
AltSigAddr: test.addr,
Req: b,
ReqSig: reqSig,
Res: randBytes(1000),
ResSig: randString(96, sigCharset),
if test.isExistingAltSignAddr {
data := &database.AltSignAddrData{
AltSignAddr: test.addr,
Req: b,
ReqSig: reqSig,
Resp: randBytes(1000),
RespSig: randString(96, sigCharset),
}
if err := db.InsertAltSig(ticketHash, data); err != nil {
t.Fatalf("%q: unable to insert ticket: %v", test.name, err)
if err := db.InsertAltSignAddr(ticketHash, data); err != nil {
t.Fatalf("%q: unable to insert alt sign addr: %v", test.name, err)
}
}
@ -223,7 +226,7 @@ func TestSetAltSig(t *testing.T) {
c.Set(dcrdKey, tNode)
c.Set(dcrdErrorKey, dcrdErr)
c.Set(requestBytesKey, b[test.deformReq:])
setAltSig(c)
setAltSignAddr(c)
}
r.POST("/", handle)
@ -241,20 +244,20 @@ func TestSetAltSig(t *testing.T) {
t.Errorf("%q: expected status %d, got %d", test.name, test.wantCode, w.Code)
}
altsig, err := db.AltSigData(ticketHash)
altsig, err := db.AltSignAddrData(ticketHash)
if err != nil {
t.Fatalf("%q: unable to get alt sig data: %v", test.name, err)
t.Fatalf("%q: unable to get alt sign addr data: %v", test.name, err)
}
if test.wantCode != http.StatusOK && !test.isExistingAltSig {
if test.wantCode != http.StatusOK && !test.isExistingAltSignAddr {
if altsig != nil {
t.Fatalf("%q: expected no alt sig saved for errored state", test.name)
t.Fatalf("%q: expected no alt sign addr saved for errored state", test.name)
}
continue
}
if !bytes.Equal(b, altsig.Req) || altsig.ReqSig != reqSig {
t.Fatalf("%q: expected alt sig data different than actual", test.name)
t.Fatalf("%q: expected alt sign addr data different than actual", test.name)
}
}
}

View File

@ -43,8 +43,8 @@
<tr>
<th>Alternate Signing Address</th>
<td>
<a href="{{ addressURL .AltSig }}">
{{ .AltSig }}
<a href="{{ addressURL .AltSignAddr }}">
{{ .AltSignAddr }}
</a>
</td>
</tr>

View File

@ -1,4 +1,4 @@
// Copyright (c) 2020 The Decred developers
// Copyright (c) 2020-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
@ -72,15 +72,15 @@ type ticketStatusResponse struct {
Request []byte `json:"request"`
}
type setAltSigRequest struct {
Timestamp int64 `json:"timestamp" binding:"required"`
TicketHash string `json:"tickethash" binding:"required"`
TicketHex string `json:"tickethex" binding:"required"`
ParentHex string `json:"parenthex" binding:"required"`
AltSigAddress string `json:"altsigaddress" binding:"required"`
type setAltSignAddrRequest struct {
Timestamp int64 `json:"timestamp" binding:"required"`
TicketHash string `json:"tickethash" binding:"required"`
TicketHex string `json:"tickethex" binding:"required"`
ParentHex string `json:"parenthex" binding:"required"`
AltSignAddress string `json:"altsignaddress" binding:"required"`
}
type setAltSigResponse struct {
type setAltSignAddrResponse struct {
Timestamp int64 `json:"timestamp"`
Request []byte `json:"request"`
}

View File

@ -228,7 +228,7 @@ func router(debugMode bool, cookieSecret []byte, dcrd rpc.DcrdConnect, wallets r
api := router.Group("/api/v3")
api.GET("/vspinfo", vspInfo)
api.POST("/setaltsig", withDcrdClient(dcrd), broadcastTicket(), vspAuth(), setAltSig)
api.POST("/setaltsignaddr", withDcrdClient(dcrd), broadcastTicket(), vspAuth(), setAltSignAddr)
api.POST("/feeaddress", withDcrdClient(dcrd), broadcastTicket(), vspAuth(), feeAddress)
api.POST("/ticketstatus", withDcrdClient(dcrd), vspAuth(), ticketStatus)
api.POST("/payfee", withDcrdClient(dcrd), vspAuth(), payFee)