vspadmin: New binary to create empty databases.
vspadmin is a new binary which implements one-off admin tasks which are necessarily interactive and thus do not fit neatly into the long-lived vspd binary. The first behaviour added to vspadmin is the ability to create a new vspd database. This behaviour is removed from vspd with the associated config option deprecated. Documentation and scripts updated to reflect the change.
This commit is contained in:
parent
0633260a3c
commit
997205ed95
30
cmd/vspadmin/README.md
Normal file
30
cmd/vspadmin/README.md
Normal file
@ -0,0 +1,30 @@
|
||||
# vspadmin
|
||||
|
||||
vspadmin is a tool to perform various VSP administration tasks.
|
||||
|
||||
## Usage
|
||||
|
||||
```no-highlight
|
||||
vspadmin [OPTIONS] COMMAND
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```no-highlight
|
||||
--homedir= Path to application home directory. (default: /home/user/.vspd)
|
||||
--network=[mainnet|testnet|simnet] Decred network to use. (default: mainnet)
|
||||
-h, --help Show help message
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### `createdatabase`
|
||||
|
||||
Creates a new database for a new deployment of vspd. Accepts the xpub key to be
|
||||
used for collecting fees as a parameter.
|
||||
|
||||
Example:
|
||||
|
||||
```no-highlight
|
||||
go run ./cmd/vspadmin createdatabase <xpub>
|
||||
```
|
||||
130
cmd/vspadmin/main.go
Normal file
130
cmd/vspadmin/main.go
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2024 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/decred/dcrd/dcrutil/v4"
|
||||
"github.com/decred/dcrd/hdkeychain/v3"
|
||||
"github.com/decred/vspd/database"
|
||||
"github.com/decred/vspd/internal/config"
|
||||
"github.com/jessevdk/go-flags"
|
||||
)
|
||||
|
||||
const (
|
||||
dbFilename = "vspd.db"
|
||||
)
|
||||
|
||||
type conf struct {
|
||||
HomeDir string `long:"homedir" description:"Path to application home directory."`
|
||||
Network string `long:"network" description:"Decred network to use." choice:"mainnet" choice:"testnet" choice:"simnet"`
|
||||
}
|
||||
|
||||
var defaultConf = conf{
|
||||
HomeDir: dcrutil.AppDataDir("vspd", false),
|
||||
Network: "mainnet",
|
||||
}
|
||||
|
||||
func log(format string, a ...any) {
|
||||
fmt.Printf(format+"\n", a...)
|
||||
}
|
||||
|
||||
// fileExists reports whether the named file or directory exists.
|
||||
func fileExists(name string) bool {
|
||||
if _, err := os.Stat(name); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func createDatabase(homeDir string, feeXPub string, network *config.Network) error {
|
||||
dataDir := filepath.Join(homeDir, "data", network.Name)
|
||||
dbFile := filepath.Join(dataDir, dbFilename)
|
||||
|
||||
// Return error if database already exists.
|
||||
if fileExists(dbFile) {
|
||||
return fmt.Errorf("%s database already exists in %s", network.Name, dataDir)
|
||||
}
|
||||
|
||||
// Ensure provided xpub is a valid key for the selected network.
|
||||
_, err := hdkeychain.NewKeyFromString(feeXPub, network.Params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse feexpub: %w", err)
|
||||
}
|
||||
|
||||
// Ensure the data directory exists.
|
||||
err = os.MkdirAll(dataDir, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create data directory: %w", err)
|
||||
}
|
||||
|
||||
// Create new database.
|
||||
err = database.CreateNew(dbFile, feeXPub)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating db file %s: %w", dbFile, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// run is the real main function for vspadmin. It is necessary to work around
|
||||
// the fact that deferred functions do not run when os.Exit() is called.
|
||||
func run() int {
|
||||
cfg := defaultConf
|
||||
|
||||
// If command line options are requesting help, write it to stdout and exit.
|
||||
if config.WriteHelp(&cfg) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Parse command line options.
|
||||
remainingArgs, err := flags.Parse(&cfg)
|
||||
if err != nil {
|
||||
// Don't need to log the error, flags lib has already done it.
|
||||
return 1
|
||||
}
|
||||
|
||||
network, err := config.NetworkFromName(cfg.Network)
|
||||
if err != nil {
|
||||
log("%v", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
if len(remainingArgs) < 1 {
|
||||
log("No command specified")
|
||||
return 1
|
||||
}
|
||||
|
||||
switch remainingArgs[0] {
|
||||
case "createdatabase":
|
||||
if len(remainingArgs) != 2 {
|
||||
log("createdatabase has one required argument, fee xpub")
|
||||
return 1
|
||||
}
|
||||
|
||||
feeXPub := remainingArgs[1]
|
||||
|
||||
err = createDatabase(cfg.HomeDir, feeXPub, network)
|
||||
if err != nil {
|
||||
log("createdatabase failed: %v", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
log("New %s vspd database created in %s", network.Name, cfg.HomeDir)
|
||||
|
||||
default:
|
||||
log("%q is not a valid command", remainingArgs[0])
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
os.Exit(run())
|
||||
}
|
||||
@ -102,6 +102,12 @@ func run() int {
|
||||
log.Warnf("")
|
||||
}
|
||||
|
||||
if cfg.FeeXPub != "" {
|
||||
log.Warnf("")
|
||||
log.Warnf("\tWARNING: Config --feexpub is set. This behavior has been moved into vspadmin and will be removed from vspd in a future release")
|
||||
log.Warnf("")
|
||||
}
|
||||
|
||||
// Open database.
|
||||
db, err := database.Open(cfg.DatabaseFile(), makeLogger(" DB"), maxVoteChangeRecords)
|
||||
if err != nil {
|
||||
|
||||
@ -96,15 +96,14 @@ vspd. **Do not run a voting wallet on your webserver.**
|
||||
config file to set your dcrd and dcrwallet connection details, and any other
|
||||
required customization.
|
||||
|
||||
1. A vspd database must be initialized before vpsd can be started. To do this,
|
||||
provide vspd with the xpub key it should use for collecting fees:
|
||||
1. Use [vspadmin](./cmd/vspadmin) to initialize a vpsd database. The xpub key to
|
||||
be used for collecting fees must be passed in as an argument.
|
||||
|
||||
```no-highlight
|
||||
$ vspd --feexpub=tpubVppjaMjp8GEW...
|
||||
$ go run ./cmd/vspadmin createdatabase tpubVppjaMjp8GEW...
|
||||
```
|
||||
|
||||
1. Once the database is initialized, vspd can be started for normal operation by
|
||||
running it without the `--feexpub` flag.
|
||||
1. Once the database is initialized, vspd can be started for normal operation.
|
||||
|
||||
1. Configure nginx with SSL and set up reverse proxy to forward requests to the
|
||||
vspd process. nginx must also set the `X-Forwarded-For` header to make vspd
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (c) 2020-2023 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.
|
||||
#
|
||||
@ -170,7 +170,7 @@ EOF
|
||||
tmux new-window -t $TMUX_SESSION -n "vspd"
|
||||
|
||||
echo "Creating vspd database"
|
||||
tmux send-keys "vspd --homedir=${HARNESS_ROOT}/vspd --feexpub=${VSPD_FEE_XPUB}" C-m
|
||||
tmux send-keys "go run ./cmd/vspadmin --homedir=${HARNESS_ROOT}/vspd --network=testnet createdatabase ${VSPD_FEE_XPUB}" C-m
|
||||
sleep 3 # wait for database creation and ensure dcrwallet rpc listeners are started
|
||||
echo "Starting vspd"
|
||||
tmux send-keys "vspd --homedir=${HARNESS_ROOT}/vspd" C-m
|
||||
|
||||
@ -17,8 +17,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/decred/dcrd/dcrutil/v4"
|
||||
"github.com/decred/dcrd/hdkeychain/v3"
|
||||
"github.com/decred/vspd/database"
|
||||
"github.com/decred/vspd/internal/config"
|
||||
"github.com/decred/vspd/internal/version"
|
||||
flags "github.com/jessevdk/go-flags"
|
||||
@ -55,12 +53,11 @@ type Config struct {
|
||||
|
||||
// The following flags should be set on CLI only, not via config file.
|
||||
ShowVersion bool `long:"version" no-ini:"true" description:"Display version information and exit."`
|
||||
FeeXPub string `long:"feexpub" no-ini:"true" description:"Cold wallet xpub used for collecting fees. Should be provided once to initialize a vspd database."`
|
||||
FeeXPub string `long:"feexpub" no-ini:"true" description:"DEPRECATED: This behavior has been moved into vspadmin and will be removed from vspd in a future version of the software."`
|
||||
HomeDir string `long:"homedir" no-ini:"true" description:"Path to application home directory. Used for storing VSP database and logs."`
|
||||
ConfigFile string `long:"configfile" no-ini:"true" description:"DEPRECATED: This behavior is no longer available and this option will be removed in a future version of the software."`
|
||||
|
||||
// The following fields are derived from the above fields by LoadConfig().
|
||||
dataDir string
|
||||
network *config.Network
|
||||
dcrdDetails *DcrdDetails
|
||||
walletDetails *WalletDetails
|
||||
@ -89,7 +86,7 @@ func (cfg *Config) LogDir() string {
|
||||
}
|
||||
|
||||
func (cfg *Config) DatabaseFile() string {
|
||||
return filepath.Join(cfg.dataDir, dbFilename)
|
||||
return filepath.Join(cfg.HomeDir, "data", cfg.network.Name, dbFilename)
|
||||
}
|
||||
|
||||
func (cfg *Config) DcrdDetails() *DcrdDetails {
|
||||
@ -420,45 +417,10 @@ func LoadConfig() (*Config, error) {
|
||||
Certs: walletCerts,
|
||||
}
|
||||
|
||||
// Create the data directory.
|
||||
cfg.dataDir = filepath.Join(cfg.HomeDir, "data", cfg.network.Name)
|
||||
err = os.MkdirAll(cfg.dataDir, 0700)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create data directory: %w", err)
|
||||
}
|
||||
|
||||
dbPath := cfg.DatabaseFile()
|
||||
|
||||
// If xpub has been provided, create a new database and exit.
|
||||
if cfg.FeeXPub != "" {
|
||||
// If database already exists, return error.
|
||||
if fileExists(dbPath) {
|
||||
return nil, fmt.Errorf("database already initialized at %s, "+
|
||||
"--feexpub option is not needed", dbPath)
|
||||
}
|
||||
|
||||
// Ensure provided value is a valid key for the selected network.
|
||||
_, err = hdkeychain.NewKeyFromString(cfg.FeeXPub, cfg.network.Params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse feexpub: %w", err)
|
||||
}
|
||||
|
||||
// Create new database.
|
||||
fmt.Printf("Initializing new database at %s\n", dbPath)
|
||||
err = database.CreateNew(dbPath, cfg.FeeXPub)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating db file %s: %w", dbPath, err)
|
||||
}
|
||||
|
||||
// Exit with success
|
||||
fmt.Printf("Database initialized\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// If database does not exist, return error.
|
||||
if !fileExists(dbPath) {
|
||||
return nil, fmt.Errorf("no database exists in %s. Run vspd with the"+
|
||||
" --feexpub option to initialize one", cfg.dataDir)
|
||||
if !fileExists(cfg.DatabaseFile()) {
|
||||
return nil, fmt.Errorf("no %s database exists in %s. A new database can"+
|
||||
" be created with vspadmin", cfg.network.Name, cfg.HomeDir)
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user