Skip to content

Commit

Permalink
itest: unify PSBT channel funding tests, add taproot
Browse files Browse the repository at this point in the history
With this commit we unify three existing PSBT channel funding
integration tests into a single one with the goal of testing all three
cases with simple taproot channels as well.
  • Loading branch information
guggero committed Aug 29, 2023
1 parent 646444c commit 590dc0c
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 34 deletions.
8 changes: 0 additions & 8 deletions itest/list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,14 +269,6 @@ var allTestCases = []*lntest.TestCase{
Name: "psbt channel funding",
TestFunc: testPsbtChanFunding,
},
{
Name: "psbt channel funding external",
TestFunc: testPsbtChanFundingExternal,
},
{
Name: "psbt channel funding single step",
TestFunc: testPsbtChanFundingSingleStep,
},
{
Name: "sign psbt",
TestFunc: testSignPsbt,
Expand Down
152 changes: 127 additions & 25 deletions itest/lnd_psbt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package itest

import (
"bytes"
"testing"
"time"

"github.com/btcsuite/btcd/btcec/v2"
Expand All @@ -27,19 +28,116 @@ import (
// by using a Partially Signed Bitcoin Transaction that funds the channel
// multisig funding output.
func testPsbtChanFunding(ht *lntest.HarnessTest) {
// First, we'll create two new nodes that we'll use to open channels
// between for this test. Dave gets some coins that will be used to
// fund the PSBT, just to make sure that Carol has an empty wallet.
carol := ht.NewNode("carol", nil)
dave := ht.NewNode("dave", nil)
const (
burnAddr = "bcrt1qxsnqpdc842lu8c0xlllgvejt6rhy49u6fmpgyz"
)

runPsbtChanFunding(ht, carol, dave)
testCases := []struct {
name string
commitmentType lnrpc.CommitmentType
private bool
}{
{
name: "anchors",
commitmentType: lnrpc.CommitmentType_ANCHORS,
private: false,
},
{
name: "simple taproot",
commitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT,

// Set this to true once simple taproot channels can be
// announced to the network.
private: true,
},
}

for _, tc := range testCases {
tc := tc

success := ht.T.Run(tc.name, func(tt *testing.T) {
st := ht.Subtest(tt)

args := lntest.NodeArgsForCommitType(tc.commitmentType)

// First, we'll create two new nodes that we'll use to
// open channels between for this test. Dave gets some
// coins that will be used to fund the PSBT, just to
// make sure that Carol has an empty wallet.
carol := st.NewNode("carol", args)
dave := st.NewNode("dave", args)

// We just send enough funds to satisfy the anchor
// channel reserve for 5 channels (50k sats).
st.FundCoins(50_000, carol)
st.FundCoins(50_000, dave)

st.RunTestCase(&lntest.TestCase{
Name: tc.name,
TestFunc: func(sst *lntest.HarnessTest) {
runPsbtChanFunding(
sst, carol, dave, tc.private,
tc.commitmentType,
)
},
})

// Empty out the wallets so there aren't any lingering
// coins.
sendAllCoinsConfirm(st, carol, burnAddr)
sendAllCoinsConfirm(st, dave, burnAddr)

// Now we test the second scenario. Again, we just send
// enough funds to satisfy the anchor channel reserve
// for 5 channels (50k sats).
st.FundCoins(50_000, carol)
st.FundCoins(50_000, dave)

st.RunTestCase(&lntest.TestCase{
Name: tc.name,
TestFunc: func(sst *lntest.HarnessTest) {
runPsbtChanFundingExternal(
sst, carol, dave, tc.private,
tc.commitmentType,
)
},
})

// Empty out the wallets a last time, so there aren't
// any lingering coins.
sendAllCoinsConfirm(st, carol, burnAddr)
sendAllCoinsConfirm(st, dave, burnAddr)

// The last test case tests the anchor channel reserve
// itself, so we need empty wallets.
st.RunTestCase(&lntest.TestCase{
Name: tc.name,
TestFunc: func(sst *lntest.HarnessTest) {
runPsbtChanFundingSingleStep(
sst, carol, dave, tc.private,
tc.commitmentType,
)
},
})
})
if !success {
// Log failure time to help relate the lnd logs to the
// failure.
ht.Logf("Failure time: %v", time.Now().Format(
"2006-01-02 15:04:05.000",
))

break
}
}
}

// runPsbtChanFunding makes sure a channel can be opened between carol and dave
// by using a Partially Signed Bitcoin Transaction that funds the channel
// multisig funding output.
func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode) {
func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode,
private bool, commitType lnrpc.CommitmentType) {

const chanSize = funding.MaxBtcFundingAmount
ht.FundCoins(btcutil.SatoshiPerBitcoin, dave)

Expand Down Expand Up @@ -71,6 +169,8 @@ func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode) {
},
},
},
Private: private,
CommitmentType: commitType,
},
)

Expand All @@ -89,6 +189,10 @@ func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode) {
},
},
},
// We haven't started Alice with the explicit params to
// support the current commit type, so we'll just use
// the default for this channel. That also allows us to
// test batches of different channel types.
},
)

