mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-02 03:01:32 +02:00
itest: refactor testOnchainFundRecovery
This commit is contained in:
parent
b4d288cc10
commit
5208c501a2
@ -115,4 +115,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
|
|||||||
Name: "recovery info",
|
Name: "recovery info",
|
||||||
TestFunc: testGetRecoveryInfo,
|
TestFunc: testGetRecoveryInfo,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "onchain fund recovery",
|
||||||
|
TestFunc: testOnchainFundRecovery,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package itest
|
package itest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
@ -9,8 +8,9 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcutil/hdkeychain"
|
"github.com/btcsuite/btcd/btcutil/hdkeychain"
|
||||||
"github.com/lightningnetwork/lnd/aezeed"
|
"github.com/lightningnetwork/lnd/aezeed"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -87,18 +87,12 @@ func testGetRecoveryInfo(ht *lntemp.HarnessTest) {
|
|||||||
// when providing a valid aezeed that owns outputs on the chain. This test
|
// when providing a valid aezeed that owns outputs on the chain. This test
|
||||||
// performs multiple restorations using the same seed and various recovery
|
// performs multiple restorations using the same seed and various recovery
|
||||||
// windows to ensure we detect funds properly.
|
// windows to ensure we detect funds properly.
|
||||||
func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
func testOnchainFundRecovery(ht *lntemp.HarnessTest) {
|
||||||
ctxb := context.Background()
|
|
||||||
|
|
||||||
// First, create a new node with strong passphrase and grab the mnemonic
|
// First, create a new node with strong passphrase and grab the mnemonic
|
||||||
// used for key derivation. This will bring up Carol with an empty
|
// used for key derivation. This will bring up Carol with an empty
|
||||||
// wallet, and such that she is synced up.
|
// wallet, and such that she is synced up.
|
||||||
password := []byte("The Magic Words are Squeamish Ossifrage")
|
password := []byte("The Magic Words are Squeamish Ossifrage")
|
||||||
carol, mnemonic, _, err := net.NewNodeWithSeed(
|
carol, mnemonic, _ := ht.NewNodeWithSeed("Carol", nil, password, false)
|
||||||
"Carol", nil, password, false,
|
|
||||||
)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
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
|
||||||
// closure below will always restore the node from the seed. The tests
|
// closure below will always restore the node from the seed. The tests
|
||||||
@ -110,17 +104,16 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// given recovery window. Additionally, the caller can specify an action
|
// given recovery window. Additionally, the caller can specify an action
|
||||||
// to perform on the restored node before the node is shutdown.
|
// to perform on the restored node before the node is shutdown.
|
||||||
restoreCheckBalance := func(expAmount int64, expectedNumUTXOs uint32,
|
restoreCheckBalance := func(expAmount int64, expectedNumUTXOs uint32,
|
||||||
recoveryWindow int32, fn func(*lntest.HarnessNode)) {
|
recoveryWindow int32, fn func(*node.HarnessNode)) {
|
||||||
|
|
||||||
t.t.Helper()
|
ht.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 := ht.RestoreNodeWithSeed(
|
||||||
"Carol", nil, password, mnemonic, rootKey,
|
carol.Name(), nil, password, mnemonic, rootKey,
|
||||||
recoveryWindow, nil,
|
recoveryWindow, nil,
|
||||||
)
|
)
|
||||||
require.NoError(t.t, 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.
|
||||||
@ -128,38 +121,33 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
currBalance int64
|
currBalance int64
|
||||||
currNumUTXOs uint32
|
currNumUTXOs uint32
|
||||||
)
|
)
|
||||||
err = wait.Predicate(func() bool {
|
err := wait.NoError(func() error {
|
||||||
req := &lnrpc.WalletBalanceRequest{}
|
resp := node.RPC.WalletBalance()
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
resp, err := node.WalletBalance(ctxt, req)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
currBalance = resp.ConfirmedBalance
|
currBalance = resp.ConfirmedBalance
|
||||||
|
|
||||||
utxoReq := &lnrpc.ListUnspentRequest{
|
req := &walletrpc.ListUnspentRequest{
|
||||||
|
Account: "",
|
||||||
MaxConfs: math.MaxInt32,
|
MaxConfs: math.MaxInt32,
|
||||||
|
MinConfs: 0,
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
utxoResp := node.RPC.ListUnspent(req)
|
||||||
utxoResp, err := node.ListUnspent(ctxt, utxoReq)
|
|
||||||
require.NoError(t.t, 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
|
||||||
// matches what's expected.
|
// matches what's expected.
|
||||||
if expAmount != currBalance {
|
if expAmount != currBalance {
|
||||||
return false
|
return fmt.Errorf("balance not matched, want "+
|
||||||
|
"%d, got %d", expAmount, currBalance)
|
||||||
}
|
}
|
||||||
if currNumUTXOs != expectedNumUTXOs {
|
if currNumUTXOs != expectedNumUTXOs {
|
||||||
return false
|
return fmt.Errorf("num of UTXOs not matched, "+
|
||||||
|
"want %d, got %d", expectedNumUTXOs,
|
||||||
|
currNumUTXOs)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return nil
|
||||||
}, defaultTimeout)
|
}, defaultTimeout)
|
||||||
if err != nil {
|
require.NoError(ht, err, "timeout checking Carol")
|
||||||
t.Fatalf("expected restored node to have %d satoshis, "+
|
|
||||||
"instead has %d satoshis, expected %d utxos "+
|
|
||||||
"instead has %d", expAmount, currBalance,
|
|
||||||
expectedNumUTXOs, currNumUTXOs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user provided a callback, execute the commands against
|
// If the user provided a callback, execute the commands against
|
||||||
// the restored Carol.
|
// the restored Carol.
|
||||||
@ -167,71 +155,41 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
fn(node)
|
fn(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the previous outpoints are set correctly.
|
|
||||||
req := &lnrpc.GetTransactionsRequest{
|
|
||||||
StartHeight: 0,
|
|
||||||
EndHeight: -1,
|
|
||||||
}
|
|
||||||
txDetails, err := node.GetTransactions(ctxb, req)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
for _, tx := range txDetails.Transactions {
|
|
||||||
require.Greater(t.t, len(tx.PreviousOutpoints), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lastly, shutdown this Carol so we can move on to the next
|
// Lastly, shutdown this Carol so we can move on to the next
|
||||||
// restoration.
|
// restoration.
|
||||||
shutdownAndAssert(net, t, node)
|
ht.Shutdown(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a closure-factory for building closures that can generate and
|
// Create a closure-factory for building closures that can generate and
|
||||||
// skip a configurable number of addresses, before finally sending coins
|
// skip a configurable number of addresses, before finally sending coins
|
||||||
// to a next generated address. The returned closure will apply the same
|
// to a next generated address. The returned closure will apply the same
|
||||||
// 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(*node.HarnessNode) {
|
||||||
return func(node *lntest.HarnessNode) {
|
return func(node *node.HarnessNode) {
|
||||||
t.t.Helper()
|
ht.Helper()
|
||||||
|
|
||||||
newP2WKHAddrReq := &lnrpc.NewAddressRequest{
|
|
||||||
Type: AddrTypeWitnessPubkeyHash,
|
|
||||||
}
|
|
||||||
|
|
||||||
newNP2WKHAddrReq := &lnrpc.NewAddressRequest{
|
|
||||||
Type: AddrTypeNestedPubkeyHash,
|
|
||||||
}
|
|
||||||
|
|
||||||
newP2TRAddrReq := &lnrpc.NewAddressRequest{
|
|
||||||
Type: AddrTypeTaprootPubkey,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate and skip the number of addresses requested.
|
// Generate and skip the number of addresses requested.
|
||||||
ctxt, cancel := context.WithTimeout(
|
|
||||||
ctxb, defaultTimeout,
|
|
||||||
)
|
|
||||||
defer cancel()
|
|
||||||
for i := 0; i < nskip; i++ {
|
for i := 0; i < nskip; i++ {
|
||||||
_, err = node.NewAddress(ctxt, newP2WKHAddrReq)
|
req := &lnrpc.NewAddressRequest{}
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
_, err = node.NewAddress(ctxt, newNP2WKHAddrReq)
|
req.Type = AddrTypeWitnessPubkeyHash
|
||||||
require.NoError(t.t, err)
|
node.RPC.NewAddress(req)
|
||||||
|
|
||||||
_, err = node.NewAddress(ctxt, newP2TRAddrReq)
|
req.Type = AddrTypeNestedPubkeyHash
|
||||||
require.NoError(t.t, err)
|
node.RPC.NewAddress(req)
|
||||||
|
|
||||||
|
req.Type = AddrTypeTaprootPubkey
|
||||||
|
node.RPC.NewAddress(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send one BTC to the next P2WKH address.
|
// Send one BTC to the next P2WKH address.
|
||||||
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, node)
|
ht.FundCoins(btcutil.SatoshiPerBitcoin, node)
|
||||||
|
|
||||||
// And another to the next NP2WKH address.
|
// And another to the next NP2WKH address.
|
||||||
net.SendCoinsNP2WKH(
|
ht.FundCoinsNP2WKH(btcutil.SatoshiPerBitcoin, node)
|
||||||
t.t, btcutil.SatoshiPerBitcoin, node,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Add another whole coin to the P2TR address.
|
// Add another whole coin to the P2TR address.
|
||||||
net.SendCoinsP2TR(
|
ht.FundCoinsP2TR(btcutil.SatoshiPerBitcoin, node)
|
||||||
t.t, btcutil.SatoshiPerBitcoin, node,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,25 +242,21 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// avoid fee discrepancies and a change output is formed.
|
// avoid fee discrepancies and a change output is formed.
|
||||||
const minerAmt = 8 * btcutil.SatoshiPerBitcoin
|
const minerAmt = 8 * btcutil.SatoshiPerBitcoin
|
||||||
const finalBalance = 9 * btcutil.SatoshiPerBitcoin
|
const finalBalance = 9 * btcutil.SatoshiPerBitcoin
|
||||||
promptChangeAddr := func(node *lntest.HarnessNode) {
|
promptChangeAddr := func(node *node.HarnessNode) {
|
||||||
t.t.Helper()
|
ht.Helper()
|
||||||
|
|
||||||
minerAddr, err := net.Miner.NewAddress()
|
minerAddr := ht.Miner.NewMinerAddress()
|
||||||
require.NoError(t.t, err)
|
req := &lnrpc.SendCoinsRequest{
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
resp, err := node.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
|
|
||||||
Addr: minerAddr.String(),
|
Addr: minerAddr.String(),
|
||||||
Amount: minerAmt,
|
Amount: minerAmt,
|
||||||
})
|
}
|
||||||
require.NoError(t.t, err)
|
resp := node.RPC.SendCoins(req)
|
||||||
txid, err := waitForTxInMempool(
|
|
||||||
net.Miner.Client, minerMempoolTimeout,
|
|
||||||
)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
require.Equal(t.t, txid.String(), resp.Txid)
|
|
||||||
|
|
||||||
block := mineBlocks(t, net, 1, 1)[0]
|
txid := ht.Miner.AssertNumTxsInMempool(1)[0]
|
||||||
assertTxInBlock(t, block, txid)
|
require.Equal(ht, txid.String(), resp.Txid)
|
||||||
|
|
||||||
|
block := ht.MineBlocks(1)[0]
|
||||||
|
ht.Miner.AssertTxInBlock(block, txid)
|
||||||
}
|
}
|
||||||
restoreCheckBalance(finalBalance, 9, 20, promptChangeAddr)
|
restoreCheckBalance(finalBalance, 9, 20, promptChangeAddr)
|
||||||
|
|
||||||
@ -318,11 +272,11 @@ func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
var seedMnemonic aezeed.Mnemonic
|
var seedMnemonic aezeed.Mnemonic
|
||||||
copy(seedMnemonic[:], mnemonic)
|
copy(seedMnemonic[:], mnemonic)
|
||||||
cipherSeed, err := seedMnemonic.ToCipherSeed(password)
|
cipherSeed, err := seedMnemonic.ToCipherSeed(password)
|
||||||
require.NoError(t.t, err)
|
require.NoError(ht, err)
|
||||||
extendedRootKey, err := hdkeychain.NewMaster(
|
extendedRootKey, err := hdkeychain.NewMaster(
|
||||||
cipherSeed.Entropy[:], harnessNetParams,
|
cipherSeed.Entropy[:], harnessNetParams,
|
||||||
)
|
)
|
||||||
require.NoError(t.t, err)
|
require.NoError(ht, err)
|
||||||
rootKey = extendedRootKey.String()
|
rootKey = extendedRootKey.String()
|
||||||
mnemonic = nil
|
mnemonic = nil
|
||||||
|
|
||||||
|
@ -4,10 +4,6 @@
|
|||||||
package itest
|
package itest
|
||||||
|
|
||||||
var allTestCases = []*testCase{
|
var allTestCases = []*testCase{
|
||||||
{
|
|
||||||
name: "onchain fund recovery",
|
|
||||||
test: testOnchainFundRecovery,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "basic funding flow with all input types",
|
name: "basic funding flow with all input types",
|
||||||
test: testChannelFundingInputTypes,
|
test: testChannelFundingInputTypes,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user