From 329793d06b585de685281261c58418944190952c Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 2 Apr 2018 16:57:04 -0700 Subject: [PATCH] lntest/harness: add NewNodeWithSeed and RestoreNodeWithSeed --- lntest/harness.go | 133 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/lntest/harness.go b/lntest/harness.go index e6e68580f..c16547ad3 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -238,7 +238,97 @@ func (n *NetworkHarness) TearDownAll() error { // current instance of the network harness. The created node is running, but // not yet connected to other nodes within the network. func (n *NetworkHarness) NewNode(extraArgs []string) (*HarnessNode, error) { + return n.newNode(extraArgs, false) +} + +// NewNodeWithSeed fully initializes a new HarnessNode after creating a fresh +// aezeed. The provided password is used as both the aezeed password and the +// wallet password. The generated mnemonic is returned along with the +// initialized harness node. +func (n *NetworkHarness) NewNodeWithSeed(extraArgs []string, + password []byte) (*HarnessNode, []string, error) { + + node, err := n.newNode(extraArgs, true) + if err != nil { + return nil, nil, err + } + + timeout := time.Duration(time.Second * 15) + ctxb := context.Background() + + // Create a request to generate a new aezeed. The new seed will have the + // same password as the internal wallet. + genSeedReq := &lnrpc.GenSeedRequest{ + AezeedPassphrase: password, + } + + ctxt, _ := context.WithTimeout(ctxb, timeout) + genSeedResp, err := node.GenSeed(ctxt, genSeedReq) + if err != nil { + return nil, nil, err + } + + // With the seed created, construct the init request to the node, + // including the newly generated seed. + initReq := &lnrpc.InitWalletRequest{ + WalletPassword: password, + CipherSeedMnemonic: genSeedResp.CipherSeedMnemonic, + AezeedPassphrase: password, + } + + // Pass the init request via rpc to finish unlocking the node. This will + // also initialize the macaroon-authenticated LightningClient. + err = node.Init(ctxb, initReq) + if err != nil { + return nil, nil, err + } + + // With the node started, we can now record its public key within the + // global mapping. + n.RegisterNode(node) + + return node, genSeedResp.CipherSeedMnemonic, nil +} + +// RestoreNodeWithSeed fully initializes a HarnessNode using a chosen mnemonic, +// password, and recovery window. After providing the initialization request to +// unlock the node, this method will finish initializing the LightningClient +// such that the HarnessNode can be used for regular rpc operations. +func (n *NetworkHarness) RestoreNodeWithSeed(extraArgs []string, + password []byte, mnemonic []string, + recoveryWindow int32) (*HarnessNode, error) { + + node, err := n.newNode(extraArgs, true) + if err != nil { + return nil, err + } + + initReq := &lnrpc.InitWalletRequest{ + WalletPassword: password, + CipherSeedMnemonic: mnemonic, + AezeedPassphrase: password, + RecoveryWindow: recoveryWindow, + } + + err = node.Init(context.Background(), initReq) + if err != nil { + return nil, err + } + + // With the node started, we can now record its public key within the + // global mapping. + n.RegisterNode(node) + + return node, nil +} + +// newNode initializes a new HarnessNode, supporting the ability to initialize a +// wallet with or without a seed. If hasSeed is false, the returned harness node +// can be used immediately. Otherwise, the node will require an additional +// initialization phase where the wallet is either created or restored. +func (n *NetworkHarness) newNode(extraArgs []string, hasSeed bool) (*HarnessNode, error) { node, err := newNode(nodeConfig{ + HasSeed: hasSeed, RPCConfig: &n.rpcConfig, NetParams: n.netParams, ExtraArgs: extraArgs, @@ -257,13 +347,27 @@ func (n *NetworkHarness) NewNode(extraArgs []string) (*HarnessNode, error) { return nil, err } + // 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 + // can be driven via an unlocked rpc connection. + if node.cfg.HasSeed { + return node, nil + } + // With the node started, we can now record its public key within the // global mapping. + n.RegisterNode(node) + + return node, nil +} + +// RegisterNode records a new HarnessNode in the NetworkHarnesses map of known +// nodes. This method should only be called with nodes that have successfully +// retrieved their public keys via FetchNodeInfo. +func (n *NetworkHarness) RegisterNode(node *HarnessNode) { n.mtx.Lock() n.nodesByPub[node.PubKeyStr] = node n.mtx.Unlock() - - return node, nil } // EnsureConnected will try to connect to two nodes, returning no error if they @@ -986,10 +1090,31 @@ func (n *NetworkHarness) DumpLogs(node *HarnessNode) (string, error) { } // SendCoins attempts to send amt satoshis from the internal mining node to the -// targeted lightning node. +// targeted lightning node using a P2WKH address. func (n *NetworkHarness) SendCoins(ctx context.Context, amt btcutil.Amount, target *HarnessNode) error { + return n.sendCoins( + ctx, amt, target, lnrpc.NewAddressRequest_WITNESS_PUBKEY_HASH, + ) +} + +// SendCoinsNP2WKH attempts to send amt satoshis from the internal mining node +// to the targeted lightning node using a NP2WKH address. +func (n *NetworkHarness) SendCoinsNP2WKH(ctx context.Context, + amt btcutil.Amount, target *HarnessNode) error { + + return n.sendCoins( + ctx, amt, target, lnrpc.NewAddressRequest_NESTED_PUBKEY_HASH, + ) +} + +// sendCoins attempts to send amt satoshis from the internal mining node to the +// targeted lightning node. +func (n *NetworkHarness) sendCoins(ctx context.Context, amt btcutil.Amount, + target *HarnessNode, + addrType lnrpc.NewAddressRequest_AddressType) error { + balReq := &lnrpc.WalletBalanceRequest{} initialBalance, err := target.WalletBalance(ctx, balReq) if err != nil { @@ -1000,7 +1125,7 @@ func (n *NetworkHarness) SendCoins(ctx context.Context, amt btcutil.Amount, // to receive a p2wkh address s.t the output can immediately be used as // an input to a funding transaction. addrReq := &lnrpc.NewAddressRequest{ - Type: lnrpc.NewAddressRequest_WITNESS_PUBKEY_HASH, + Type: addrType, } resp, err := target.NewAddress(ctx, addrReq) if err != nil {