mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
funding: add unit tests for reg+zero conf taproot chans
This commit is contained in:
parent
91e855d59a
commit
9f6ed65d80
@ -33,6 +33,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntest/mock"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
@ -384,9 +385,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
|
||||
wc := &mock.WalletController{
|
||||
RootKey: alicePrivKey,
|
||||
}
|
||||
signer := &mock.SingleSigner{
|
||||
Privkey: alicePrivKey,
|
||||
}
|
||||
signer := mock.NewSingleSigner(alicePrivKey)
|
||||
bio := &mock.ChainIO{
|
||||
BestHeight: fundingBroadcastHeight,
|
||||
}
|
||||
@ -720,12 +719,13 @@ func tearDownFundingManagers(t *testing.T, a, b *testNode) {
|
||||
// transaction is confirmed on-chain. Returns the funding out point.
|
||||
func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
|
||||
pushAmt btcutil.Amount, numConfs uint32,
|
||||
updateChan chan *lnrpc.OpenStatusUpdate, announceChan bool) (
|
||||
updateChan chan *lnrpc.OpenStatusUpdate, announceChan bool,
|
||||
chanType *lnwire.ChannelType) (
|
||||
*wire.OutPoint, *wire.MsgTx) {
|
||||
|
||||
publ := fundChannel(
|
||||
t, alice, bob, localFundingAmt, pushAmt, false, 0, 0, numConfs,
|
||||
updateChan, announceChan, nil,
|
||||
updateChan, announceChan, chanType,
|
||||
)
|
||||
fundingOutPoint := &wire.OutPoint{
|
||||
Hash: publ.TxHash(),
|
||||
@ -734,6 +734,18 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
|
||||
return fundingOutPoint, publ
|
||||
}
|
||||
|
||||
func isTaprootChanType(chanType *lnwire.ChannelType) bool {
|
||||
if chanType == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
featVec := lnwire.RawFeatureVector(*chanType)
|
||||
|
||||
return featVec.IsSet(
|
||||
lnwire.SimpleTaprootChannelsRequired,
|
||||
)
|
||||
}
|
||||
|
||||
// fundChannel takes the funding process to the point where the funding
|
||||
// transaction is confirmed on-chain. Returns the funding tx.
|
||||
func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
|
||||
@ -761,6 +773,12 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
|
||||
Err: errChan,
|
||||
}
|
||||
|
||||
// If this is a taproot channel, then we want to force it to be a
|
||||
// private channel, as that's the only channel type supported for now.
|
||||
if isTaprootChanType(chanType) {
|
||||
initReq.Private = true
|
||||
}
|
||||
|
||||
alice.fundingMgr.InitFundingWorkflow(initReq)
|
||||
|
||||
// Alice should have sent the OpenChannel message to Bob.
|
||||
@ -785,6 +803,11 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
|
||||
"alice, instead got %T", aliceMsg)
|
||||
}
|
||||
|
||||
// For taproot channel types, the nonce should be set.
|
||||
if isTaprootChanType(chanType) {
|
||||
require.NotNil(t, openChannelReq.LocalNonce)
|
||||
}
|
||||
|
||||
// Let Bob handle the init message.
|
||||
bob.fundingMgr.ProcessFundingMsg(openChannelReq, alice)
|
||||
|
||||
@ -793,6 +816,11 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
|
||||
t, bob.msgChan, "AcceptChannel",
|
||||
).(*lnwire.AcceptChannel)
|
||||
|
||||
// For taproot channel types, the nonce should be set.
|
||||
if isTaprootChanType(chanType) {
|
||||
require.NotNil(t, acceptChannelResponse.LocalNonce)
|
||||
}
|
||||
|
||||
// They now should both have pending reservations for this channel
|
||||
// active.
|
||||
assertNumPendingReservations(t, alice, bobPubKey, 1)
|
||||
@ -814,6 +842,11 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
|
||||
t, alice.msgChan, "FundingCreated",
|
||||
).(*lnwire.FundingCreated)
|
||||
|
||||
// For taproot channel types, the partial signature should be set.
|
||||
if isTaprootChanType(chanType) {
|
||||
require.NotNil(t, fundingCreated.PartialSig)
|
||||
}
|
||||
|
||||
// Give the message to Bob.
|
||||
bob.fundingMgr.ProcessFundingMsg(fundingCreated, alice)
|
||||
|
||||
@ -822,6 +855,11 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt,
|
||||
t, bob.msgChan, "FundingSigned",
|
||||
).(*lnwire.FundingSigned)
|
||||
|
||||
// For taproot channel types, the partial signature should be set.
|
||||
if isTaprootChanType(chanType) {
|
||||
require.NotNil(t, fundingSigned.PartialSig)
|
||||
}
|
||||
|
||||
// Forward the signature to Alice.
|
||||
alice.fundingMgr.ProcessFundingMsg(fundingSigned, bob)
|
||||
|
||||
@ -1244,6 +1282,25 @@ func assertAnnouncementSignatures(t *testing.T, alice, bob *testNode) {
|
||||
}
|
||||
}
|
||||
|
||||
func assertType[T any](t *testing.T, typ any) T {
|
||||
value, ok := typ.(T)
|
||||
require.True(t, ok)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func assertNodeAnnSent(t *testing.T, alice, bob *testNode) {
|
||||
t.Helper()
|
||||
|
||||
for _, node := range []*testNode{alice, bob} {
|
||||
nodeAnn, err := lnutils.RecvOrTimeout(
|
||||
node.msgChan, time.Second*5,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assertType[*lnwire.NodeAnnouncement](t, *nodeAnn)
|
||||
}
|
||||
}
|
||||
|
||||
func waitForOpenUpdate(t *testing.T, updateChan chan *lnrpc.OpenStatusUpdate) {
|
||||
var openUpdate *lnrpc.OpenStatusUpdate
|
||||
select {
|
||||
@ -1349,14 +1406,31 @@ func assertHandleChannelReady(t *testing.T, alice, bob *testNode,
|
||||
}
|
||||
}
|
||||
|
||||
func TestFundingManagerNormalWorkflow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
func testNormalWorkflow(t *testing.T, chanType *lnwire.ChannelType) {
|
||||
alice, bob := setupFundingManagers(t)
|
||||
t.Cleanup(func() {
|
||||
tearDownFundingManagers(t, alice, bob)
|
||||
})
|
||||
|
||||
// If the channel type is set, then we need to make sure both parties
|
||||
// support explicit channel type negotiation.
|
||||
if chanType != nil {
|
||||
// Alice and Bob will have the same set of feature bits in our
|
||||
// test.
|
||||
featureBits := []lnwire.FeatureBit{
|
||||
lnwire.ZeroConfOptional,
|
||||
lnwire.ScidAliasOptional,
|
||||
lnwire.ExplicitChannelTypeOptional,
|
||||
lnwire.StaticRemoteKeyOptional,
|
||||
lnwire.AnchorsZeroFeeHtlcTxOptional,
|
||||
lnwire.SimpleTaprootChannelsOptional,
|
||||
}
|
||||
alice.localFeatures = featureBits
|
||||
alice.remoteFeatures = featureBits
|
||||
bob.localFeatures = featureBits
|
||||
bob.remoteFeatures = featureBits
|
||||
}
|
||||
|
||||
// We will consume the channel updates as we go, so no buffering is
|
||||
// needed.
|
||||
updateChan := make(chan *lnrpc.OpenStatusUpdate)
|
||||
@ -1368,6 +1442,7 @@ func TestFundingManagerNormalWorkflow(t *testing.T) {
|
||||
capacity := localAmt + pushAmt
|
||||
fundingOutPoint, fundingTx := openChannel(
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true,
|
||||
chanType,
|
||||
)
|
||||
|
||||
// Check that neither Alice nor Bob sent an error message.
|
||||
@ -1400,6 +1475,13 @@ func TestFundingManagerNormalWorkflow(t *testing.T) {
|
||||
).(*lnwire.ChannelReady)
|
||||
require.True(t, ok)
|
||||
|
||||
// For taproot channels, the funding locked messages should have the
|
||||
// next set of verification nonces.
|
||||
if isTaprootChanType(chanType) {
|
||||
require.NotNil(t, channelReadyAlice.NextLocalNonce)
|
||||
require.NotNil(t, channelReadyBob.NextLocalNonce)
|
||||
}
|
||||
|
||||
// Check that the state machine is updated accordingly
|
||||
assertChannelReadySent(t, alice, bob, fundingOutPoint)
|
||||
|
||||
@ -1431,8 +1513,20 @@ func TestFundingManagerNormalWorkflow(t *testing.T) {
|
||||
Tx: fundingTx,
|
||||
}
|
||||
|
||||
// Make sure the fundingManagers exchange announcement signatures.
|
||||
assertAnnouncementSignatures(t, alice, bob)
|
||||
switch {
|
||||
// For taproot channels, we expect them to only send a node
|
||||
// announcement message at this point. These channels aren't advertised
|
||||
// so we don't expect the other messages.
|
||||
case isTaprootChanType(chanType):
|
||||
assertNodeAnnSent(t, alice, bob)
|
||||
|
||||
// For regular channels, we'll make sure the fundingManagers exchange
|
||||
// announcement signatures.
|
||||
case chanType == nil:
|
||||
fallthrough
|
||||
default:
|
||||
assertAnnouncementSignatures(t, alice, bob)
|
||||
}
|
||||
|
||||
// The internal state-machine should now have deleted the channelStates
|
||||
// from the database, as the channel is announced.
|
||||
@ -1443,6 +1537,37 @@ func TestFundingManagerNormalWorkflow(t *testing.T) {
|
||||
assertNoFwdingPolicy(t, alice, bob, channelReadyAlice.ChanID)
|
||||
}
|
||||
|
||||
// TestFundingManagerNormalWorkflow tests that the funding manager is able to
|
||||
// do a routine channel funding flow back and forth.
|
||||
func TestFundingManagerNormalWorkflow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
taprootChanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector(
|
||||
lnwire.SimpleTaprootChannelsRequired,
|
||||
))
|
||||
|
||||
testCases := []struct {
|
||||
typeName string
|
||||
chanType *lnwire.ChannelType
|
||||
}{
|
||||
{
|
||||
typeName: "normal",
|
||||
chanType: nil,
|
||||
},
|
||||
{
|
||||
typeName: "taproot",
|
||||
chanType: &taprootChanType,
|
||||
},
|
||||
}
|
||||
|
||||
//nolint:paralleltest
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.typeName, func(t *testing.T) {
|
||||
testNormalWorkflow(t, testCase.chanType)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestFundingManagerRejectCSV tests checking of local CSV values against our
|
||||
// local CSV limit for incoming and outgoing channels.
|
||||
func TestFundingManagerRejectCSV(t *testing.T) {
|
||||
@ -1617,6 +1742,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
|
||||
updateChan := make(chan *lnrpc.OpenStatusUpdate)
|
||||
fundingOutPoint, fundingTx := openChannel(
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true,
|
||||
nil,
|
||||
)
|
||||
|
||||
// After the funding transaction gets mined, both nodes will send the
|
||||
@ -1775,6 +1901,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
|
||||
updateChan := make(chan *lnrpc.OpenStatusUpdate)
|
||||
fundingOutPoint, fundingTx := openChannel(
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true,
|
||||
nil,
|
||||
)
|
||||
|
||||
// After the funding transaction gets mined, both nodes will send the
|
||||
@ -2160,7 +2287,7 @@ func TestFundingManagerFundingTimeout(t *testing.T) {
|
||||
|
||||
// Run through the process of opening the channel, up until the funding
|
||||
// transaction is broadcasted.
|
||||
_, _ = openChannel(t, alice, bob, 500000, 0, 1, updateChan, true)
|
||||
_, _ = openChannel(t, alice, bob, 500000, 0, 1, updateChan, true, nil)
|
||||
|
||||
// Bob will at this point be waiting for the funding transaction to be
|
||||
// confirmed, so the channel should be considered pending.
|
||||
@ -2208,7 +2335,7 @@ func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) {
|
||||
|
||||
// Run through the process of opening the channel, up until the funding
|
||||
// transaction is broadcasted.
|
||||
_, _ = openChannel(t, alice, bob, 500000, 0, 1, updateChan, true)
|
||||
_, _ = openChannel(t, alice, bob, 500000, 0, 1, updateChan, true, nil)
|
||||
|
||||
// Alice will at this point be waiting for the funding transaction to be
|
||||
// confirmed, so the channel should be considered pending.
|
||||
@ -2285,7 +2412,7 @@ func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) {
|
||||
pushAmt := btcutil.Amount(0)
|
||||
capacity := localAmt + pushAmt
|
||||
fundingOutPoint, fundingTx := openChannel(
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true,
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true, nil,
|
||||
)
|
||||
|
||||
// Notify that transaction was mined
|
||||
@ -2398,7 +2525,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) {
|
||||
pushAmt := btcutil.Amount(0)
|
||||
capacity := localAmt + pushAmt
|
||||
fundingOutPoint, fundingTx := openChannel(
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true,
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true, nil,
|
||||
)
|
||||
|
||||
// Notify that transaction was mined
|
||||
@ -2497,7 +2624,7 @@ func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) {
|
||||
pushAmt := btcutil.Amount(0)
|
||||
capacity := localAmt + pushAmt
|
||||
fundingOutPoint, fundingTx := openChannel(
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true,
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, true, nil,
|
||||
)
|
||||
|
||||
// Notify that transaction was mined
|
||||
@ -2592,7 +2719,7 @@ func TestFundingManagerPrivateChannel(t *testing.T) {
|
||||
pushAmt := btcutil.Amount(0)
|
||||
capacity := localAmt + pushAmt
|
||||
fundingOutPoint, fundingTx := openChannel(
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, false,
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, false, nil,
|
||||
)
|
||||
|
||||
// Notify that transaction was mined
|
||||
@ -2717,7 +2844,7 @@ func TestFundingManagerPrivateRestart(t *testing.T) {
|
||||
pushAmt := btcutil.Amount(0)
|
||||
capacity := localAmt + pushAmt
|
||||
fundingOutPoint, fundingTx := openChannel(
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, false,
|
||||
t, alice, bob, localAmt, pushAmt, 1, updateChan, false, nil,
|
||||
)
|
||||
|
||||
// Notify that transaction was mined
|
||||
@ -4320,11 +4447,7 @@ func testUpfrontFailure(t *testing.T, pkscript []byte, expectErr bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestFundingManagerZeroConf tests that the fundingmanager properly handles
|
||||
// the whole flow for zero-conf channels.
|
||||
func TestFundingManagerZeroConf(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
func testZeroConf(t *testing.T, chanType *lnwire.ChannelType) {
|
||||
alice, bob := setupFundingManagers(t)
|
||||
t.Cleanup(func() {
|
||||
tearDownFundingManagers(t, alice, bob)
|
||||
@ -4337,6 +4460,7 @@ func TestFundingManagerZeroConf(t *testing.T) {
|
||||
lnwire.ExplicitChannelTypeOptional,
|
||||
lnwire.StaticRemoteKeyOptional,
|
||||
lnwire.AnchorsZeroFeeHtlcTxOptional,
|
||||
lnwire.SimpleTaprootChannelsOptional,
|
||||
}
|
||||
alice.localFeatures = featureBits
|
||||
alice.remoteFeatures = featureBits
|
||||
@ -4348,11 +4472,20 @@ func TestFundingManagerZeroConf(t *testing.T) {
|
||||
updateChan := make(chan *lnrpc.OpenStatusUpdate)
|
||||
|
||||
// Construct the zero-conf ChannelType for use in open_channel.
|
||||
channelTypeBits := []lnwire.FeatureBit{
|
||||
lnwire.ZeroConfRequired,
|
||||
lnwire.StaticRemoteKeyRequired,
|
||||
lnwire.AnchorsZeroFeeHtlcTxRequired,
|
||||
var channelTypeBits []lnwire.FeatureBit
|
||||
if isTaprootChanType(chanType) {
|
||||
channelTypeBits = []lnwire.FeatureBit{
|
||||
lnwire.ZeroConfRequired,
|
||||
lnwire.SimpleTaprootChannelsRequired,
|
||||
}
|
||||
} else {
|
||||
channelTypeBits = []lnwire.FeatureBit{
|
||||
lnwire.ZeroConfRequired,
|
||||
lnwire.StaticRemoteKeyRequired,
|
||||
lnwire.AnchorsZeroFeeHtlcTxRequired,
|
||||
}
|
||||
}
|
||||
|
||||
channelType := lnwire.ChannelType(
|
||||
*lnwire.NewRawFeatureVector(channelTypeBits...),
|
||||
)
|
||||
@ -4425,9 +4558,12 @@ func TestFundingManagerZeroConf(t *testing.T) {
|
||||
Tx: fundingTx,
|
||||
}
|
||||
|
||||
assertChannelAnnouncements(
|
||||
t, alice, bob, fundingAmt, nil, nil, nil, nil,
|
||||
)
|
||||
// For taproot channels, we don't expect them to be announced atm.
|
||||
if !isTaprootChanType(chanType) {
|
||||
assertChannelAnnouncements(
|
||||
t, alice, bob, fundingAmt, nil, nil, nil, nil,
|
||||
)
|
||||
}
|
||||
|
||||
// Both Alice and Bob should send on reportScidChan.
|
||||
select {
|
||||
@ -4451,7 +4587,20 @@ func TestFundingManagerZeroConf(t *testing.T) {
|
||||
Tx: fundingTx,
|
||||
}
|
||||
|
||||
assertAnnouncementSignatures(t, alice, bob)
|
||||
switch {
|
||||
// For taproot channels, we expect them to only send a node
|
||||
// announcement message at this point. These channels aren't advertised
|
||||
// so we don't expect the other messages.
|
||||
case isTaprootChanType(chanType):
|
||||
assertNodeAnnSent(t, alice, bob)
|
||||
|
||||
// For regular channels, we'll make sure the fundingManagers exchange
|
||||
// announcement signatures.
|
||||
case chanType == nil:
|
||||
fallthrough
|
||||
default:
|
||||
assertAnnouncementSignatures(t, alice, bob)
|
||||
}
|
||||
|
||||
// Assert that the channel state is deleted from the fundingmanager's
|
||||
// datastore.
|
||||
@ -4552,3 +4701,34 @@ func TestFundingManagerNoEchoChanType(t *testing.T) {
|
||||
alice.fundingMgr.ProcessFundingMsg(acceptChanMsg, bob)
|
||||
assertFundingMsgSent(t, alice.msgChan, "Error")
|
||||
}
|
||||
|
||||
// TestFundingManagerZeroConf tests that the fundingmanager properly handles
|
||||
// the whole flow for zero-conf channels.
|
||||
func TestFundingManagerZeroConf(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
taprootChanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector(
|
||||
lnwire.SimpleTaprootChannelsRequired,
|
||||
))
|
||||
|
||||
testCases := []struct {
|
||||
typeName string
|
||||
chanType *lnwire.ChannelType
|
||||
}{
|
||||
{
|
||||
typeName: "normal",
|
||||
chanType: nil,
|
||||
},
|
||||
{
|
||||
typeName: "taproot",
|
||||
chanType: &taprootChanType,
|
||||
},
|
||||
}
|
||||
|
||||
//nolint:paralleltest
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.typeName, func(t *testing.T) {
|
||||
testZeroConf(t, testCase.chanType)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user