lbcwallet/config.go

712 lines
26 KiB
Go
Raw Normal View History

// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
2013-08-22 18:30:38 +02:00
2013-08-21 16:37:30 +02:00
package main
import (
"encoding/hex"
2013-08-21 16:37:30 +02:00
"fmt"
"net"
2013-08-21 16:37:30 +02:00
"os"
"os/user"
2013-08-21 16:37:30 +02:00
"path/filepath"
"runtime"
"sort"
2013-08-21 16:37:30 +02:00
"strings"
"time"
2014-07-03 13:45:40 +02:00
2018-05-24 04:02:33 +02:00
flags "github.com/jessevdk/go-flags"
"github.com/lbryio/lbcd/chaincfg"
btcutil "github.com/lbryio/lbcutil"
"github.com/lbryio/lbcwallet/internal/cfgutil"
"github.com/lbryio/lbcwallet/internal/legacy/keystore"
"github.com/lbryio/lbcwallet/netparams"
"github.com/lbryio/lbcwallet/wallet"
2013-08-21 16:37:30 +02:00
)
const (
defaultCAFilename = "lbcd.cert"
defaultConfigFilename = "lbcwallet.conf"
defaultLogLevel = "info"
defaultLogDirname = "logs"
defaultLogFilename = "lbcwallet.log"
defaultRPCMaxClients = 10
defaultRPCMaxWebsockets = 25
2013-08-21 16:37:30 +02:00
)
var (
lbcdDefaultCAFile = filepath.Join(btcutil.AppDataDir("lbcd", false), "rpc.cert")
defaultAppDataDir = btcutil.AppDataDir("lbcwallet", false)
defaultConfigFile = filepath.Join(defaultAppDataDir, defaultConfigFilename)
defaultRPCKeyFile = filepath.Join(defaultAppDataDir, "rpc.key")
defaultRPCCertFile = filepath.Join(defaultAppDataDir, "rpc.cert")
defaultLogDir = filepath.Join(defaultAppDataDir, defaultLogDirname)
2013-08-21 16:37:30 +02:00
)
type config struct {
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// General application behavior
ConfigFile *cfgutil.ExplicitString `short:"C" long:"configfile" description:"Path to configuration file"`
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
Create bool `long:"create" description:"Create the wallet if it does not exist"`
CreateTemp bool `long:"createtemp" description:"Create a temporary simulation wallet (pass=password) in the data directory indicated; must call with --datadir"`
AppDataDir *cfgutil.ExplicitString `short:"A" long:"appdata" description:"Application data directory for wallet config, databases and logs"`
TestNet3 bool `long:"testnet" description:"Use the test Bitcoin network (version 3) (default client port: 19244, server port: 19245)"`
Regtest bool `long:"regtest" description:"Use the regression test network (default client port: 29244, server port: 29245)"`
SimNet bool `long:"simnet" description:"Use the simulation test network (default client port: 39244, server port: 39245)"`
SigNet bool `long:"signet" description:"Use the signet test network (default client port: 49244, server port: 49245)"`
SigNetChallenge string `long:"signetchallenge" description:"Connect to a custom signet network defined by this challenge instead of using the global default signet test network -- Can be specified multiple times"`
SigNetSeedNode []string `long:"signetseednode" description:"Specify a seed node for the signet network instead of using the global default signet network seed nodes"`
NoInitialLoad bool `long:"noinitialload" description:"Defer wallet creation/opening on startup and enable loading wallets over RPC"`
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"`
LogDir string `long:"logdir" description:"Directory to log output."`
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
DBTimeout time.Duration `long:"dbtimeout" description:"The timeout value to use when opening the wallet database."`
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// Wallet options
Refactor wallet transaction creation code. This began as a change to improve the fee calculation code and evolved into a much larger refactor which improves the readability and modularity of all of the transaction creation code. Transaction fee calculations have been switched from full increments of the relay fee to a proportion based on the transaction size. This means that for a relay fee of 1e3 satoshis/kB, a 500 byte transaction is only required to pay a 5e2 satoshi fee and a 1500 byte transaction only need pay a 1.5e3 fee. The previous code would end up estimating these fees to be 1e3 and 2e3 respectively. Because the previous code would add more fee than needed in almost every case, the transaction size estimations were optimistic (best/smallest case) and signing was done in a loop where the fee was incremented by the relay fee again each time the actual size of the signed transaction rendered the fee too low. This has switched to using worst case transaction size estimates rather than best case, and signing is only performed once. Transaction input signature creation has switched from using txscript.SignatureScript to txscript.SignTxOutput. The new API is able to redeem outputs other than just P2PKH, so the previous restrictions about P2SH outputs being unspendable (except through the signrawtransaction RPC) no longer hold. Several new public packages have been added: wallet/txauthor - transaction authoring and signing wallet/txfees - fee estimations and change output inclusion wallet/txrules - simple consensus and mempool policy rule checks Along with some internal packages: wallet/internal/txsizes - transaction size estimation internal/helpers - context free convenience functions The txsizes package is internal as the estimations it provides are specific for the algorithms used by these new packages.
2016-02-28 05:30:56 +01:00
WalletPass string `long:"walletpass" default-mask:"-" description:"The public wallet password -- Only required if the wallet was created with one"`
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// RPC client options
RPCConnect string `short:"c" long:"rpcconnect" description:"Hostname/IP and port of lbcd RPC server to connect to (default localhost:9245, testnet: localhost:19245, regtest: localhost:29245 simnet: localhost:39245)"`
CAFile *cfgutil.ExplicitString `long:"cafile" description:"File containing root certificates to authenticate a TLS connections with lbcd"`
DisableClientTLS bool `long:"noclienttls" description:"Disable TLS for the RPC client -- NOTE: This is only allowed if the RPC client is connecting to localhost"`
SkipVerify bool `long:"skipverify" description:"Skip verifying TLS for the RPC client"`
LbcdUsername string `long:"lbcdusername" description:"Username for lbcd authentication"`
LbcdPassword string `long:"lbcdpassword" default-mask:"-" description:"Password for lbcd authentication"`
Proxy string `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
ProxyUser string `long:"proxyuser" description:"Username for proxy server"`
ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"`
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// SPV client options
UseSPV bool `long:"usespv" description:"Enables the experimental use of SPV rather than RPC for chain synchronization"`
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"`
MaxPeers int `long:"maxpeers" description:"Max number of inbound and outbound peers"`
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// RPC server options
//
// The legacy server is still enabled by default (and eventually will be
// replaced with the experimental server) so prepare for that change by
// renaming the struct fields (but not the configuration options).
//
// Usernames can also be used for the consensus RPC client, so they
// aren't considered legacy.
RPCCert *cfgutil.ExplicitString `long:"rpccert" description:"File containing the certificate file"`
RPCKey *cfgutil.ExplicitString `long:"rpckey" description:"File containing the certificate key"`
OneTimeTLSKey bool `long:"onetimetlskey" description:"Generate a new TLS certpair at startup, but only write the certificate to disk"`
DisableServerTLS bool `long:"noservertls" description:"Disable TLS for the RPC server -- NOTE: This is only allowed if the RPC server is bound to localhost"`
LegacyRPCListeners []string `long:"rpclisten" description:"Listen for legacy RPC connections on this interface/port (default port: 9244, testnet: 19244, regtest: 29244, simnet: 29244)"`
LegacyRPCMaxClients int64 `long:"rpcmaxclients" description:"Max number of legacy RPC clients for standard connections"`
LegacyRPCMaxWebsockets int64 `long:"rpcmaxwebsockets" description:"Max number of legacy RPC websocket connections"`
Username string `short:"u" long:"username" description:"Username for legacy RPC and lbcd authentication (if lbcdusername is unset)"`
Password string `short:"P" long:"password" default-mask:"-" description:"Password for legacy RPC and lbcd authentication (if lbcdpassword is unset)"`
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// EXPERIMENTAL RPC server options
//
// These options will change (and require changes to config files, etc.)
// when the new gRPC server is enabled.
ExperimentalRPCListeners []string `long:"experimentalrpclisten" description:"Listen for RPC connections on this interface/port"`
// Deprecated options
DataDir *cfgutil.ExplicitString `short:"b" long:"datadir" default-mask:"-" description:"DEPRECATED -- use appdata instead"`
2013-08-21 16:37:30 +02:00
}
// cleanAndExpandPath expands environement variables and leading ~ in the
// passed path, cleans the result, and returns it.
func cleanAndExpandPath(path string) string {
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style
// %VARIABLE%, but they variables can still be expanded via POSIX-style
// $VARIABLE.
path = os.ExpandEnv(path)
if !strings.HasPrefix(path, "~") {
return filepath.Clean(path)
}
// Expand initial ~ to the current user's home directory, or ~otheruser
// to otheruser's home directory. On Windows, both forward and backward
// slashes can be used.
path = path[1:]
var pathSeparators string
if runtime.GOOS == "windows" {
pathSeparators = string(os.PathSeparator) + "/"
} else {
pathSeparators = string(os.PathSeparator)
}
userName := ""
if i := strings.IndexAny(path, pathSeparators); i != -1 {
userName = path[:i]
path = path[i:]
}
homeDir := ""
var u *user.User
var err error
if userName == "" {
u, err = user.Current()
} else {
u, err = user.Lookup(userName)
}
if err == nil {
homeDir = u.HomeDir
}
// Fallback to CWD if user lookup fails or user has no home directory.
if homeDir == "" {
homeDir = "."
}
return filepath.Join(homeDir, path)
}
// validLogLevel returns whether or not logLevel is a valid debug log level.
func validLogLevel(logLevel string) bool {
switch logLevel {
case "trace":
fallthrough
case "debug":
fallthrough
case "info":
fallthrough
case "warn":
fallthrough
case "error":
fallthrough
case "critical":
return true
}
return false
}
// supportedSubsystems returns a sorted slice of the supported subsystems for
// logging purposes.
func supportedSubsystems() []string {
// Convert the subsystemLoggers map keys to a slice.
subsystems := make([]string, 0, len(subsystemLoggers))
for subsysID := range subsystemLoggers {
subsystems = append(subsystems, subsysID)
}
// Sort the subsytems for stable display.
sort.Strings(subsystems)
return subsystems
}
// parseAndSetDebugLevels attempts to parse the specified debug level and set
// the levels accordingly. An appropriate error is returned if anything is
// invalid.
func parseAndSetDebugLevels(debugLevel string) error {
// When the specified string doesn't have any delimters, treat it as
// the log level for all subsystems.
if !strings.Contains(debugLevel, ",") && !strings.Contains(debugLevel, "=") {
// Validate debug log level.
if !validLogLevel(debugLevel) {
2021-03-24 14:43:24 +01:00
str := "the specified debug level [%v] is invalid"
return fmt.Errorf(str, debugLevel)
}
// Change the logging level for all subsystems.
setLogLevels(debugLevel)
return nil
}
// Split the specified string into subsystem/level pairs while detecting
// issues and update the log levels accordingly.
for _, logLevelPair := range strings.Split(debugLevel, ",") {
if !strings.Contains(logLevelPair, "=") {
2021-03-24 14:43:24 +01:00
str := "the specified debug level contains an invalid " +
"subsystem/level pair [%v]"
return fmt.Errorf(str, logLevelPair)
}
// Extract the specified subsystem and log level.
fields := strings.Split(logLevelPair, "=")
subsysID, logLevel := fields[0], fields[1]
// Validate subsystem.
if _, exists := subsystemLoggers[subsysID]; !exists {
2021-03-24 14:43:24 +01:00
str := "the specified subsystem [%v] is invalid -- " +
"supported subsytems %v"
return fmt.Errorf(str, subsysID, supportedSubsystems())
}
// Validate log level.
if !validLogLevel(logLevel) {
2021-03-24 14:43:24 +01:00
str := "the specified debug level [%v] is invalid"
return fmt.Errorf(str, logLevel)
}
setLogLevel(subsysID, logLevel)
}
return nil
}
2013-08-21 16:37:30 +02:00
// loadConfig initializes and parses the config using a config file and command
// line options.
//
// The configuration proceeds as follows:
// 1) Start with a default config with sane settings
// 2) Pre-parse the command line to check for an alternative config file
// 3) Load configuration file overwriting defaults with any specified options
// 4) Parse CLI options and overwrite/add any specified options
//
// The above results in lbcwallet functioning properly without any config
2013-08-21 16:37:30 +02:00
// settings while still allowing the user to override settings with config files
// and command line options. Command line options always take precedence.
func loadConfig() (*config, []string, error) {
// Default config.
cfg := config{
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
DebugLevel: defaultLogLevel,
ConfigFile: cfgutil.NewExplicitString(defaultConfigFile),
AppDataDir: cfgutil.NewExplicitString(defaultAppDataDir),
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
LogDir: defaultLogDir,
WalletPass: wallet.InsecurePubPassphrase,
CAFile: cfgutil.NewExplicitString(""),
RPCKey: cfgutil.NewExplicitString(defaultRPCKeyFile),
RPCCert: cfgutil.NewExplicitString(defaultRPCCertFile),
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
LegacyRPCMaxClients: defaultRPCMaxClients,
LegacyRPCMaxWebsockets: defaultRPCMaxWebsockets,
DataDir: cfgutil.NewExplicitString(defaultAppDataDir),
UseSPV: false,
AddPeers: []string{},
ConnectPeers: []string{},
DBTimeout: wallet.DefaultDBTimeout,
2013-08-21 16:37:30 +02:00
}
// Pre-parse the command line options to see if an alternative config
// file or the version flag was specified.
preCfg := cfg
preParser := flags.NewParser(&preCfg, flags.Default)
_, err := preParser.Parse()
2013-08-21 16:37:30 +02:00
if err != nil {
if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
preParser.WriteHelp(os.Stderr)
}
return nil, nil, err
}
// Show the version and exit if the version flag was specified.
funcName := "loadConfig"
appName := filepath.Base(os.Args[0])
appName = strings.TrimSuffix(appName, filepath.Ext(appName))
usageMessage := fmt.Sprintf("Use %s -h to show usage", appName)
2013-08-21 16:37:30 +02:00
if preCfg.ShowVersion {
fmt.Println(appName, "version", version())
os.Exit(0)
}
// Load additional config from file.
var configFileError error
2013-08-21 16:37:30 +02:00
parser := flags.NewParser(&cfg, flags.Default)
configFilePath := preCfg.ConfigFile.Value
if preCfg.ConfigFile.ExplicitlySet() {
configFilePath = cleanAndExpandPath(configFilePath)
} else {
appDataDir := preCfg.AppDataDir.Value
if !preCfg.AppDataDir.ExplicitlySet() && preCfg.DataDir.ExplicitlySet() {
appDataDir = cleanAndExpandPath(preCfg.DataDir.Value)
}
if appDataDir != defaultAppDataDir {
configFilePath = filepath.Join(appDataDir, defaultConfigFilename)
}
}
err = flags.NewIniParser(parser).ParseFile(configFilePath)
2013-08-21 16:37:30 +02:00
if err != nil {
if _, ok := err.(*os.PathError); !ok {
fmt.Fprintln(os.Stderr, err)
parser.WriteHelp(os.Stderr)
return nil, nil, err
}
configFileError = err
2013-08-21 16:37:30 +02:00
}
// Parse command line options again to ensure they take precedence.
remainingArgs, err := parser.Parse()
if err != nil {
if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
parser.WriteHelp(os.Stderr)
}
return nil, nil, err
}
// Check deprecated aliases. The new options receive priority when both
// are changed from the default.
if cfg.DataDir.ExplicitlySet() {
fmt.Fprintln(os.Stderr, "datadir option has been replaced by "+
"appdata -- please update your config")
if !cfg.AppDataDir.ExplicitlySet() {
cfg.AppDataDir.Value = cfg.DataDir.Value
}
}
// If an alternate data directory was specified, and paths with defaults
// relative to the data dir are unchanged, modify each path to be
// relative to the new data dir.
if cfg.AppDataDir.ExplicitlySet() {
cfg.AppDataDir.Value = cleanAndExpandPath(cfg.AppDataDir.Value)
if !cfg.RPCKey.ExplicitlySet() {
cfg.RPCKey.Value = filepath.Join(cfg.AppDataDir.Value, "rpc.key")
}
if !cfg.RPCCert.ExplicitlySet() {
cfg.RPCCert.Value = filepath.Join(cfg.AppDataDir.Value, "rpc.cert")
}
}
// Choose the active network params based on the selected network.
// Multiple networks can't be selected simultaneously.
numNets := 0
if cfg.TestNet3 {
activeNet = &netparams.TestNet3Params
numNets++
}
if cfg.Regtest {
activeNet = &netparams.RegTestParams
numNets++
}
if cfg.SimNet {
activeNet = &netparams.SimNetParams
numNets++
}
if cfg.SigNet {
activeNet = &netparams.SigNetParams
numNets++
// Let the user overwrite the default signet parameters. The
// challenge defines the actual signet network to join and the
// seed nodes are needed for network discovery.
sigNetChallenge := chaincfg.DefaultSignetChallenge
sigNetSeeds := chaincfg.DefaultSignetDNSSeeds
if cfg.SigNetChallenge != "" {
challenge, err := hex.DecodeString(cfg.SigNetChallenge)
if err != nil {
str := "%s: Invalid signet challenge, hex " +
"decode failed: %v"
err := fmt.Errorf(str, funcName, err)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
sigNetChallenge = challenge
}
if len(cfg.SigNetSeedNode) > 0 {
sigNetSeeds = make(
[]chaincfg.DNSSeed, len(cfg.SigNetSeedNode),
)
for idx, seed := range cfg.SigNetSeedNode {
sigNetSeeds[idx] = chaincfg.DNSSeed{
Host: seed,
HasFiltering: false,
}
}
}
chainParams := chaincfg.CustomSignetParams(
sigNetChallenge, sigNetSeeds,
)
activeNet.Params = &chainParams
}
if numNets > 1 {
str := "%s: The testnet, signet and simnet params can't be " +
"used together -- choose one"
err := fmt.Errorf(str, "loadConfig")
fmt.Fprintln(os.Stderr, err)
parser.WriteHelp(os.Stderr)
return nil, nil, err
}
// Append the network type to the log directory so it is "namespaced"
// per network.
cfg.LogDir = cleanAndExpandPath(cfg.LogDir)
cfg.LogDir = filepath.Join(cfg.LogDir, activeNet.Params.Name)
// Special show command to list supported subsystems and exit.
if cfg.DebugLevel == "show" {
fmt.Println("Supported subsystems", supportedSubsystems())
os.Exit(0)
}
// Initialize log rotation. After log rotation has been initialized, the
// logger variables may be used.
initLogRotator(filepath.Join(cfg.LogDir, defaultLogFilename))
// Parse, validate, and set debug log level(s).
if err := parseAndSetDebugLevels(cfg.DebugLevel); err != nil {
err := fmt.Errorf("%s: %v", "loadConfig", err.Error())
fmt.Fprintln(os.Stderr, err)
parser.WriteHelp(os.Stderr)
return nil, nil, err
}
if cfg.CreateTemp {
errMsg := "Tried to create a temporary simulation wallet"
// Exit if you try to use a simulation wallet with a standard
// data directory.
if !(cfg.AppDataDir.ExplicitlySet() || cfg.DataDir.ExplicitlySet()) {
errMsg += ", but failed to specify data directory!"
fmt.Fprintln(os.Stderr, errMsg)
os.Exit(0)
}
// Exit if you try to use a simulation wallet on anything other than
// simnet, regtest or testnet3.
if !(cfg.Regtest || cfg.SimNet || cfg.TestNet3) {
errMsg += "for network other than simnet, regtest, or testnet3"
fmt.Fprintln(os.Stderr, errMsg)
os.Exit(0)
}
}
// Ensure the wallet exists or create it when the create flag is set.
netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params)
dbPath := filepath.Join(netDir, wallet.WalletDBName)
if cfg.CreateTemp && cfg.Create {
2021-03-24 14:43:24 +01:00
err := fmt.Errorf("the flags --create and --createtemp can not " +
"be specified together. Use --help for more information")
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
dbFileExists, err := cfgutil.FileExists(dbPath)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
2021-03-24 14:43:24 +01:00
if cfg.CreateTemp { // nolint:gocritic
tempWalletExists := false
if dbFileExists {
str := fmt.Sprintf("The wallet already exists. Loading this " +
"wallet instead.")
fmt.Fprintln(os.Stdout, str)
tempWalletExists = true
}
// Ensure the data directory for the network exists.
if err := checkCreateDir(netDir); err != nil {
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
if !tempWalletExists {
// Perform the initial wallet creation wizard.
if err := createSimulationWallet(&cfg); err != nil {
fmt.Fprintln(os.Stderr, "Unable to create wallet:", err)
return nil, nil, err
}
}
} else if cfg.Create {
// Error if the create flag is set and the wallet already
// exists.
if dbFileExists {
2021-03-24 14:43:24 +01:00
err := fmt.Errorf("the wallet database file `%v` "+
"already exists", dbPath)
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
// Ensure the data directory for the network exists.
if err := checkCreateDir(netDir); err != nil {
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
// Perform the initial wallet creation wizard.
if err := createWallet(&cfg); err != nil {
fmt.Fprintln(os.Stderr, "Unable to create wallet:", err)
return nil, nil, err
}
// Created successfully, so exit now with success.
os.Exit(0)
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
} else if !dbFileExists && !cfg.NoInitialLoad {
keystorePath := filepath.Join(netDir, keystore.Filename)
keystoreExists, err := cfgutil.FileExists(keystorePath)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
if !keystoreExists {
2021-03-24 14:43:24 +01:00
err = fmt.Errorf("the wallet does not exist, run with " +
"the --create option to initialize and create it")
} else {
2021-03-24 14:43:24 +01:00
err = fmt.Errorf("the wallet is in legacy format, run " +
"with the --create option to import it")
}
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
localhostListeners := map[string]struct{}{
"localhost": {},
"127.0.0.1": {},
"::1": {},
}
if cfg.RPCConnect == "" {
cfg.RPCConnect = net.JoinHostPort("localhost", activeNet.RPCClientPort)
}
// Add default port to connect flag if missing.
cfg.RPCConnect, err = cfgutil.NormalizeAddress(cfg.RPCConnect,
activeNet.RPCClientPort)
if err != nil {
fmt.Fprintf(os.Stderr,
"Invalid rpcconnect network address: %v\n", err)
return nil, nil, err
}
RPCHost, _, err := net.SplitHostPort(cfg.RPCConnect)
if err != nil {
return nil, nil, err
}
if cfg.DisableClientTLS {
if _, ok := localhostListeners[RPCHost]; !ok {
str := "%s: the --noclienttls option may not be used " +
"when connecting RPC to non localhost " +
"addresses: %s"
err := fmt.Errorf(str, funcName, cfg.RPCConnect)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
} else {
// If CAFile is unset, choose either the copy or local lbcd cert.
if !cfg.CAFile.ExplicitlySet() {
cfg.CAFile.Value = filepath.Join(cfg.AppDataDir.Value, defaultCAFilename)
// If the CA copy does not exist, check if we're connecting to
// a local lbcd and switch to its RPC cert if it exists.
certExists, err := cfgutil.FileExists(cfg.CAFile.Value)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
if !certExists {
if _, ok := localhostListeners[RPCHost]; ok {
lbcdCertExists, err := cfgutil.FileExists(
lbcdDefaultCAFile)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
if lbcdCertExists {
cfg.CAFile.Value = lbcdDefaultCAFile
}
}
}
}
}
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// Only set default RPC listeners when there are no listeners set for
// the experimental RPC server. This is required to prevent the old RPC
// server from sharing listen addresses, since it is impossible to
// remove defaults from go-flags slice options without assigning
// specific behavior to a particular string.
if len(cfg.ExperimentalRPCListeners) == 0 && len(cfg.LegacyRPCListeners) == 0 {
addrs, err := net.LookupHost("localhost")
if err != nil {
return nil, nil, err
}
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
cfg.LegacyRPCListeners = make([]string, 0, len(addrs))
for _, addr := range addrs {
addr = net.JoinHostPort(addr, activeNet.RPCServerPort)
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
cfg.LegacyRPCListeners = append(cfg.LegacyRPCListeners, addr)
}
}
// Add default port to all rpc listener addresses if needed and remove
// duplicate addresses.
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
cfg.LegacyRPCListeners, err = cfgutil.NormalizeAddresses(
cfg.LegacyRPCListeners, activeNet.RPCServerPort)
if err != nil {
fmt.Fprintf(os.Stderr,
"Invalid network address in legacy RPC listeners: %v\n", err)
return nil, nil, err
}
cfg.ExperimentalRPCListeners, err = cfgutil.NormalizeAddresses(
cfg.ExperimentalRPCListeners, activeNet.RPCServerPort)
if err != nil {
fmt.Fprintf(os.Stderr,
"Invalid network address in RPC listeners: %v\n", err)
return nil, nil, err
}
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
// Both RPC servers may not listen on the same interface/port.
if len(cfg.LegacyRPCListeners) > 0 && len(cfg.ExperimentalRPCListeners) > 0 {
seenAddresses := make(map[string]struct{}, len(cfg.LegacyRPCListeners))
for _, addr := range cfg.LegacyRPCListeners {
seenAddresses[addr] = struct{}{}
}
for _, addr := range cfg.ExperimentalRPCListeners {
_, seen := seenAddresses[addr]
if seen {
2021-03-24 14:43:24 +01:00
err := fmt.Errorf("address `%s` may not be "+
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
"used as a listener address for both "+
"RPC servers", addr)
fmt.Fprintln(os.Stderr, err)
return nil, nil, err
}
}
}
// Only allow server TLS to be disabled if the RPC server is bound to
// localhost addresses.
if cfg.DisableServerTLS {
Modernize the RPC server. This is a rather monolithic commit that moves the old RPC server to its own package (rpc/legacyrpc), introduces a new RPC server using gRPC (rpc/rpcserver), and provides the ability to defer wallet loading until request at a later time by an RPC (--noinitialload). The legacy RPC server remains the default for now while the new gRPC server is not enabled by default. Enabling the new server requires setting a listen address (--experimenalrpclisten). This experimental flag is used to effectively feature gate the server until it is ready to use as a default. Both RPC servers can be run at the same time, but require binding to different listen addresses. In theory, with the legacy RPC server now living in its own package it should become much easier to unit test the handlers. This will be useful for any future changes to the package, as compatibility with Core's wallet is still desired. Type safety has also been improved in the legacy RPC server. Multiple handler types are now used for methods that do and do not require the RPC client as a dependency. This can statically help prevent nil pointer dereferences, and was very useful for catching bugs during refactoring. To synchronize the wallet loading process between the main package (the default) and through the gRPC WalletLoader service (with the --noinitialload option), as well as increasing the loose coupling of packages, a new wallet.Loader type has been added. All creating and loading of existing wallets is done through a single Loader instance, and callbacks can be attached to the instance to run after the wallet has been opened. This is how the legacy RPC server is associated with a loaded wallet, even after the wallet is loaded by a gRPC method in a completely unrelated package. Documentation for the new RPC server has been added to the rpc/documentation directory. The documentation includes a specification for the new RPC API, addresses how to make changes to the server implementation, and provides short example clients in several different languages. Some of the new RPC methods are not implementated exactly as described by the specification. These are considered bugs with the implementation, not the spec. Known bugs are commented as such.
2015-06-01 21:57:50 +02:00
allListeners := append(cfg.LegacyRPCListeners,
cfg.ExperimentalRPCListeners...)
for _, addr := range allListeners {
host, _, err := net.SplitHostPort(addr)
if err != nil {
str := "%s: RPC listen interface '%s' is " +
"invalid: %v"
err := fmt.Errorf(str, funcName, addr, err)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
if _, ok := localhostListeners[host]; !ok {
str := "%s: the --noservertls option may not be used " +
"when binding RPC to non localhost " +
"addresses: %s"
err := fmt.Errorf(str, funcName, addr)
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err
}
}
}
// Expand environment variable and leading ~ for filepaths.
cfg.CAFile.Value = cleanAndExpandPath(cfg.CAFile.Value)
cfg.RPCCert.Value = cleanAndExpandPath(cfg.RPCCert.Value)
cfg.RPCKey.Value = cleanAndExpandPath(cfg.RPCKey.Value)
// If the lbcd username or password are unset, use the same auth as for
// the client. The two settings were previously shared for lbcd and
// client auth, so this avoids breaking backwards compatibility while
// allowing users to use different auth settings for lbcd and wallet.
if cfg.LbcdUsername == "" {
cfg.LbcdUsername = cfg.Username
}
if cfg.LbcdPassword == "" {
cfg.LbcdPassword = cfg.Password
}
// Warn about missing config file after the final command line parse
// succeeds. This prevents the warning on help messages and invalid
// options.
if configFileError != nil {
log.Warnf("%v", configFileError)
}
2013-08-21 16:37:30 +02:00
return &cfg, remainingArgs, nil
}