mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 01:36:24 +01:00
lntemp+itest: refactor wallet import tests
This commit is contained in:
parent
0176d58b85
commit
9000994b7b
3 changed files with 188 additions and 345 deletions
|
@ -469,4 +469,12 @@ var allTestCasesTemp = []*lntemp.TestCase{
|
|||
Name: "taproot",
|
||||
TestFunc: testTaproot,
|
||||
},
|
||||
{
|
||||
Name: "wallet import account",
|
||||
TestFunc: testWalletImportAccount,
|
||||
},
|
||||
{
|
||||
Name: "wallet import pubkey",
|
||||
TestFunc: testWalletImportPubKey,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -12,14 +12,6 @@ var allTestCases = []*testCase{
|
|||
name: "async bidirectional payments",
|
||||
test: testBidirectionalAsyncPayments,
|
||||
},
|
||||
{
|
||||
name: "wallet import account",
|
||||
test: testWalletImportAccount,
|
||||
},
|
||||
{
|
||||
name: "wallet import pubkey",
|
||||
test: testWalletImportPubKey,
|
||||
},
|
||||
{
|
||||
name: "remote signer",
|
||||
test: testRemoteSigner,
|
||||
|
|
|
@ -2,10 +2,6 @@ package itest
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -20,8 +16,8 @@ import (
|
|||
"github.com/lightningnetwork/lnd/funding"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/lntemp"
|
||||
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -55,30 +51,27 @@ func walletToLNAddrType(t *testing.T,
|
|||
|
||||
// newExternalAddr generates a new external address of an imported account for a
|
||||
// pair of nodes, where one acts as the funder and the other as the signer.
|
||||
func newExternalAddr(t *testing.T, funder, signer *lntest.HarnessNode,
|
||||
func newExternalAddr(ht *lntemp.HarnessTest, funder, signer *node.HarnessNode,
|
||||
importedAccount string, addrType walletrpc.AddressType) string {
|
||||
|
||||
// We'll generate a new address for Carol from Dave's node to receive
|
||||
// and fund a new channel.
|
||||
ctxb := context.Background()
|
||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
funderResp, err := funder.NewAddress(ctxt, &lnrpc.NewAddressRequest{
|
||||
Type: walletToLNAddrType(t, addrType),
|
||||
req := &lnrpc.NewAddressRequest{
|
||||
Type: walletToLNAddrType(ht.T, addrType),
|
||||
Account: importedAccount,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
funderResp := funder.RPC.NewAddress(req)
|
||||
|
||||
// Carol also needs to generate the address for the sake of this test to
|
||||
// be able to sign the channel funding input.
|
||||
signerResp, err := signer.NewAddress(ctxt, &lnrpc.NewAddressRequest{
|
||||
Type: walletToLNAddrType(t, addrType),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// Carol also needs to generate the address for the sake of this test
|
||||
// to be able to sign the channel funding input.
|
||||
req = &lnrpc.NewAddressRequest{
|
||||
Type: walletToLNAddrType(ht.T, addrType),
|
||||
}
|
||||
signerResp := signer.RPC.NewAddress(req)
|
||||
|
||||
// Sanity check that the generated addresses match.
|
||||
require.Equal(t, funderResp.Address, signerResp.Address)
|
||||
assertExternalAddrType(t, funderResp.Address, addrType)
|
||||
require.Equal(ht, funderResp.Address, signerResp.Address)
|
||||
assertExternalAddrType(ht.T, funderResp.Address, addrType)
|
||||
|
||||
return funderResp.Address
|
||||
}
|
||||
|
@ -130,108 +123,21 @@ func assertOutputScriptType(t *testing.T, expType txscript.ScriptClass,
|
|||
spew.Sdump(tx))
|
||||
}
|
||||
|
||||
// assertAccountBalance asserts that the unconfirmed and confirmed balance for
|
||||
// the given account is satisfied by the WalletBalance and ListUnspent RPCs. The
|
||||
// unconfirmed balance is not checked for neutrino nodes.
|
||||
func assertAccountBalance(t *testing.T, node *lntest.HarnessNode, account string,
|
||||
confirmedBalance, unconfirmedBalance int64) {
|
||||
|
||||
err := wait.NoError(func() error {
|
||||
balanceResp, err := node.WalletBalance(
|
||||
context.Background(), &lnrpc.WalletBalanceRequest{},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
require.Contains(t, balanceResp.AccountBalance, account)
|
||||
accountBalance := balanceResp.AccountBalance[account]
|
||||
|
||||
// Check confirmed balance.
|
||||
if accountBalance.ConfirmedBalance != confirmedBalance {
|
||||
return fmt.Errorf("expected confirmed balance %v, "+
|
||||
"got %v", confirmedBalance,
|
||||
accountBalance.ConfirmedBalance)
|
||||
}
|
||||
listUtxosReq := &lnrpc.ListUnspentRequest{
|
||||
MinConfs: 1,
|
||||
MaxConfs: math.MaxInt32,
|
||||
Account: account,
|
||||
}
|
||||
confirmedUtxosResp, err := node.ListUnspent(
|
||||
context.Background(), listUtxosReq,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var totalConfirmedVal int64
|
||||
for _, utxo := range confirmedUtxosResp.Utxos {
|
||||
totalConfirmedVal += utxo.AmountSat
|
||||
}
|
||||
if totalConfirmedVal != confirmedBalance {
|
||||
return fmt.Errorf("expected total confirmed utxo "+
|
||||
"balance %v, got %v", confirmedBalance,
|
||||
totalConfirmedVal)
|
||||
}
|
||||
|
||||
// Skip unconfirmed balance checks for neutrino nodes.
|
||||
if node.Cfg.BackendCfg.Name() == lntest.NeutrinoBackendName {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check unconfirmed balance.
|
||||
if accountBalance.UnconfirmedBalance != unconfirmedBalance {
|
||||
return fmt.Errorf("expected unconfirmed balance %v, "+
|
||||
"got %v", unconfirmedBalance,
|
||||
accountBalance.UnconfirmedBalance)
|
||||
}
|
||||
listUtxosReq.MinConfs = 0
|
||||
listUtxosReq.MaxConfs = 0
|
||||
unconfirmedUtxosResp, err := node.ListUnspent(
|
||||
context.Background(), listUtxosReq,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
var totalUnconfirmedVal int64
|
||||
for _, utxo := range unconfirmedUtxosResp.Utxos {
|
||||
totalUnconfirmedVal += utxo.AmountSat
|
||||
}
|
||||
if totalUnconfirmedVal != unconfirmedBalance {
|
||||
return fmt.Errorf("expected total unconfirmed utxo "+
|
||||
"balance %v, got %v", unconfirmedBalance,
|
||||
totalUnconfirmedVal)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, defaultTimeout)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// psbtSendFromImportedAccount attempts to fund a PSBT from the given imported
|
||||
// account, originating from the source node to the destination.
|
||||
func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode,
|
||||
signer *lntest.HarnessNode, account string,
|
||||
func psbtSendFromImportedAccount(ht *lntemp.HarnessTest, srcNode, destNode,
|
||||
signer *node.HarnessNode, account string,
|
||||
accountAddrType walletrpc.AddressType) {
|
||||
|
||||
ctxb := context.Background()
|
||||
|
||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
balanceResp, err := srcNode.WalletBalance(
|
||||
ctxt, &lnrpc.WalletBalanceRequest{},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
require.Contains(t.t, balanceResp.AccountBalance, account)
|
||||
balanceResp := srcNode.RPC.WalletBalance()
|
||||
require.Contains(ht, balanceResp.AccountBalance, account)
|
||||
confBalance := balanceResp.AccountBalance[account].ConfirmedBalance
|
||||
|
||||
destAmt := confBalance - 10000
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
destAddrResp, err := destNode.NewAddress(ctxt, &lnrpc.NewAddressRequest{
|
||||
destAddrResp := destNode.RPC.NewAddress(&lnrpc.NewAddressRequest{
|
||||
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
|
||||
})
|
||||
require.NoError(t.t, err)
|
||||
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
fundReq := &walletrpc.FundPsbtRequest{
|
||||
Template: &walletrpc.FundPsbtRequest_Raw{
|
||||
Raw: &walletrpc.TxTemplate{
|
||||
|
@ -245,29 +151,20 @@ func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
},
|
||||
Account: account,
|
||||
}
|
||||
fundResp, err := srcNode.WalletKitClient.FundPsbt(ctxt, fundReq)
|
||||
require.NoError(t.t, err)
|
||||
fundResp := srcNode.RPC.FundPsbt(fundReq)
|
||||
|
||||
// Have Carol sign the PSBT input since Dave doesn't have any private
|
||||
// key information.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
finalizeReq := &walletrpc.FinalizePsbtRequest{
|
||||
FundedPsbt: fundResp.FundedPsbt,
|
||||
}
|
||||
finalizeResp, err := signer.WalletKitClient.FinalizePsbt(
|
||||
ctxt, finalizeReq,
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
finalizeResp := signer.RPC.FinalizePsbt(finalizeReq)
|
||||
|
||||
// With the PSBT signed, we can broadcast the resulting transaction.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
publishReq := &walletrpc.Transaction{
|
||||
TxHex: finalizeResp.RawFinalTx,
|
||||
}
|
||||
_, err = srcNode.WalletKitClient.PublishTransaction(ctxt, publishReq)
|
||||
require.NoError(t.t, err)
|
||||
srcNode.RPC.PublishTransaction(publishReq)
|
||||
|
||||
// Carol's balance from Dave's perspective should update accordingly.
|
||||
var (
|
||||
|
@ -304,7 +201,7 @@ func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
expChangeScriptType = txscript.WitnessV1TaprootTy
|
||||
|
||||
default:
|
||||
t.Fatalf("unsupported addr type %v", accountAddrType)
|
||||
ht.Fatalf("unsupported addr type %v", accountAddrType)
|
||||
}
|
||||
changeUtxoAmt := confBalance - destAmt - expTxFee
|
||||
|
||||
|
@ -314,16 +211,20 @@ func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
if account == defaultImportedAccount {
|
||||
accountWithBalance = defaultAccount
|
||||
}
|
||||
assertAccountBalance(t.t, srcNode, accountWithBalance, 0, changeUtxoAmt)
|
||||
_ = mineBlocks(t, t.lndHarness, 1, 1)
|
||||
assertAccountBalance(t.t, srcNode, accountWithBalance, changeUtxoAmt, 0)
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, accountWithBalance, 0, changeUtxoAmt,
|
||||
)
|
||||
ht.MineBlocksAndAssertNumTxes(1, 1)
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, accountWithBalance, changeUtxoAmt, 0,
|
||||
)
|
||||
|
||||
// Finally, assert that the transaction has the expected change address
|
||||
// type based on the account.
|
||||
var tx wire.MsgTx
|
||||
err = tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx))
|
||||
require.NoError(t.t, err)
|
||||
assertOutputScriptType(t.t, expChangeScriptType, &tx, changeUtxoAmt)
|
||||
err := tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx))
|
||||
require.NoError(ht, err)
|
||||
assertOutputScriptType(ht.T, expChangeScriptType, &tx, changeUtxoAmt)
|
||||
}
|
||||
|
||||
// fundChanAndCloseFromImportedAccount attempts to a fund a channel from the
|
||||
|
@ -331,21 +232,14 @@ func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
// node. To ensure the channel is operational before closing it, a test payment
|
||||
// is made. Several balance assertions are made along the way for the sake of
|
||||
// correctness.
|
||||
func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
||||
signer *lntest.HarnessNode, account string,
|
||||
func fundChanAndCloseFromImportedAccount(ht *lntemp.HarnessTest, srcNode,
|
||||
destNode, signer *node.HarnessNode, account string,
|
||||
accountAddrType walletrpc.AddressType, utxoAmt, chanSize int64) {
|
||||
|
||||
ctxb := context.Background()
|
||||
|
||||
// Retrieve the current confirmed balance to make some assertions later
|
||||
// on.
|
||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
balanceResp, err := srcNode.WalletBalance(
|
||||
ctxt, &lnrpc.WalletBalanceRequest{},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
require.Contains(t.t, balanceResp.AccountBalance, account)
|
||||
balanceResp := srcNode.RPC.WalletBalance()
|
||||
require.Contains(ht, balanceResp.AccountBalance, account)
|
||||
accountConfBalance := balanceResp.
|
||||
AccountBalance[account].ConfirmedBalance
|
||||
defaultAccountConfBalance := balanceResp.
|
||||
|
@ -353,31 +247,23 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
|
||||
// Now, start the channel funding process. We'll need to connect both
|
||||
// nodes first.
|
||||
t.lndHarness.EnsureConnected(t.t, srcNode, destNode)
|
||||
ht.EnsureConnected(srcNode, destNode)
|
||||
|
||||
// The source node will then fund the channel through a PSBT shim.
|
||||
var pendingChanID [32]byte
|
||||
_, err = rand.Read(pendingChanID[:])
|
||||
require.NoError(t.t, err)
|
||||
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
chanUpdates, rawPsbt, err := openChannelPsbt(
|
||||
ctxt, srcNode, destNode, lntest.OpenChannelParams{
|
||||
pendingChanID := ht.Random32Bytes()
|
||||
chanUpdates, rawPsbt := ht.OpenChannelPsbt(
|
||||
srcNode, destNode, lntemp.OpenChannelParams{
|
||||
Amt: btcutil.Amount(chanSize),
|
||||
FundingShim: &lnrpc.FundingShim{
|
||||
Shim: &lnrpc.FundingShim_PsbtShim{
|
||||
PsbtShim: &lnrpc.PsbtShim{
|
||||
PendingChanId: pendingChanID[:],
|
||||
PendingChanId: pendingChanID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
fundReq := &walletrpc.FundPsbtRequest{
|
||||
Template: &walletrpc.FundPsbtRequest_Psbt{
|
||||
Psbt: rawPsbt,
|
||||
|
@ -387,49 +273,40 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
},
|
||||
Account: account,
|
||||
}
|
||||
fundResp, err := srcNode.WalletKitClient.FundPsbt(ctxt, fundReq)
|
||||
require.NoError(t.t, err)
|
||||
fundResp := srcNode.RPC.FundPsbt(fundReq)
|
||||
|
||||
_, err = srcNode.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{
|
||||
srcNode.RPC.FundingStateStep(&lnrpc.FundingTransitionMsg{
|
||||
Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{
|
||||
PsbtVerify: &lnrpc.FundingPsbtVerify{
|
||||
PendingChanId: pendingChanID[:],
|
||||
PendingChanId: pendingChanID,
|
||||
FundedPsbt: fundResp.FundedPsbt,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t.t, err)
|
||||
|
||||
// Now that we have a PSBT to fund the channel, our signer needs to sign
|
||||
// it.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
finalizeReq := &walletrpc.FinalizePsbtRequest{
|
||||
FundedPsbt: fundResp.FundedPsbt,
|
||||
}
|
||||
finalizeResp, err := signer.WalletKitClient.FinalizePsbt(ctxt, finalizeReq)
|
||||
require.NoError(t.t, err)
|
||||
finalizeResp := signer.RPC.FinalizePsbt(finalizeReq)
|
||||
|
||||
// The source node can then submit the signed PSBT and complete the
|
||||
// channel funding process.
|
||||
_, err = srcNode.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{
|
||||
srcNode.RPC.FundingStateStep(&lnrpc.FundingTransitionMsg{
|
||||
Trigger: &lnrpc.FundingTransitionMsg_PsbtFinalize{
|
||||
PsbtFinalize: &lnrpc.FundingPsbtFinalize{
|
||||
PendingChanId: pendingChanID[:],
|
||||
PendingChanId: pendingChanID,
|
||||
SignedPsbt: finalizeResp.SignedPsbt,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t.t, err)
|
||||
|
||||
// We should receive a notification of the channel funding transaction
|
||||
// being broadcast.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
updateResp, err := receiveChanUpdate(ctxt, chanUpdates)
|
||||
require.NoError(t.t, err)
|
||||
updateResp := ht.ReceiveOpenChannelUpdate(chanUpdates)
|
||||
upd, ok := updateResp.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
|
||||
require.True(t.t, ok)
|
||||
require.True(ht, ok)
|
||||
|
||||
// Mine enough blocks to announce the channel to the network, making
|
||||
// balance assertions along the way.
|
||||
|
@ -467,11 +344,11 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
expChangeScriptType = txscript.WitnessV1TaprootTy
|
||||
|
||||
default:
|
||||
t.Fatalf("unsupported addr type %v", accountAddrType)
|
||||
ht.Fatalf("unsupported addr type %v", accountAddrType)
|
||||
}
|
||||
chanChangeUtxoAmt := utxoAmt - chanSize - expChanTxFee
|
||||
txHash, err := chainhash.NewHash(upd.ChanPending.Txid)
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
|
||||
// If we're spending from the default imported account, then any change
|
||||
// outputs produced are moved to the default wallet account, so we
|
||||
|
@ -479,35 +356,35 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
var confBalanceAfterChan int64
|
||||
if account == defaultImportedAccount {
|
||||
confBalanceAfterChan = defaultAccountConfBalance
|
||||
assertAccountBalance(t.t, srcNode, account, 0, 0)
|
||||
assertAccountBalance(
|
||||
t.t, srcNode, defaultAccount, defaultAccountConfBalance,
|
||||
ht.AssertWalletAccountBalance(srcNode, account, 0, 0)
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, defaultAccount, defaultAccountConfBalance,
|
||||
chanChangeUtxoAmt,
|
||||
)
|
||||
|
||||
block := mineBlocks(t, t.lndHarness, 6, 1)[0]
|
||||
assertTxInBlock(t, block, txHash)
|
||||
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
||||
ht.Miner.AssertTxInBlock(block, txHash)
|
||||
|
||||
confBalanceAfterChan += chanChangeUtxoAmt
|
||||
assertAccountBalance(t.t, srcNode, account, 0, 0)
|
||||
assertAccountBalance(
|
||||
t.t, srcNode, defaultAccount, confBalanceAfterChan, 0,
|
||||
ht.AssertWalletAccountBalance(srcNode, account, 0, 0)
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, defaultAccount, confBalanceAfterChan, 0,
|
||||
)
|
||||
} else {
|
||||
// Otherwise, all interactions remain within Carol's imported
|
||||
// account.
|
||||
confBalanceAfterChan = accountConfBalance - utxoAmt
|
||||
assertAccountBalance(
|
||||
t.t, srcNode, account, confBalanceAfterChan,
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, account, confBalanceAfterChan,
|
||||
chanChangeUtxoAmt,
|
||||
)
|
||||
|
||||
block := mineBlocks(t, t.lndHarness, 6, 1)[0]
|
||||
assertTxInBlock(t, block, txHash)
|
||||
block := ht.MineBlocksAndAssertNumTxes(6, 1)[0]
|
||||
ht.Miner.AssertTxInBlock(block, txHash)
|
||||
|
||||
confBalanceAfterChan += chanChangeUtxoAmt
|
||||
assertAccountBalance(
|
||||
t.t, srcNode, account, confBalanceAfterChan, 0,
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, account, confBalanceAfterChan, 0,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -515,8 +392,10 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
// based on the account.
|
||||
var tx wire.MsgTx
|
||||
err = tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx))
|
||||
require.NoError(t.t, err)
|
||||
assertOutputScriptType(t.t, expChangeScriptType, &tx, chanChangeUtxoAmt)
|
||||
require.NoError(ht, err)
|
||||
assertOutputScriptType(
|
||||
ht.T, expChangeScriptType, &tx, chanChangeUtxoAmt,
|
||||
)
|
||||
|
||||
// Wait for the channel to be announced by both parties.
|
||||
chanPoint := &lnrpc.ChannelPoint{
|
||||
|
@ -525,29 +404,30 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
},
|
||||
OutputIndex: upd.ChanPending.OutputIndex,
|
||||
}
|
||||
err = srcNode.WaitForNetworkChannelOpen(chanPoint)
|
||||
require.NoError(t.t, err)
|
||||
err = destNode.WaitForNetworkChannelOpen(chanPoint)
|
||||
require.NoError(t.t, err)
|
||||
ht.AssertTopologyChannelOpen(srcNode, chanPoint)
|
||||
ht.AssertTopologyChannelOpen(destNode, chanPoint)
|
||||
|
||||
// Send a test payment to ensure the channel is operating as normal.
|
||||
const invoiceAmt = 100000
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
resp, err := destNode.AddInvoice(ctxt, &lnrpc.Invoice{
|
||||
invoice := &lnrpc.Invoice{
|
||||
Memo: "psbt import chan",
|
||||
Value: invoiceAmt,
|
||||
})
|
||||
require.NoError(t.t, err)
|
||||
}
|
||||
resp := destNode.RPC.AddInvoice(invoice)
|
||||
|
||||
err = completePaymentRequests(
|
||||
srcNode, srcNode.RouterClient,
|
||||
[]string{resp.PaymentRequest}, true,
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
ht.CompletePaymentRequests(srcNode, []string{resp.PaymentRequest})
|
||||
|
||||
// TODO(yy): remove the sleep once the following bug is fixed. When the
|
||||
// payment is reported as settled by srcNode, it's expected the
|
||||
// commitment dance is finished and all subsequent states have been
|
||||
// updated. Yet we'd receive the error `cannot co-op close channel with
|
||||
// active htlcs` or `link failed to shutdown` if we close the channel.
|
||||
// We need to investigate the order of settling the payments and
|
||||
// updating commitments to understand and fix .
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Now that we've confirmed the opened channel works, we'll close it.
|
||||
closeChannelAndAssert(t, t.lndHarness, srcNode, chanPoint, false)
|
||||
ht.CloseChannel(srcNode, chanPoint)
|
||||
|
||||
// Since the channel still had funds left on the source node's side,
|
||||
// they must've been redeemed after the close. Without a pre-negotiated
|
||||
|
@ -557,17 +437,17 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
balanceFromClosedChan := chanSize - invoiceAmt - chanCloseTxFee
|
||||
|
||||
if account == defaultImportedAccount {
|
||||
assertAccountBalance(t.t, srcNode, account, 0, 0)
|
||||
assertAccountBalance(
|
||||
t.t, srcNode, defaultAccount,
|
||||
ht.AssertWalletAccountBalance(srcNode, account, 0, 0)
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, defaultAccount,
|
||||
confBalanceAfterChan+balanceFromClosedChan, 0,
|
||||
)
|
||||
} else {
|
||||
assertAccountBalance(
|
||||
t.t, srcNode, account, confBalanceAfterChan, 0,
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, account, confBalanceAfterChan, 0,
|
||||
)
|
||||
assertAccountBalance(
|
||||
t.t, srcNode, defaultAccount, balanceFromClosedChan, 0,
|
||||
ht.AssertWalletAccountBalance(
|
||||
srcNode, defaultAccount, balanceFromClosedChan, 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -575,7 +455,7 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
|
|||
// testWalletImportAccount tests that an imported account can fund transactions
|
||||
// and channels through PSBTs, by having one node (the one with the imported
|
||||
// account) craft the transactions and another node act as the signer.
|
||||
func testWalletImportAccount(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
func testWalletImportAccount(ht *lntemp.HarnessTest) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
addrType walletrpc.AddressType
|
||||
|
@ -600,23 +480,24 @@ func testWalletImportAccount(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
success := t.t.Run(tc.name, func(tt *testing.T) {
|
||||
ht := newHarnessTest(tt, net)
|
||||
ht.RunTestCase(&testCase{
|
||||
name: tc.name,
|
||||
test: func(net1 *lntest.NetworkHarness,
|
||||
t1 *harnessTest) {
|
||||
success := ht.Run(tc.name, func(tt *testing.T) {
|
||||
testFunc := func(ht *lntemp.HarnessTest) {
|
||||
testWalletImportAccountScenario(
|
||||
ht, tc.addrType,
|
||||
)
|
||||
}
|
||||
|
||||
testWalletImportAccountScenario(
|
||||
net, t, tc.addrType,
|
||||
)
|
||||
},
|
||||
st := ht.Subtest(tt)
|
||||
|
||||
st.RunTestCase(&lntemp.TestCase{
|
||||
Name: tc.name,
|
||||
TestFunc: testFunc,
|
||||
})
|
||||
})
|
||||
if !success {
|
||||
// Log failure time to help relate the lnd logs to the
|
||||
// failure.
|
||||
t.Logf("Failure time: %v", time.Now().Format(
|
||||
ht.Logf("Failure time: %v", time.Now().Format(
|
||||
"2006-01-02 15:04:05.000",
|
||||
))
|
||||
break
|
||||
|
@ -624,115 +505,98 @@ func testWalletImportAccount(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
}
|
||||
}
|
||||
|
||||
func testWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest,
|
||||
func testWalletImportAccountScenario(ht *lntemp.HarnessTest,
|
||||
addrType walletrpc.AddressType) {
|
||||
|
||||
// We'll start our test by having two nodes, Carol and Dave. Carol's
|
||||
// default wallet account will be imported into Dave's node.
|
||||
carol := net.NewNode(t.t, "carol", nil)
|
||||
defer shutdownAndAssert(net, t, carol)
|
||||
//
|
||||
// NOTE: we won't use standby nodes here since the test will change
|
||||
// each of the node's wallet state.
|
||||
carol := ht.NewNode("carol", nil)
|
||||
dave := ht.NewNode("dave", nil)
|
||||
|
||||
dave := net.NewNode(t.t, "dave", nil)
|
||||
defer shutdownAndAssert(net, t, dave)
|
||||
|
||||
runWalletImportAccountScenario(net, t, addrType, carol, dave)
|
||||
runWalletImportAccountScenario(ht, addrType, carol, dave)
|
||||
}
|
||||
|
||||
func runWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest,
|
||||
addrType walletrpc.AddressType, carol, dave *lntest.HarnessNode) {
|
||||
func runWalletImportAccountScenario(ht *lntemp.HarnessTest,
|
||||
addrType walletrpc.AddressType, carol, dave *node.HarnessNode) {
|
||||
|
||||
ctxb := context.Background()
|
||||
const utxoAmt int64 = btcutil.SatoshiPerBitcoin
|
||||
|
||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
listReq := &walletrpc.ListAccountsRequest{
|
||||
Name: "default",
|
||||
AddressType: addrType,
|
||||
}
|
||||
listResp, err := carol.WalletKitClient.ListAccounts(ctxt, listReq)
|
||||
require.NoError(t.t, err)
|
||||
require.Equal(t.t, len(listResp.Accounts), 1)
|
||||
listResp := carol.RPC.ListAccounts(listReq)
|
||||
require.Len(ht, listResp.Accounts, 1)
|
||||
carolAccount := listResp.Accounts[0]
|
||||
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
const importedAccount = "carol"
|
||||
importReq := &walletrpc.ImportAccountRequest{
|
||||
Name: importedAccount,
|
||||
ExtendedPublicKey: carolAccount.ExtendedPublicKey,
|
||||
AddressType: addrType,
|
||||
}
|
||||
_, err = dave.WalletKitClient.ImportAccount(ctxt, importReq)
|
||||
require.NoError(t.t, err)
|
||||
dave.RPC.ImportAccount(importReq)
|
||||
|
||||
// We'll generate an address for Carol from Dave's node to receive some
|
||||
// funds.
|
||||
externalAddr := newExternalAddr(
|
||||
t.t, dave, carol, importedAccount, addrType,
|
||||
ht, dave, carol, importedAccount, addrType,
|
||||
)
|
||||
|
||||
// Send coins to Carol's address and confirm them, making sure the
|
||||
// balance updates accordingly.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
|
||||
alice := ht.Alice
|
||||
req := &lnrpc.SendCoinsRequest{
|
||||
Addr: externalAddr,
|
||||
Amount: utxoAmt,
|
||||
SatPerByte: 1,
|
||||
})
|
||||
require.NoError(t.t, err)
|
||||
}
|
||||
alice.RPC.SendCoins(req)
|
||||
|
||||
assertAccountBalance(t.t, dave, importedAccount, 0, utxoAmt)
|
||||
_ = mineBlocks(t, net, 1, 1)
|
||||
assertAccountBalance(t.t, dave, importedAccount, utxoAmt, 0)
|
||||
ht.AssertWalletAccountBalance(dave, importedAccount, 0, utxoAmt)
|
||||
ht.MineBlocksAndAssertNumTxes(1, 1)
|
||||
ht.AssertWalletAccountBalance(dave, importedAccount, utxoAmt, 0)
|
||||
|
||||
// To ensure that Dave can use Carol's account as watch-only, we'll
|
||||
// construct a PSBT that sends funds to Alice, which we'll then hand
|
||||
// over to Carol to sign.
|
||||
psbtSendFromImportedAccount(
|
||||
t, dave, net.Alice, carol, importedAccount, addrType,
|
||||
ht, dave, alice, carol, importedAccount, addrType,
|
||||
)
|
||||
|
||||
// We'll generate a new address for Carol from Dave's node to receive
|
||||
// and fund a new channel.
|
||||
externalAddr = newExternalAddr(
|
||||
t.t, dave, carol, importedAccount, addrType,
|
||||
ht, dave, carol, importedAccount, addrType,
|
||||
)
|
||||
|
||||
// Retrieve the current confirmed balance of the imported account for
|
||||
// some assertions we'll make later on.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
balanceResp, err := dave.WalletBalance(
|
||||
ctxt, &lnrpc.WalletBalanceRequest{},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
require.Contains(t.t, balanceResp.AccountBalance, importedAccount)
|
||||
balanceResp := dave.RPC.WalletBalance()
|
||||
require.Contains(ht, balanceResp.AccountBalance, importedAccount)
|
||||
confBalance := balanceResp.AccountBalance[importedAccount].ConfirmedBalance
|
||||
|
||||
// Send coins to Carol's address and confirm them, making sure the
|
||||
// balance updates accordingly.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
|
||||
req = &lnrpc.SendCoinsRequest{
|
||||
Addr: externalAddr,
|
||||
Amount: utxoAmt,
|
||||
SatPerByte: 1,
|
||||
})
|
||||
require.NoError(t.t, err)
|
||||
}
|
||||
alice.RPC.SendCoins(req)
|
||||
|
||||
assertAccountBalance(t.t, dave, importedAccount, confBalance, utxoAmt)
|
||||
_ = mineBlocks(t, net, 1, 1)
|
||||
assertAccountBalance(
|
||||
t.t, dave, importedAccount, confBalance+utxoAmt, 0,
|
||||
)
|
||||
ht.AssertWalletAccountBalance(dave, importedAccount, confBalance, utxoAmt)
|
||||
ht.MineBlocksAndAssertNumTxes(1, 1)
|
||||
ht.AssertWalletAccountBalance(dave, importedAccount, confBalance+utxoAmt, 0)
|
||||
|
||||
// Now that we have enough funds, it's time to fund the channel, make a
|
||||
// test payment, and close it. This contains several balance assertions
|
||||
// along the way.
|
||||
fundChanAndCloseFromImportedAccount(
|
||||
t, dave, net.Alice, carol, importedAccount, addrType, utxoAmt,
|
||||
ht, dave, alice, carol, importedAccount, addrType, utxoAmt,
|
||||
int64(funding.MaxBtcFundingAmount),
|
||||
)
|
||||
}
|
||||
|
@ -740,7 +604,7 @@ func runWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest,
|
|||
// testWalletImportPubKey tests that an imported public keys can fund
|
||||
// transactions and channels through PSBTs, by having one node (the one with the
|
||||
// imported account) craft the transactions and another node act as the signer.
|
||||
func testWalletImportPubKey(net *lntest.NetworkHarness, t *harnessTest) {
|
||||
func testWalletImportPubKey(ht *lntemp.HarnessTest) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
addrType walletrpc.AddressType
|
||||
|
@ -761,23 +625,24 @@ func testWalletImportPubKey(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
success := t.t.Run(tc.name, func(tt *testing.T) {
|
||||
ht := newHarnessTest(tt, net)
|
||||
ht.RunTestCase(&testCase{
|
||||
name: tc.name,
|
||||
test: func(net1 *lntest.NetworkHarness,
|
||||
t1 *harnessTest) {
|
||||
success := ht.Run(tc.name, func(tt *testing.T) {
|
||||
testFunc := func(ht *lntemp.HarnessTest) {
|
||||
testWalletImportPubKeyScenario(
|
||||
ht, tc.addrType,
|
||||
)
|
||||
}
|
||||
|
||||
testWalletImportPubKeyScenario(
|
||||
net, t, tc.addrType,
|
||||
)
|
||||
},
|
||||
st := ht.Subtest(tt)
|
||||
|
||||
st.RunTestCase(&lntemp.TestCase{
|
||||
Name: tc.name,
|
||||
TestFunc: testFunc,
|
||||
})
|
||||
})
|
||||
if !success {
|
||||
// Log failure time to help relate the lnd logs to the
|
||||
// failure.
|
||||
t.Logf("Failure time: %v", time.Now().Format(
|
||||
ht.Logf("Failure time: %v", time.Now().Format(
|
||||
"2006-01-02 15:04:05.000",
|
||||
))
|
||||
break
|
||||
|
@ -785,18 +650,18 @@ func testWalletImportPubKey(net *lntest.NetworkHarness, t *harnessTest) {
|
|||
}
|
||||
}
|
||||
|
||||
func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest,
|
||||
func testWalletImportPubKeyScenario(ht *lntemp.HarnessTest,
|
||||
addrType walletrpc.AddressType) {
|
||||
|
||||
ctxb := context.Background()
|
||||
const utxoAmt int64 = btcutil.SatoshiPerBitcoin
|
||||
alice := ht.Alice
|
||||
|
||||
// We'll start our test by having two nodes, Carol and Dave.
|
||||
carol := net.NewNode(t.t, "carol", nil)
|
||||
defer shutdownAndAssert(net, t, carol)
|
||||
|
||||
dave := net.NewNode(t.t, "dave", nil)
|
||||
defer shutdownAndAssert(net, t, dave)
|
||||
//
|
||||
// NOTE: we won't use standby nodes here since the test will change
|
||||
// each of the node's wallet state.
|
||||
carol := ht.NewNode("carol", nil)
|
||||
dave := ht.NewNode("dave", nil)
|
||||
|
||||
// We'll define a helper closure that we'll use throughout the test to
|
||||
// generate a new address of the given type from Carol's perspective,
|
||||
|
@ -806,30 +671,25 @@ func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest,
|
|||
|
||||
// Retrieve Carol's account public key for the corresponding
|
||||
// address type.
|
||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
listReq := &walletrpc.ListAccountsRequest{
|
||||
Name: "default",
|
||||
AddressType: addrType,
|
||||
}
|
||||
listResp, err := carol.WalletKitClient.ListAccounts(
|
||||
ctxt, listReq,
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
require.Equal(t.t, len(listResp.Accounts), 1)
|
||||
listResp := carol.RPC.ListAccounts(listReq)
|
||||
require.Len(ht, listResp.Accounts, 1)
|
||||
p2wkhAccount := listResp.Accounts[0]
|
||||
|
||||
// Derive the external address at the given index.
|
||||
accountPubKey, err := hdkeychain.NewKeyFromString(
|
||||
p2wkhAccount.ExtendedPublicKey,
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
externalAccountExtKey, err := accountPubKey.Derive(0)
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
externalAddrExtKey, err := externalAccountExtKey.Derive(keyIndex)
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
externalAddrPubKey, err := externalAddrExtKey.ECPubKey()
|
||||
require.NoError(t.t, err)
|
||||
require.NoError(ht, err)
|
||||
|
||||
// Serialize as 32-byte x-only pubkey for Taproot addresses.
|
||||
serializedPubKey := externalAddrPubKey.SerializeCompressed()
|
||||
|
@ -840,44 +700,34 @@ func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest,
|
|||
}
|
||||
|
||||
// Import the public key into Dave.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
importReq := &walletrpc.ImportPublicKeyRequest{
|
||||
PublicKey: serializedPubKey,
|
||||
AddressType: addrType,
|
||||
}
|
||||
_, err = dave.WalletKitClient.ImportPublicKey(ctxt, importReq)
|
||||
require.NoError(t.t, err)
|
||||
dave.RPC.ImportPublicKey(importReq)
|
||||
|
||||
// We'll also generate the same address for Carol, as it'll be
|
||||
// required later when signing.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
carolAddrResp, err := carol.NewAddress(
|
||||
ctxt, &lnrpc.NewAddressRequest{
|
||||
Type: walletToLNAddrType(t.t, addrType),
|
||||
},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
carolAddrResp := carol.RPC.NewAddress(&lnrpc.NewAddressRequest{
|
||||
Type: walletToLNAddrType(ht.T, addrType),
|
||||
})
|
||||
|
||||
// Send coins to Carol's address and confirm them, making sure
|
||||
// the balance updates accordingly.
|
||||
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
|
||||
req := &lnrpc.SendCoinsRequest{
|
||||
Addr: carolAddrResp.Address,
|
||||
Amount: utxoAmt,
|
||||
SatPerByte: 1,
|
||||
})
|
||||
require.NoError(t.t, err)
|
||||
}
|
||||
alice.RPC.SendCoins(req)
|
||||
|
||||
assertAccountBalance(
|
||||
t.t, dave, defaultImportedAccount, prevConfBalance,
|
||||
ht.AssertWalletAccountBalance(
|
||||
dave, defaultImportedAccount, prevConfBalance,
|
||||
prevUnconfBalance+utxoAmt,
|
||||
)
|
||||
_ = mineBlocks(t, net, 1, 1)
|
||||
assertAccountBalance(
|
||||
t.t, dave, defaultImportedAccount,
|
||||
ht.MineBlocksAndAssertNumTxes(1, 1)
|
||||
ht.AssertWalletAccountBalance(
|
||||
dave, defaultImportedAccount,
|
||||
prevConfBalance+utxoAmt, prevUnconfBalance,
|
||||
)
|
||||
}
|
||||
|
@ -890,22 +740,15 @@ func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest,
|
|||
// construct a PSBT that sends funds to Alice, which we'll then hand
|
||||
// over to Carol to sign.
|
||||
psbtSendFromImportedAccount(
|
||||
t, dave, net.Alice, carol, defaultImportedAccount, addrType,
|
||||
ht, dave, alice, carol, defaultImportedAccount, addrType,
|
||||
)
|
||||
|
||||
// We'll now attempt to fund a channel.
|
||||
//
|
||||
// We'll have Carol generate another external address, which we'll
|
||||
// import into Dave again.
|
||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
||||
defer cancel()
|
||||
balanceResp, err := dave.WalletBalance(
|
||||
ctxt, &lnrpc.WalletBalanceRequest{},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
require.Contains(
|
||||
t.t, balanceResp.AccountBalance, defaultImportedAccount,
|
||||
)
|
||||
balanceResp := dave.RPC.WalletBalance()
|
||||
require.Contains(ht, balanceResp.AccountBalance, defaultImportedAccount)
|
||||
confBalance := balanceResp.
|
||||
AccountBalance[defaultImportedAccount].ConfirmedBalance
|
||||
importPubKey(1, confBalance, 0)
|
||||
|
@ -914,7 +757,7 @@ func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest,
|
|||
// test payment, and close it. This contains several balance assertions
|
||||
// along the way.
|
||||
fundChanAndCloseFromImportedAccount(
|
||||
t, dave, net.Alice, carol, defaultImportedAccount, addrType,
|
||||
ht, dave, alice, carol, defaultImportedAccount, addrType,
|
||||
utxoAmt, int64(funding.MaxBtcFundingAmount),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue