mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-13 18:10:25 +02:00
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.
This commit is contained in:
@@ -5,9 +5,12 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
|
"github.com/btcsuite/btcutil/hdkeychain"
|
||||||
|
"github.com/lightningnetwork/lnd/aezeed"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// testGetRecoveryInfo checks whether lnd gives the right information about
|
// 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, mnemonic, _, err := net.NewNodeWithSeed(
|
||||||
"Carol", nil, password, false,
|
"Carol", nil, password, false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("unable to create node with seed; %v", err)
|
|
||||||
}
|
|
||||||
shutdownAndAssert(net, t, carol)
|
shutdownAndAssert(net, t, carol)
|
||||||
|
|
||||||
// As long as the mnemonic is non-nil and the extended key is empty, the
|
// 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,
|
restoreCheckBalance := func(expAmount int64, expectedNumUTXOs uint32,
|
||||||
recoveryWindow int32, fn func(*lntest.HarnessNode)) {
|
recoveryWindow int32, fn func(*lntest.HarnessNode)) {
|
||||||
|
|
||||||
|
t.t.Helper()
|
||||||
|
|
||||||
// Restore Carol, passing in the password, mnemonic, and
|
// Restore Carol, passing in the password, mnemonic, and
|
||||||
// desired recovery window.
|
// desired recovery window.
|
||||||
node, err := net.RestoreNodeWithSeed(
|
node, err := net.RestoreNodeWithSeed(
|
||||||
"Carol", nil, password, mnemonic, rootKey,
|
"Carol", nil, password, mnemonic, rootKey,
|
||||||
recoveryWindow, nil,
|
recoveryWindow, nil,
|
||||||
)
|
)
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("unable to restore node: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query carol for her current wallet balance, and also that we
|
// Query carol for her current wallet balance, and also that we
|
||||||
// gain the expected number of UTXOs.
|
// gain the expected number of UTXOs.
|
||||||
@@ -163,10 +164,7 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
req := &lnrpc.WalletBalanceRequest{}
|
req := &lnrpc.WalletBalanceRequest{}
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||||
resp, err := node.WalletBalance(ctxt, req)
|
resp, err := node.WalletBalance(ctxt, req)
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("unable to query wallet balance: %v",
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
currBalance = resp.ConfirmedBalance
|
currBalance = resp.ConfirmedBalance
|
||||||
|
|
||||||
utxoReq := &lnrpc.ListUnspentRequest{
|
utxoReq := &lnrpc.ListUnspentRequest{
|
||||||
@@ -174,9 +172,7 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
utxoResp, err := node.ListUnspent(ctxt, utxoReq)
|
utxoResp, err := node.ListUnspent(ctxt, utxoReq)
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("unable to query utxos: %v", err)
|
|
||||||
}
|
|
||||||
currNumUTXOs = uint32(len(utxoResp.Utxos))
|
currNumUTXOs = uint32(len(utxoResp.Utxos))
|
||||||
|
|
||||||
// Verify that Carol's balance and number of 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.
|
// behavior to both default P2WKH and NP2WKH scopes.
|
||||||
skipAndSend := func(nskip int) func(*lntest.HarnessNode) {
|
skipAndSend := func(nskip int) func(*lntest.HarnessNode) {
|
||||||
return func(node *lntest.HarnessNode) {
|
return func(node *lntest.HarnessNode) {
|
||||||
|
t.t.Helper()
|
||||||
|
|
||||||
newP2WKHAddrReq := &lnrpc.NewAddressRequest{
|
newP2WKHAddrReq := &lnrpc.NewAddressRequest{
|
||||||
Type: AddrTypeWitnessPubkeyHash,
|
Type: AddrTypeWitnessPubkeyHash,
|
||||||
}
|
}
|
||||||
@@ -226,17 +224,11 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
for i := 0; i < nskip; i++ {
|
for i := 0; i < nskip; i++ {
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||||
_, err = node.NewAddress(ctxt, newP2WKHAddrReq)
|
_, err = node.NewAddress(ctxt, newP2WKHAddrReq)
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("unable to generate new "+
|
|
||||||
"p2wkh address: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
_, err = node.NewAddress(ctxt, newNP2WKHAddrReq)
|
_, err = node.NewAddress(ctxt, newNP2WKHAddrReq)
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("unable to generate new "+
|
|
||||||
"np2wkh address: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send one BTC to the next P2WKH address.
|
// 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 minerAmt = 5 * btcutil.SatoshiPerBitcoin
|
||||||
const finalBalance = 6 * btcutil.SatoshiPerBitcoin
|
const finalBalance = 6 * btcutil.SatoshiPerBitcoin
|
||||||
promptChangeAddr := func(node *lntest.HarnessNode) {
|
promptChangeAddr := func(node *lntest.HarnessNode) {
|
||||||
|
t.t.Helper()
|
||||||
|
|
||||||
minerAddr, err := net.Miner.NewAddress()
|
minerAddr, err := net.Miner.NewAddress()
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("unable to create new miner address: %v", err)
|
|
||||||
}
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
||||||
resp, err := node.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
|
resp, err := node.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
|
||||||
Addr: minerAddr.String(),
|
Addr: minerAddr.String(),
|
||||||
Amount: minerAmt,
|
Amount: minerAmt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("unable to send coins to miner: %v", err)
|
|
||||||
}
|
|
||||||
txid, err := waitForTxInMempool(
|
txid, err := waitForTxInMempool(
|
||||||
net.Miner.Client, minerMempoolTimeout,
|
net.Miner.Client, minerMempoolTimeout,
|
||||||
)
|
)
|
||||||
if err != nil {
|
require.NoError(t.t, err)
|
||||||
t.Fatalf("transaction not found in mempool: %v", err)
|
require.Equal(t.t, txid.String(), resp.Txid)
|
||||||
}
|
|
||||||
if resp.Txid != txid.String() {
|
|
||||||
t.Fatalf("txid mismatch: %v vs %v", resp.Txid,
|
|
||||||
txid.String())
|
|
||||||
}
|
|
||||||
block := mineBlocks(t, net, 1, 1)[0]
|
block := mineBlocks(t, net, 1, 1)[0]
|
||||||
assertTxInBlock(t, block, txid)
|
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.
|
// only have one UTXO present (the change output) of 6 - 5 - fee BTC.
|
||||||
const fee = 27750
|
const fee = 27750
|
||||||
restoreCheckBalance(finalBalance-minerAmt-fee, 1, 21, nil)
|
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)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user