Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine concepts: xpub and last used index #479

Merged
merged 3 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 0 additions & 41 deletions database/addressindex.go

This file was deleted.

26 changes: 5 additions & 21 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ func CreateNew(dbFile, feeXPub string) error {
}

// Store fee xpub.
err = vspBkt.Put(feeXPubK, []byte(feeXPub))
xpub := FeeXPub{
Key: feeXPub,
LastUsedIdx: 0,
}
err = insertFeeXPub(tx, xpub)
if err != nil {
return err
}
Expand Down Expand Up @@ -311,26 +315,6 @@ func (vdb *VspDatabase) KeyPair() (ed25519.PrivateKey, ed25519.PublicKey, error)
return signKey, pubKey, err
}

// FeeXPub retrieves the extended pubkey used for generating fee addresses
// from the database.
func (vdb *VspDatabase) FeeXPub() (string, error) {
var feeXPub string
err := vdb.db.View(func(tx *bolt.Tx) error {
vspBkt := tx.Bucket(vspBktK)

xpubBytes := vspBkt.Get(feeXPubK)
if xpubBytes == nil {
return nil
}

feeXPub = string(xpubBytes)

return nil
})

return feeXPub, err
}

// CookieSecret retrieves the generated cookie store secret key from the
// database.
func (vdb *VspDatabase) CookieSecret() ([]byte, error) {
Expand Down
14 changes: 2 additions & 12 deletions database/database_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2022 The Decred developers
// Copyright (c) 2020-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -77,7 +77,7 @@ func TestDatabase(t *testing.T) {
"testTicketFeeExpired": testTicketFeeExpired,
"testFilterTickets": testFilterTickets,
"testCountTickets": testCountTickets,
"testAddressIndex": testAddressIndex,
"testFeeXPub": testFeeXPub,
"testDeleteTicket": testDeleteTicket,
"testVoteChangeRecords": testVoteChangeRecords,
"testHTTPBackup": testHTTPBackup,
Expand Down Expand Up @@ -134,16 +134,6 @@ func testCreateNew(t *testing.T) {
if len(secret) != 32 {
t.Fatalf("expected a 32 byte cookie secret, got %d bytes", len(secret))
}

// A newly created DB should store the fee xpub it was initialized with.
retrievedXPub, err := db.FeeXPub()
if err != nil {
t.Fatalf("error getting fee xpub: %v", err)
}

if retrievedXPub != feeXPub {
t.Fatalf("expected fee xpub %v, got %v", feeXPub, retrievedXPub)
}
}

func testHTTPBackup(t *testing.T) {
Expand Down
75 changes: 75 additions & 0 deletions database/feexpub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2020-2024 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 (
"fmt"

bolt "go.etcd.io/bbolt"
)

type FeeXPub struct {
Key string
LastUsedIdx uint32
}

// insertFeeXPub stores the provided pubkey in the database, regardless of
// whether a value pre-exists.
func insertFeeXPub(tx *bolt.Tx, xpub FeeXPub) error {
vspBkt := tx.Bucket(vspBktK)

err := vspBkt.Put(feeXPubK, []byte(xpub.Key))
if err != nil {
return err
}

return vspBkt.Put(lastAddressIndexK, uint32ToBytes(xpub.LastUsedIdx))
}

// FeeXPub retrieves the extended pubkey used for generating fee addresses
// from the database.
func (vdb *VspDatabase) FeeXPub() (FeeXPub, error) {
var feeXPub string
var idx uint32
err := vdb.db.View(func(tx *bolt.Tx) error {
vspBkt := tx.Bucket(vspBktK)

// Get the key.
xpubBytes := vspBkt.Get(feeXPubK)
if xpubBytes == nil {
return nil
}
feeXPub = string(xpubBytes)

// Get the last used address index.
idxBytes := vspBkt.Get(lastAddressIndexK)
if idxBytes == nil {
return nil
}
idx = bytesToUint32(idxBytes)

return nil
})
if err != nil {
return FeeXPub{}, fmt.Errorf("could not retrieve fee xpub: %w", err)
}

return FeeXPub{Key: feeXPub, LastUsedIdx: idx}, nil
}

// SetLastAddressIndex updates the last index used to derive a new fee address
// from the fee xpub key.
func (vdb *VspDatabase) SetLastAddressIndex(idx uint32) error {
current, err := vdb.FeeXPub()
if err != nil {
return err
}

current.LastUsedIdx = idx

return vdb.db.Update(func(tx *bolt.Tx) error {
return insertFeeXPub(tx, current)
})
}
25 changes: 15 additions & 10 deletions database/addressindex_test.go → database/feexpub_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020 The Decred developers
// Copyright (c) 2020-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand All @@ -8,30 +8,35 @@ import (
"testing"
)

func testAddressIndex(t *testing.T) {

// Getting index before it has been set should return 0.
idx, err := db.GetLastAddressIndex()
func testFeeXPub(t *testing.T) {
// A newly created DB should store the fee xpub it was initialized with, and
// the last used index should be 0.
retrievedXPub, err := db.FeeXPub()
if err != nil {
t.Fatalf("error getting address index: %v", err)
t.Fatalf("error getting fee xpub: %v", err)
}
if idx != 0 {

if retrievedXPub.Key != feeXPub {
t.Fatalf("expected fee xpub %v, got %v", feeXPub, retrievedXPub.Key)
}

if retrievedXPub.LastUsedIdx != 0 {
t.Fatalf("retrieved addr index value didnt match expected")
}

// Update address index.
idx = uint32(99)
idx := uint32(99)
err = db.SetLastAddressIndex(idx)
if err != nil {
t.Fatalf("error setting address index: %v", err)
}

// Check for updated value.
retrievedIdx, err := db.GetLastAddressIndex()
retrievedXPub, err = db.FeeXPub()
if err != nil {
t.Fatalf("error getting address index: %v", err)
}
if idx != retrievedIdx {
if idx != retrievedXPub.LastUsedIdx {
t.Fatalf("retrieved addr index value didnt match expected")
}
}
9 changes: 5 additions & 4 deletions internal/webapi/addressgenerator.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2022 The Decred developers
// Copyright (c) 2020-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand All @@ -11,6 +11,7 @@ import (
"github.com/decred/dcrd/hdkeychain/v3"
"github.com/decred/dcrd/txscript/v4/stdaddr"
"github.com/decred/slog"
"github.com/decred/vspd/database"
)

type addressGenerator struct {
Expand All @@ -20,8 +21,8 @@ type addressGenerator struct {
log slog.Logger
}

func newAddressGenerator(xPub string, netParams *chaincfg.Params, lastUsedIdx uint32, log slog.Logger) (*addressGenerator, error) {
xPubKey, err := hdkeychain.NewKeyFromString(xPub, netParams)
func newAddressGenerator(xPub database.FeeXPub, netParams *chaincfg.Params, log slog.Logger) (*addressGenerator, error) {
xPubKey, err := hdkeychain.NewKeyFromString(xPub.Key, netParams)
if err != nil {
return nil, err
}
Expand All @@ -39,7 +40,7 @@ func newAddressGenerator(xPub string, netParams *chaincfg.Params, lastUsedIdx ui
return &addressGenerator{
external: external,
netParams: netParams,
lastUsedIndex: lastUsedIdx,
lastUsedIndex: xPub.LastUsedIdx,
log: log,
}, nil
}
Expand Down
14 changes: 6 additions & 8 deletions internal/webapi/webapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,15 @@ func New(vdb *database.VspDatabase, log slog.Logger, dcrd rpc.DcrdConnect,
log.Errorf("Could not initialize VSP stats cache: %v", err)
}

// Get the last used address index and the feeXpub from the database, and
// use them to initialize the address generator.
idx, err := vdb.GetLastAddressIndex()
if err != nil {
return nil, fmt.Errorf("db.GetLastAddressIndex error: %w", err)
}
// Get the current fee xpub details from the database.
feeXPub, err := vdb.FeeXPub()
if err != nil {
return nil, fmt.Errorf("db.GetFeeXPub error: %w", err)
return nil, fmt.Errorf("db.FeeXPub error: %w", err)
}
addrGen, err := newAddressGenerator(feeXPub, cfg.Network.Params, idx, log)

// Use the retrieved pubkey to initialize an address generator which can
// later be used to derive new fee addresses.
addrGen, err := newAddressGenerator(feeXPub, cfg.Network.Params, log)
if err != nil {
return nil, fmt.Errorf("failed to initialize fee address generator: %w", err)
}
Expand Down
Loading