Expand Down Expand Up @@ -224,18 +328,14 @@ func runPsbtChanFunding(ht *lntest.HarnessTest, carol, dave *node.HarnessNode) {
ht.CloseChannel(carol, chanPoint2)
}

// testPsbtChanFundingExternal makes sure a channel can be opened between carol
// runPsbtChanFundingExternal makes sure a channel can be opened between carol
// and dave by using a Partially Signed Bitcoin Transaction that funds the
// channel multisig funding output and is fully funded by an external third
// party.
func testPsbtChanFundingExternal(ht *lntest.HarnessTest) {
const chanSize = funding.MaxBtcFundingAmount
func runPsbtChanFundingExternal(ht *lntest.HarnessTest, carol,
dave *node.HarnessNode, private bool, commitType lnrpc.CommitmentType) {

// First, we'll create two new nodes that we'll use to open channels
// between for this test. Both these nodes have an empty wallet as Alice
// will be funding the channel.
carol := ht.NewNode("carol", nil)
dave := ht.NewNode("dave", nil)
const chanSize = funding.MaxBtcFundingAmount

// Before we start the test, we'll ensure both sides are connected so
// the funding flow can be properly executed.
Expand Down Expand Up @@ -265,6 +365,8 @@ func testPsbtChanFundingExternal(ht *lntest.HarnessTest) {
},
},
},
Private: private,
CommitmentType: commitType,
},
)

Expand All @@ -283,6 +385,10 @@ func testPsbtChanFundingExternal(ht *lntest.HarnessTest) {
},
},
},
// We haven't started Alice with the explicit params to
// support the current commit type, so we'll just use
// the default for this channel. That also allows us to
// test batches of different channel types.
},
)

Expand Down Expand Up @@ -406,20 +512,14 @@ func testPsbtChanFundingExternal(ht *lntest.HarnessTest) {
ht.CloseChannel(carol, chanPoint2)
}

// testPsbtChanFundingSingleStep checks whether PSBT funding works also when
// runPsbtChanFundingSingleStep checks whether PSBT funding works also when
// the wallet of both nodes are empty and one of them uses PSBT and an external
// wallet to fund the channel while creating reserve output in the same
// transaction.
func testPsbtChanFundingSingleStep(ht *lntest.HarnessTest) {
const chanSize = funding.MaxBtcFundingAmount
func runPsbtChanFundingSingleStep(ht *lntest.HarnessTest, carol,
dave *node.HarnessNode, private bool, commitType lnrpc.CommitmentType) {

args := lntest.NodeArgsForCommitType(lnrpc.CommitmentType_ANCHORS)

// First, we'll create two new nodes that we'll use to open channels
// between for this test. But in this case both nodes have an empty
// wallet.
carol := ht.NewNode("carol", args)
dave := ht.NewNode("dave", args)
const chanSize = funding.MaxBtcFundingAmount

alice := ht.Alice
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)
Expand Down Expand Up @@ -458,6 +558,8 @@ func testPsbtChanFundingSingleStep(ht *lntest.HarnessTest) {
},
},
},
Private: private,
CommitmentType: commitType,
},
)

Expand Down
5 changes: 4 additions & 1 deletion itest/lnd_remote_signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ func testRemoteSigner(ht *lntest.HarnessTest) {
name: "psbt",
randomSeed: true,
fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runPsbtChanFunding(tt, carol, wo)
runPsbtChanFunding(
tt, carol, wo, false,
lnrpc.CommitmentType_LEGACY,
)
runSignPsbtSegWitV0P2WKH(tt, wo)
runSignPsbtSegWitV1KeySpendBip86(tt, wo)
runSignPsbtSegWitV1KeySpendRootHash(tt, wo)
Expand Down
18 changes: 18 additions & 0 deletions lntest/harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,7 @@ func (h *HarnessTest) OpenChannelPsbt(srcNode, destNode *node.HarnessNode,
SpendUnconfirmed: p.SpendUnconfirmed,
MinHtlcMsat: int64(p.MinHtlc),
FundingShim: p.FundingShim,
CommitmentType: p.CommitmentType,
}
respStream := srcNode.RPC.OpenChannel(req)

Expand All @@ -1476,6 +1477,23 @@ func (h *HarnessTest) OpenChannelPsbt(srcNode, destNode *node.HarnessNode,
upd, ok := resp.Update.(*lnrpc.OpenStatusUpdate_PsbtFund)
require.Truef(h, ok, "expected PSBT funding update, got %v", resp)

// Make sure the channel funding address has the correct type for the
// given commitment type.
fundingAddr, err := btcutil.DecodeAddress(
upd.PsbtFund.FundingAddress, harnessNetParams,
)
require.NoError(h, err)

switch p.CommitmentType {
case lnrpc.CommitmentType_SIMPLE_TAPROOT:
require.IsType(h, &btcutil.AddressTaproot{}, fundingAddr)

default:
require.IsType(
h, &btcutil.AddressWitnessScriptHash{}, fundingAddr,
)
}

return respStream, upd.PsbtFund.Psbt
}

Expand Down

0 comments on commit 590dc0c

Please sign in to comment.