lntest: expose configuration of harness node

When using the lntest package for itests in external projects, it
is necessary to access a harness node's configuration, for example
to get its data directory on disk. This commit exports that
configuration.
This commit is contained in:
Oliver Gugger 2019-12-17 10:48:17 +01:00
parent 6fef37cc06
commit b762d441cf
No known key found for this signature in database
GPG Key ID: 8E4256593F177720
2 changed files with 46 additions and 46 deletions

@ -343,7 +343,7 @@ func (n *NetworkHarness) RestoreNodeWithSeed(name string, extraArgs []string,
func (n *NetworkHarness) newNode(name string, extraArgs []string, func (n *NetworkHarness) newNode(name string, extraArgs []string,
hasSeed bool, password []byte) (*HarnessNode, error) { hasSeed bool, password []byte) (*HarnessNode, error) {
node, err := newNode(nodeConfig{ node, err := newNode(NodeConfig{
Name: name, Name: name,
HasSeed: hasSeed, HasSeed: hasSeed,
Password: password, Password: password,
@ -368,7 +368,7 @@ func (n *NetworkHarness) newNode(name string, extraArgs []string,
// If this node is to have a seed, it will need to be unlocked or // If this node is to have a seed, it will need to be unlocked or
// initialized via rpc. Delay registering it with the network until it // initialized via rpc. Delay registering it with the network until it
// can be driven via an unlocked rpc connection. // can be driven via an unlocked rpc connection.
if node.cfg.HasSeed { if node.Cfg.HasSeed {
return node, nil return node, nil
} }
@ -431,7 +431,7 @@ func (n *NetworkHarness) EnsureConnected(ctx context.Context, a, b *HarnessNode)
req := &lnrpc.ConnectPeerRequest{ req := &lnrpc.ConnectPeerRequest{
Addr: &lnrpc.LightningAddress{ Addr: &lnrpc.LightningAddress{
Pubkey: bInfo.IdentityPubkey, Pubkey: bInfo.IdentityPubkey,
Host: b.cfg.P2PAddr(), Host: b.Cfg.P2PAddr(),
}, },
} }
@ -536,7 +536,7 @@ func (n *NetworkHarness) ConnectNodes(ctx context.Context, a, b *HarnessNode) er
req := &lnrpc.ConnectPeerRequest{ req := &lnrpc.ConnectPeerRequest{
Addr: &lnrpc.LightningAddress{ Addr: &lnrpc.LightningAddress{
Pubkey: bobInfo.IdentityPubkey, Pubkey: bobInfo.IdentityPubkey,
Host: b.cfg.P2PAddr(), Host: b.Cfg.P2PAddr(),
}, },
} }
@ -618,14 +618,14 @@ func (n *NetworkHarness) RestartNode(node *HarnessNode, callback func() error,
// If the node doesn't have a password set, then we can exit here as we // If the node doesn't have a password set, then we can exit here as we
// don't need to unlock it. // don't need to unlock it.
if len(node.cfg.Password) == 0 { if len(node.Cfg.Password) == 0 {
return nil return nil
} }
// Otherwise, we'll unlock the wallet, then complete the final steps // Otherwise, we'll unlock the wallet, then complete the final steps
// for the node initialization process. // for the node initialization process.
unlockReq := &lnrpc.UnlockWalletRequest{ unlockReq := &lnrpc.UnlockWalletRequest{
WalletPassword: node.cfg.Password, WalletPassword: node.Cfg.Password,
} }
if len(chanBackups) != 0 { if len(chanBackups) != 0 {
unlockReq.ChannelBackups = chanBackups[0] unlockReq.ChannelBackups = chanBackups[0]
@ -687,13 +687,13 @@ func saveProfilesPage(node *HarnessNode) error {
resp, err := http.Get( resp, err := http.Get(
fmt.Sprintf( fmt.Sprintf(
"http://localhost:%d/debug/pprof/goroutine?debug=1", "http://localhost:%d/debug/pprof/goroutine?debug=1",
node.cfg.ProfilePort, node.Cfg.ProfilePort,
), ),
) )
if err != nil { if err != nil {
return fmt.Errorf("Failed to get profile page "+ return fmt.Errorf("Failed to get profile page "+
"(node_id=%d, name=%s): %v\n", "(node_id=%d, name=%s): %v\n",
node.NodeID, node.cfg.Name, err) node.NodeID, node.Cfg.Name, err)
} }
defer resp.Body.Close() defer resp.Body.Close()
@ -701,11 +701,11 @@ func saveProfilesPage(node *HarnessNode) error {
if err != nil { if err != nil {
return fmt.Errorf("Failed to read profile page "+ return fmt.Errorf("Failed to read profile page "+
"(node_id=%d, name=%s): %v\n", "(node_id=%d, name=%s): %v\n",
node.NodeID, node.cfg.Name, err) node.NodeID, node.Cfg.Name, err)
} }
fileName := fmt.Sprintf( fileName := fmt.Sprintf(
"pprof-%d-%s-%s.log", node.NodeID, node.cfg.Name, "pprof-%d-%s-%s.log", node.NodeID, node.Cfg.Name,
hex.EncodeToString(node.PubKey[:logPubKeyBytes]), hex.EncodeToString(node.PubKey[:logPubKeyBytes]),
) )
@ -713,7 +713,7 @@ func saveProfilesPage(node *HarnessNode) error {
if err != nil { if err != nil {
return fmt.Errorf("Failed to create file for profile page "+ return fmt.Errorf("Failed to create file for profile page "+
"(node_id=%d, name=%s): %v\n", "(node_id=%d, name=%s): %v\n",
node.NodeID, node.cfg.Name, err) node.NodeID, node.Cfg.Name, err)
} }
defer logFile.Close() defer logFile.Close()
@ -721,7 +721,7 @@ func saveProfilesPage(node *HarnessNode) error {
if err != nil { if err != nil {
return fmt.Errorf("Failed to save profile page "+ return fmt.Errorf("Failed to save profile page "+
"(node_id=%d, name=%s): %v\n", "(node_id=%d, name=%s): %v\n",
node.NodeID, node.cfg.Name, err) node.NodeID, node.Cfg.Name, err)
} }
return nil return nil
} }
@ -1222,7 +1222,7 @@ func (n *NetworkHarness) AssertChannelExists(ctx context.Context,
// Logs from lightning node being generated with delay - you should // Logs from lightning node being generated with delay - you should
// add time.Sleep() in order to get all logs. // add time.Sleep() in order to get all logs.
func (n *NetworkHarness) DumpLogs(node *HarnessNode) (string, error) { func (n *NetworkHarness) DumpLogs(node *HarnessNode) (string, error) {
logFile := fmt.Sprintf("%v/simnet/lnd.log", node.cfg.LogDir) logFile := fmt.Sprintf("%v/simnet/lnd.log", node.Cfg.LogDir)
buf, err := ioutil.ReadFile(logFile) buf, err := ioutil.ReadFile(logFile)
if err != nil { if err != nil {
@ -1319,7 +1319,7 @@ func (n *NetworkHarness) sendCoins(ctx context.Context, amt btcutil.Amount,
err = wait.NoError(func() error { err = wait.NoError(func() error {
// Since neutrino doesn't support unconfirmed outputs, skip // Since neutrino doesn't support unconfirmed outputs, skip
// this check. // this check.
if target.cfg.BackendCfg.Name() == "neutrino" { if target.Cfg.BackendCfg.Name() == "neutrino" {
return nil return nil
} }

@ -130,7 +130,7 @@ type BackendConfig interface {
Name() string Name() string
} }
type nodeConfig struct { type NodeConfig struct {
Name string Name string
BackendCfg BackendConfig BackendCfg BackendConfig
NetParams *chaincfg.Params NetParams *chaincfg.Params
@ -154,24 +154,24 @@ type nodeConfig struct {
ProfilePort int ProfilePort int
} }
func (cfg nodeConfig) P2PAddr() string { func (cfg NodeConfig) P2PAddr() string {
return net.JoinHostPort("127.0.0.1", strconv.Itoa(cfg.P2PPort)) return net.JoinHostPort("127.0.0.1", strconv.Itoa(cfg.P2PPort))
} }
func (cfg nodeConfig) RPCAddr() string { func (cfg NodeConfig) RPCAddr() string {
return net.JoinHostPort("127.0.0.1", strconv.Itoa(cfg.RPCPort)) return net.JoinHostPort("127.0.0.1", strconv.Itoa(cfg.RPCPort))
} }
func (cfg nodeConfig) RESTAddr() string { func (cfg NodeConfig) RESTAddr() string {
return net.JoinHostPort("127.0.0.1", strconv.Itoa(cfg.RESTPort)) return net.JoinHostPort("127.0.0.1", strconv.Itoa(cfg.RESTPort))
} }
func (cfg nodeConfig) DBPath() string { func (cfg NodeConfig) DBPath() string {
return filepath.Join(cfg.DataDir, "graph", return filepath.Join(cfg.DataDir, "graph",
fmt.Sprintf("%v/channel.db", cfg.NetParams.Name)) fmt.Sprintf("%v/channel.db", cfg.NetParams.Name))
} }
func (cfg nodeConfig) ChanBackupPath() string { func (cfg NodeConfig) ChanBackupPath() string {
return filepath.Join( return filepath.Join(
cfg.DataDir, "chain", "bitcoin", cfg.DataDir, "chain", "bitcoin",
fmt.Sprintf( fmt.Sprintf(
@ -183,7 +183,7 @@ func (cfg nodeConfig) ChanBackupPath() string {
// genArgs generates a slice of command line arguments from the lightning node // genArgs generates a slice of command line arguments from the lightning node
// config struct. // config struct.
func (cfg nodeConfig) genArgs() []string { func (cfg NodeConfig) genArgs() []string {
var args []string var args []string
switch cfg.NetParams { switch cfg.NetParams {
@ -232,7 +232,7 @@ func (cfg nodeConfig) genArgs() []string {
// harness. Each HarnessNode instance also fully embeds an RPC client in // harness. Each HarnessNode instance also fully embeds an RPC client in
// order to pragmatically drive the node. // order to pragmatically drive the node.
type HarnessNode struct { type HarnessNode struct {
cfg *nodeConfig Cfg *NodeConfig
// NodeID is a unique identifier for the node within a NetworkHarness. // NodeID is a unique identifier for the node within a NetworkHarness.
NodeID int NodeID int
@ -286,7 +286,7 @@ var _ lnrpc.WalletUnlockerClient = (*HarnessNode)(nil)
var _ invoicesrpc.InvoicesClient = (*HarnessNode)(nil) var _ invoicesrpc.InvoicesClient = (*HarnessNode)(nil)
// newNode creates a new test lightning node instance from the passed config. // newNode creates a new test lightning node instance from the passed config.
func newNode(cfg nodeConfig) (*HarnessNode, error) { func newNode(cfg NodeConfig) (*HarnessNode, error) {
if cfg.BaseDir == "" { if cfg.BaseDir == "" {
var err error var err error
cfg.BaseDir, err = ioutil.TempDir("", "lndtest-node") cfg.BaseDir, err = ioutil.TempDir("", "lndtest-node")
@ -310,7 +310,7 @@ func newNode(cfg nodeConfig) (*HarnessNode, error) {
numActiveNodesMtx.Unlock() numActiveNodesMtx.Unlock()
return &HarnessNode{ return &HarnessNode{
cfg: &cfg, Cfg: &cfg,
NodeID: nodeNum, NodeID: nodeNum,
chanWatchRequests: make(chan *chanWatchRequest), chanWatchRequests: make(chan *chanWatchRequest),
openChans: make(map[wire.OutPoint]int), openChans: make(map[wire.OutPoint]int),
@ -323,44 +323,44 @@ func newNode(cfg nodeConfig) (*HarnessNode, error) {
// DBPath returns the filepath to the channeldb database file for this node. // DBPath returns the filepath to the channeldb database file for this node.
func (hn *HarnessNode) DBPath() string { func (hn *HarnessNode) DBPath() string {
return hn.cfg.DBPath() return hn.Cfg.DBPath()
} }
// Name returns the name of this node set during initialization. // Name returns the name of this node set during initialization.
func (hn *HarnessNode) Name() string { func (hn *HarnessNode) Name() string {
return hn.cfg.Name return hn.Cfg.Name
} }
// TLSCertStr returns the path where the TLS certificate is stored. // TLSCertStr returns the path where the TLS certificate is stored.
func (hn *HarnessNode) TLSCertStr() string { func (hn *HarnessNode) TLSCertStr() string {
return hn.cfg.TLSCertPath return hn.Cfg.TLSCertPath
} }
// TLSKeyStr returns the path where the TLS key is stored. // TLSKeyStr returns the path where the TLS key is stored.
func (hn *HarnessNode) TLSKeyStr() string { func (hn *HarnessNode) TLSKeyStr() string {
return hn.cfg.TLSKeyPath return hn.Cfg.TLSKeyPath
} }
// ChanBackupPath returns the fielpath to the on-disk channels.backup file for // ChanBackupPath returns the fielpath to the on-disk channels.backup file for
// this node. // this node.
func (hn *HarnessNode) ChanBackupPath() string { func (hn *HarnessNode) ChanBackupPath() string {
return hn.cfg.ChanBackupPath() return hn.Cfg.ChanBackupPath()
} }
// AdminMacPath returns the filepath to the admin.macaroon file for this node. // AdminMacPath returns the filepath to the admin.macaroon file for this node.
func (hn *HarnessNode) AdminMacPath() string { func (hn *HarnessNode) AdminMacPath() string {
return hn.cfg.AdminMacPath return hn.Cfg.AdminMacPath
} }
// ReadMacPath returns the filepath to the readonly.macaroon file for this node. // ReadMacPath returns the filepath to the readonly.macaroon file for this node.
func (hn *HarnessNode) ReadMacPath() string { func (hn *HarnessNode) ReadMacPath() string {
return hn.cfg.ReadMacPath return hn.Cfg.ReadMacPath
} }
// InvoiceMacPath returns the filepath to the invoice.macaroon file for this // InvoiceMacPath returns the filepath to the invoice.macaroon file for this
// node. // node.
func (hn *HarnessNode) InvoiceMacPath() string { func (hn *HarnessNode) InvoiceMacPath() string {
return hn.cfg.InvoiceMacPath return hn.Cfg.InvoiceMacPath
} }
// Start launches a new process running lnd. Additionally, the PID of the // Start launches a new process running lnd. Additionally, the PID of the
@ -372,7 +372,7 @@ func (hn *HarnessNode) InvoiceMacPath() string {
func (hn *HarnessNode) start(lndError chan<- error) error { func (hn *HarnessNode) start(lndError chan<- error) error {
hn.quit = make(chan struct{}) hn.quit = make(chan struct{})
args := hn.cfg.genArgs() args := hn.Cfg.genArgs()
hn.cmd = exec.Command("../../lnd-itest", args...) hn.cmd = exec.Command("../../lnd-itest", args...)
// Redirect stderr output to buffer // Redirect stderr output to buffer
@ -391,14 +391,14 @@ func (hn *HarnessNode) start(lndError chan<- error) error {
// log files. // log files.
if *logOutput { if *logOutput {
fileName := fmt.Sprintf("output-%d-%s-%s.log", hn.NodeID, fileName := fmt.Sprintf("output-%d-%s-%s.log", hn.NodeID,
hn.cfg.Name, hex.EncodeToString(hn.PubKey[:logPubKeyBytes])) hn.Cfg.Name, hex.EncodeToString(hn.PubKey[:logPubKeyBytes]))
// If the node's PubKey is not yet initialized, create a temporary // If the node's PubKey is not yet initialized, create a temporary
// file name. Later, after the PubKey has been initialized, the // file name. Later, after the PubKey has been initialized, the
// file can be moved to its final name with the PubKey included. // file can be moved to its final name with the PubKey included.
if bytes.Equal(hn.PubKey[:4], []byte{0, 0, 0, 0}) { if bytes.Equal(hn.PubKey[:4], []byte{0, 0, 0, 0}) {
fileName = fmt.Sprintf("output-%d-%s-tmp__.log", hn.NodeID, fileName = fmt.Sprintf("output-%d-%s-tmp__.log", hn.NodeID,
hn.cfg.Name) hn.Cfg.Name)
// Once the node has done its work, the log file can be renamed. // Once the node has done its work, the log file can be renamed.
finalizeLogfile = func() { finalizeLogfile = func() {
@ -406,7 +406,7 @@ func (hn *HarnessNode) start(lndError chan<- error) error {
hn.logFile.Close() hn.logFile.Close()
newFileName := fmt.Sprintf("output-%d-%s-%s.log", newFileName := fmt.Sprintf("output-%d-%s-%s.log",
hn.NodeID, hn.cfg.Name, hn.NodeID, hn.Cfg.Name,
hex.EncodeToString(hn.PubKey[:logPubKeyBytes])) hex.EncodeToString(hn.PubKey[:logPubKeyBytes]))
err := os.Rename(fileName, newFileName) err := os.Rename(fileName, newFileName)
if err != nil { if err != nil {
@ -469,7 +469,7 @@ func (hn *HarnessNode) start(lndError chan<- error) error {
// Since Stop uses the LightningClient to stop the node, if we fail to get a // Since Stop uses the LightningClient to stop the node, if we fail to get a
// connected client, we have to kill the process. // connected client, we have to kill the process.
useMacaroons := !hn.cfg.HasSeed useMacaroons := !hn.Cfg.HasSeed
conn, err := hn.ConnectRPC(useMacaroons) conn, err := hn.ConnectRPC(useMacaroons)
if err != nil { if err != nil {
hn.cmd.Process.Kill() hn.cmd.Process.Kill()
@ -480,7 +480,7 @@ func (hn *HarnessNode) start(lndError chan<- error) error {
// additional step to unlock the wallet. The connection returned will // additional step to unlock the wallet. The connection returned will
// only use the TLS certs, and can only perform operations necessary to // only use the TLS certs, and can only perform operations necessary to
// unlock the daemon. // unlock the daemon.
if hn.cfg.HasSeed { if hn.Cfg.HasSeed {
hn.WalletUnlockerClient = lnrpc.NewWalletUnlockerClient(conn) hn.WalletUnlockerClient = lnrpc.NewWalletUnlockerClient(conn)
return nil return nil
} }
@ -645,7 +645,7 @@ func (hn *HarnessNode) AddToLog(line string) error {
// writePidFile writes the process ID of the running lnd process to a .pid file. // writePidFile writes the process ID of the running lnd process to a .pid file.
func (hn *HarnessNode) writePidFile() error { func (hn *HarnessNode) writePidFile() error {
filePath := filepath.Join(hn.cfg.BaseDir, fmt.Sprintf("%v.pid", hn.NodeID)) filePath := filepath.Join(hn.Cfg.BaseDir, fmt.Sprintf("%v.pid", hn.NodeID))
pid, err := os.Create(filePath) pid, err := os.Create(filePath)
if err != nil { if err != nil {
@ -699,7 +699,7 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
// Wait until TLS certificate is created before using it, up to 30 sec. // Wait until TLS certificate is created before using it, up to 30 sec.
tlsTimeout := time.After(DefaultTimeout) tlsTimeout := time.After(DefaultTimeout)
for !fileExists(hn.cfg.TLSCertPath) { for !fileExists(hn.Cfg.TLSCertPath) {
select { select {
case <-tlsTimeout: case <-tlsTimeout:
return nil, fmt.Errorf("timeout waiting for TLS cert " + return nil, fmt.Errorf("timeout waiting for TLS cert " +
@ -710,7 +710,7 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
opts := []grpc.DialOption{grpc.WithBlock()} opts := []grpc.DialOption{grpc.WithBlock()}
tlsCreds, err := credentials.NewClientTLSFromFile( tlsCreds, err := credentials.NewClientTLSFromFile(
hn.cfg.TLSCertPath, "", hn.Cfg.TLSCertPath, "",
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -718,14 +718,14 @@ func (hn *HarnessNode) ConnectRPCWithMacaroon(mac *macaroon.Macaroon) (
opts = append(opts, grpc.WithTransportCredentials(tlsCreds)) opts = append(opts, grpc.WithTransportCredentials(tlsCreds))
if mac == nil { if mac == nil {
return grpc.Dial(hn.cfg.RPCAddr(), opts...) return grpc.Dial(hn.Cfg.RPCAddr(), opts...)
} }
macCred := macaroons.NewMacaroonCredential(mac) macCred := macaroons.NewMacaroonCredential(mac)
opts = append(opts, grpc.WithPerRPCCredentials(macCred)) opts = append(opts, grpc.WithPerRPCCredentials(macCred))
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout) ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
defer cancel() defer cancel()
return grpc.DialContext(ctx, hn.cfg.RPCAddr(), opts...) return grpc.DialContext(ctx, hn.Cfg.RPCAddr(), opts...)
} }
// ConnectRPC uses the TLS certificate and admin macaroon files written by the // ConnectRPC uses the TLS certificate and admin macaroon files written by the
@ -739,7 +739,7 @@ func (hn *HarnessNode) ConnectRPC(useMacs bool) (*grpc.ClientConn, error) {
// If we should use a macaroon, always take the admin macaroon as a // If we should use a macaroon, always take the admin macaroon as a
// default. // default.
mac, err := hn.ReadMacaroon(hn.cfg.AdminMacPath, DefaultTimeout) mac, err := hn.ReadMacaroon(hn.Cfg.AdminMacPath, DefaultTimeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -749,12 +749,12 @@ func (hn *HarnessNode) ConnectRPC(useMacs bool) (*grpc.ClientConn, error) {
// SetExtraArgs assigns the ExtraArgs field for the node's configuration. The // SetExtraArgs assigns the ExtraArgs field for the node's configuration. The
// changes will take effect on restart. // changes will take effect on restart.
func (hn *HarnessNode) SetExtraArgs(extraArgs []string) { func (hn *HarnessNode) SetExtraArgs(extraArgs []string) {
hn.cfg.ExtraArgs = extraArgs hn.Cfg.ExtraArgs = extraArgs
} }
// cleanup cleans up all the temporary files created by the node's process. // cleanup cleans up all the temporary files created by the node's process.
func (hn *HarnessNode) cleanup() error { func (hn *HarnessNode) cleanup() error {
return os.RemoveAll(hn.cfg.BaseDir) return os.RemoveAll(hn.Cfg.BaseDir)
} }
// Stop attempts to stop the active lnd process. // Stop attempts to stop the active lnd process.