From 08225737439472f2a24652a5a43fc9d3e90f6733 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Sat, 24 Oct 2020 23:18:58 +0200 Subject: [PATCH] itest: test wallet recovery from extended master root key We add an additional test case to the on-chain fund recovery test that tries restoring the same wallet from the extended master root key instead of the seed. --- lntest/itest/lnd_recovery_test.go | 69 ++++++++++++++++--------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/lntest/itest/lnd_recovery_test.go b/lntest/itest/lnd_recovery_test.go index d287c9b29..d330bfb80 100644 --- a/lntest/itest/lnd_recovery_test.go +++ b/lntest/itest/lnd_recovery_test.go @@ -5,9 +5,12 @@ import ( "math" "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcutil/hdkeychain" + "github.com/lightningnetwork/lnd/aezeed" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntest/wait" + "github.com/stretchr/testify/require" ) // testGetRecoveryInfo checks whether lnd gives the right information about @@ -126,9 +129,7 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { carol, mnemonic, _, err := net.NewNodeWithSeed( "Carol", nil, password, false, ) - if err != nil { - t.Fatalf("unable to create node with seed; %v", err) - } + require.NoError(t.t, err) shutdownAndAssert(net, t, carol) // As long as the mnemonic is non-nil and the extended key is empty, the @@ -143,15 +144,15 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { restoreCheckBalance := func(expAmount int64, expectedNumUTXOs uint32, recoveryWindow int32, fn func(*lntest.HarnessNode)) { + t.t.Helper() + // Restore Carol, passing in the password, mnemonic, and // desired recovery window. node, err := net.RestoreNodeWithSeed( "Carol", nil, password, mnemonic, rootKey, recoveryWindow, nil, ) - if err != nil { - t.Fatalf("unable to restore node: %v", err) - } + require.NoError(t.t, err) // Query carol for her current wallet balance, and also that we // gain the expected number of UTXOs. @@ -163,10 +164,7 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { req := &lnrpc.WalletBalanceRequest{} ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) resp, err := node.WalletBalance(ctxt, req) - if err != nil { - t.Fatalf("unable to query wallet balance: %v", - err) - } + require.NoError(t.t, err) currBalance = resp.ConfirmedBalance utxoReq := &lnrpc.ListUnspentRequest{ @@ -174,9 +172,7 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { } ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) utxoResp, err := node.ListUnspent(ctxt, utxoReq) - if err != nil { - t.Fatalf("unable to query utxos: %v", err) - } + require.NoError(t.t, err) currNumUTXOs = uint32(len(utxoResp.Utxos)) // Verify that Carol's balance and number of UTXOs @@ -214,6 +210,8 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { // behavior to both default P2WKH and NP2WKH scopes. skipAndSend := func(nskip int) func(*lntest.HarnessNode) { return func(node *lntest.HarnessNode) { + t.t.Helper() + newP2WKHAddrReq := &lnrpc.NewAddressRequest{ Type: AddrTypeWitnessPubkeyHash, } @@ -226,17 +224,11 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { for i := 0; i < nskip; i++ { ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) _, err = node.NewAddress(ctxt, newP2WKHAddrReq) - if err != nil { - t.Fatalf("unable to generate new "+ - "p2wkh address: %v", err) - } + require.NoError(t.t, err) ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) _, err = node.NewAddress(ctxt, newNP2WKHAddrReq) - if err != nil { - t.Fatalf("unable to generate new "+ - "np2wkh address: %v", err) - } + require.NoError(t.t, err) } // Send one BTC to the next P2WKH address. @@ -303,28 +295,22 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { const minerAmt = 5 * btcutil.SatoshiPerBitcoin const finalBalance = 6 * btcutil.SatoshiPerBitcoin promptChangeAddr := func(node *lntest.HarnessNode) { + t.t.Helper() + minerAddr, err := net.Miner.NewAddress() - if err != nil { - t.Fatalf("unable to create new miner address: %v", err) - } + require.NoError(t.t, err) ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) resp, err := node.SendCoins(ctxt, &lnrpc.SendCoinsRequest{ Addr: minerAddr.String(), Amount: minerAmt, }) - if err != nil { - t.Fatalf("unable to send coins to miner: %v", err) - } + require.NoError(t.t, err) txid, err := waitForTxInMempool( net.Miner.Client, minerMempoolTimeout, ) - if err != nil { - t.Fatalf("transaction not found in mempool: %v", err) - } - if resp.Txid != txid.String() { - t.Fatalf("txid mismatch: %v vs %v", resp.Txid, - txid.String()) - } + require.NoError(t.t, err) + require.Equal(t.t, txid.String(), resp.Txid) + block := mineBlocks(t, net, 1, 1)[0] assertTxInBlock(t, block, txid) } @@ -335,4 +321,19 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { // only have one UTXO present (the change output) of 6 - 5 - fee BTC. const fee = 27750 restoreCheckBalance(finalBalance-minerAmt-fee, 1, 21, nil) + + // Last of all, make sure we can also restore a node from the extended + // master root key directly instead of the seed. + var seedMnemonic aezeed.Mnemonic + copy(seedMnemonic[:], mnemonic) + cipherSeed, err := seedMnemonic.ToCipherSeed(password) + require.NoError(t.t, err) + extendedRootKey, err := hdkeychain.NewMaster( + cipherSeed.Entropy[:], harnessNetParams, + ) + require.NoError(t.t, err) + rootKey = extendedRootKey.String() + mnemonic = nil + + restoreCheckBalance(finalBalance-minerAmt-fee, 1, 21, nil) }