6
6
"testing"
7
7
"time"
8
8
9
+ "github.com/btcsuite/btcd/btcec/v2"
9
10
"github.com/btcsuite/btcd/btcutil"
10
11
"github.com/btcsuite/btcd/chaincfg/chainhash"
11
12
"github.com/btcsuite/btcd/txscript"
@@ -241,16 +242,14 @@ func basicChannelFundingTest(ht *lntest.HarnessTest,
241
242
// open or an error occurs in the funding process. A series of
242
243
// assertions will be executed to ensure the funding process completed
243
244
// successfully.
244
- chanPoint := ht .OpenChannel (
245
- alice , bob , lntest.OpenChannelParams {
246
- Private : privateChan ,
247
- Amt : chanAmt ,
248
- PushAmt : pushAmt ,
249
- FundingShim : fundingShim ,
250
- SatPerVByte : satPerVbyte ,
251
- CommitmentType : commitTypeParam ,
252
- },
253
- )
245
+ chanPoint := ht .OpenChannel (alice , bob , lntest.OpenChannelParams {
246
+ Private : privateChan ,
247
+ Amt : chanAmt ,
248
+ PushAmt : pushAmt ,
249
+ FundingShim : fundingShim ,
250
+ SatPerVByte : satPerVbyte ,
251
+ CommitmentType : commitTypeParam ,
252
+ })
254
253
255
254
cType := ht .GetChannelCommitType (alice , chanPoint )
256
255
@@ -541,10 +540,19 @@ func sendAllCoinsConfirm(ht *lntest.HarnessTest, node *node.HarnessNode,
541
540
// channel funding workflow given a channel point that was constructed outside
542
541
// the main daemon.
543
542
func testExternalFundingChanPoint (ht * lntest.HarnessTest ) {
543
+ runExternalFundingScriptEnforced (ht )
544
+ runExternalFundingTaproot (ht )
545
+ }
546
+
547
+ // runExternalFundingChanPoint runs the actual test that tests we're able to
548
+ // carry out a normal channel funding workflow given a channel point that was
549
+ // constructed outside the main daemon for the script enforced channel type.
550
+ func runExternalFundingScriptEnforced (ht * lntest.HarnessTest ) {
544
551
// First, we'll create two new nodes that we'll use to open channel
545
552
// between for this test.
546
553
carol := ht .NewNode ("carol" , nil )
547
554
dave := ht .NewNode ("dave" , nil )
555
+ commitmentType := lnrpc .CommitmentType_SCRIPT_ENFORCED_LEASE
548
556
549
557
// Carol will be funding the channel, so we'll send some coins over to
550
558
// her and ensure they have enough confirmations before we proceed.
@@ -560,7 +568,7 @@ func testExternalFundingChanPoint(ht *lntest.HarnessTest) {
560
568
const thawHeight uint32 = 10
561
569
const chanSize = funding .MaxBtcFundingAmount
562
570
fundingShim1 , chanPoint1 := deriveFundingShim (
563
- ht , carol , dave , chanSize , thawHeight , false ,
571
+ ht , carol , dave , chanSize , thawHeight , false , commitmentType ,
564
572
)
565
573
ht .OpenChannelAssertPending (
566
574
carol , dave , lntest.OpenChannelParams {
@@ -576,7 +584,7 @@ func testExternalFundingChanPoint(ht *lntest.HarnessTest) {
576
584
// do exactly that now. For this one we publish the transaction so we
577
585
// can mine it later.
578
586
fundingShim2 , chanPoint2 := deriveFundingShim (
579
- ht , carol , dave , chanSize , thawHeight , true ,
587
+ ht , carol , dave , chanSize , thawHeight , true , commitmentType ,
580
588
)
581
589
582
590
// At this point, we'll now carry out the normal basic channel funding
@@ -648,6 +656,159 @@ func testExternalFundingChanPoint(ht *lntest.HarnessTest) {
648
656
ht .AssertNodesNumPendingOpenChannels (carol , dave , 0 )
649
657
}
650
658
659
+ // runExternalFundingTaproot runs the actual test that tests we're able to carry
660
+ // out a normal channel funding workflow given a channel point that was
661
+ // constructed outside the main daemon for the taproot channel type.
662
+ func runExternalFundingTaproot (ht * lntest.HarnessTest ) {
663
+ // First, we'll create two new nodes that we'll use to open channel
664
+ // between for this test.
665
+ commitmentType := lnrpc .CommitmentType_SIMPLE_TAPROOT
666
+ args := lntest .NodeArgsForCommitType (commitmentType )
667
+ carol := ht .NewNode ("carol" , args )
668
+
669
+ // We'll attempt two channels, so Dave will need to accept two pending
670
+ // ones.
671
+ dave := ht .NewNode ("dave" , append (args , "--maxpendingchannels=2" ))
672
+
673
+ // Carol will be funding the channel, so we'll send some coins over to
674
+ // her and ensure they have enough confirmations before we proceed.
675
+ ht .FundCoins (btcutil .SatoshiPerBitcoin , carol )
676
+
677
+ // Before we start the test, we'll ensure both sides are connected to
678
+ // the funding flow can properly be executed.
679
+ ht .EnsureConnected (carol , dave )
680
+
681
+ // At this point, we're ready to simulate our external channel funding
682
+ // flow. To start with, we'll create a pending channel with a shim for
683
+ // a transaction that will never be published.
684
+ const thawHeight uint32 = 10
685
+ const chanSize = funding .MaxBtcFundingAmount
686
+ fundingShim1 , chanPoint1 := deriveFundingShim (
687
+ ht , carol , dave , chanSize , thawHeight , false , commitmentType ,
688
+ )
689
+ ht .OpenChannelAssertPending (carol , dave , lntest.OpenChannelParams {
690
+ Amt : chanSize ,
691
+ FundingShim : fundingShim1 ,
692
+ CommitmentType : commitmentType ,
693
+ Private : true ,
694
+ })
695
+ ht .AssertNodesNumPendingOpenChannels (carol , dave , 1 )
696
+
697
+ // That channel is now pending forever and normally would saturate the
698
+ // max pending channel limit for both nodes. But because the channel is
699
+ // externally funded, we should still be able to open another one. Let's
700
+ // do exactly that now. For this one we publish the transaction so we
701
+ // can mine it later.
702
+ fundingShim2 , chanPoint2 := deriveFundingShim (
703
+ ht , carol , dave , chanSize , thawHeight , true , commitmentType ,
704
+ )
705
+
706
+ // At this point, we'll now carry out the normal basic channel funding
707
+ // test as everything should now proceed as normal (a regular channel
708
+ // funding flow).
709
+ carolChan , daveChan , _ := basicChannelFundingTest (
710
+ ht , carol , dave , fundingShim2 , true , & commitmentType ,
711
+ )
712
+
713
+ // The itest harness doesn't mine blocks for private channels, so we
714
+ // want to make sure the channel with the published and mined
715
+ // transaction leaves the pending state.
716
+ ht .MineBlocks (6 )
717
+
718
+ rpcChanPointToStr := func (cp * lnrpc.ChannelPoint ) string {
719
+ txid , err := chainhash .NewHash (cp .GetFundingTxidBytes ())
720
+ require .NoError (ht , err )
721
+ return fmt .Sprintf ("%v:%d" , txid .String (), cp .OutputIndex )
722
+ }
723
+
724
+ pendingCarol := carol .RPC .PendingChannels ().PendingOpenChannels
725
+ require .Len (ht , pendingCarol , 1 )
726
+ require .Equal (
727
+ ht , rpcChanPointToStr (chanPoint1 ),
728
+ pendingCarol [0 ].Channel .ChannelPoint ,
729
+ )
730
+ openCarol := carol .RPC .ListChannels (& lnrpc.ListChannelsRequest {
731
+ ActiveOnly : true ,
732
+ PrivateOnly : true ,
733
+ })
734
+ require .Len (ht , openCarol .Channels , 1 )
735
+ require .Equal (
736
+ ht , rpcChanPointToStr (chanPoint2 ),
737
+ openCarol .Channels [0 ].ChannelPoint ,
738
+ )
739
+
740
+ pendingDave := dave .RPC .PendingChannels ().PendingOpenChannels
741
+ require .Len (ht , pendingDave , 1 )
742
+ require .Equal (
743
+ ht , rpcChanPointToStr (chanPoint1 ),
744
+ pendingDave [0 ].Channel .ChannelPoint ,
745
+ )
746
+
747
+ openDave := dave .RPC .ListChannels (& lnrpc.ListChannelsRequest {
748
+ ActiveOnly : true ,
749
+ PrivateOnly : true ,
750
+ })
751
+ require .Len (ht , openDave .Channels , 1 )
752
+ require .Equal (
753
+ ht , rpcChanPointToStr (chanPoint2 ),
754
+ openDave .Channels [0 ].ChannelPoint ,
755
+ )
756
+
757
+ // Both channels should be marked as frozen with the proper thaw height.
758
+ require .EqualValues (ht , thawHeight , carolChan .ThawHeight , "thaw height" )
759
+ require .EqualValues (ht , thawHeight , daveChan .ThawHeight , "thaw height" )
760
+
761
+ // Next, to make sure the channel functions as normal, we'll make some
762
+ // payments within the channel.
763
+ payAmt := btcutil .Amount (100000 )
764
+ invoice := & lnrpc.Invoice {
765
+ Memo : "new chans" ,
766
+ Value : int64 (payAmt ),
767
+ }
768
+ resp := dave .RPC .AddInvoice (invoice )
769
+ ht .CompletePaymentRequests (carol , []string {resp .PaymentRequest })
770
+
771
+ // Now that the channels are open, and we've confirmed that they're
772
+ // operational, we'll now ensure that the channels are frozen as
773
+ // intended (if requested).
774
+ //
775
+ // First, we'll try to close the channel as Carol, the initiator. This
776
+ // should fail as a frozen channel only allows the responder to
777
+ // initiate a channel close.
778
+ err := ht .CloseChannelAssertErr (carol , chanPoint2 , false )
779
+ require .Contains (ht , err .Error (), "cannot co-op close frozen channel" )
780
+
781
+ // Before Dave closes the channel, he needs to check the invoice is
782
+ // settled to avoid an error saying cannot close channel due to active
783
+ // HTLCs.
784
+ ht .AssertInvoiceSettled (dave , resp .PaymentAddr )
785
+
786
+ // TODO(yy): remove the sleep once the following bug is fixed.
787
+ // When the invoice is reported settled, the commitment dance is not
788
+ // yet finished, which can cause an error when closing the channel,
789
+ // saying there's active HTLCs. We need to investigate this issue and
790
+ // reverse the order to, first finish the commitment dance, then report
791
+ // the invoice as settled.
792
+ time .Sleep (2 * time .Second )
793
+
794
+ // Next we'll try but this time with Dave (the responder) as the
795
+ // initiator. This time the channel should be closed as normal.
796
+ ht .CloseChannel (dave , chanPoint2 )
797
+
798
+ // Let's make sure we can abandon it.
799
+ carol .RPC .AbandonChannel (& lnrpc.AbandonChannelRequest {
800
+ ChannelPoint : chanPoint1 ,
801
+ PendingFundingShimOnly : true ,
802
+ })
803
+ dave .RPC .AbandonChannel (& lnrpc.AbandonChannelRequest {
804
+ ChannelPoint : chanPoint1 ,
805
+ PendingFundingShimOnly : true ,
806
+ })
807
+
808
+ // It should now not appear in the pending channels anymore.
809
+ ht .AssertNodesNumPendingOpenChannels (carol , dave , 0 )
810
+ }
811
+
651
812
// testFundingPersistence is intended to ensure that the Funding Manager
652
813
// persists the state of new channels prior to broadcasting the channel's
653
814
// funding transaction. This ensures that the daemon maintains an up-to-date
@@ -977,9 +1138,9 @@ func ensurePolicy(ht *lntest.HarnessTest, alice, peer *node.HarnessNode,
977
1138
978
1139
// deriveFundingShim creates a channel funding shim by deriving the necessary
979
1140
// keys on both sides.
980
- func deriveFundingShim (ht * lntest.HarnessTest ,
981
- carol , dave * node. HarnessNode , chanSize btcutil. Amount ,
982
- thawHeight uint32 , publish bool ) (* lnrpc.FundingShim ,
1141
+ func deriveFundingShim (ht * lntest.HarnessTest , carol , dave * node. HarnessNode ,
1142
+ chanSize btcutil. Amount , thawHeight uint32 , publish bool ,
1143
+ commitType lnrpc. CommitmentType ) (* lnrpc.FundingShim ,
983
1144
* lnrpc.ChannelPoint ) {
984
1145
985
1146
keyLoc := & signrpc.KeyLocator {KeyFamily : 9999 }
@@ -991,11 +1152,31 @@ func deriveFundingShim(ht *lntest.HarnessTest,
991
1152
// immediately create and broadcast a transaction paying out an exact
992
1153
// amount. Normally this would reside in the mempool, but we just
993
1154
// confirm it now for simplicity.
994
- _ , fundingOutput , err := input .GenFundingPkScript (
995
- carolFundingKey .RawKeyBytes , daveFundingKey .RawKeyBytes ,
996
- int64 (chanSize ),
1155
+ var (
1156
+ fundingOutput * wire.TxOut
1157
+ musig2 bool
1158
+ err error
997
1159
)
998
- require .NoError (ht , err )
1160
+ if commitType == lnrpc .CommitmentType_SIMPLE_TAPROOT {
1161
+ var carolKey , daveKey * btcec.PublicKey
1162
+ carolKey , err = btcec .ParsePubKey (carolFundingKey .RawKeyBytes )
1163
+ require .NoError (ht , err )
1164
+ daveKey , err = btcec .ParsePubKey (daveFundingKey .RawKeyBytes )
1165
+ require .NoError (ht , err )
1166
+
1167
+ _ , fundingOutput , err = input .GenTaprootFundingScript (
1168
+ carolKey , daveKey , int64 (chanSize ),
1169
+ )
1170
+ require .NoError (ht , err )
1171
+
1172
+ musig2 = true
1173
+ } else {
1174
+ _ , fundingOutput , err = input .GenFundingPkScript (
1175
+ carolFundingKey .RawKeyBytes , daveFundingKey .RawKeyBytes ,
1176
+ int64 (chanSize ),
1177
+ )
1178
+ require .NoError (ht , err )
1179
+ }
999
1180
1000
1181
var txid * chainhash.Hash
1001
1182
targetOutputs := []* wire.TxOut {fundingOutput }
@@ -1034,6 +1215,7 @@ func deriveFundingShim(ht *lntest.HarnessTest,
1034
1215
RemoteKey : carolFundingKey .RawKeyBytes ,
1035
1216
PendingChanId : pendingChanID ,
1036
1217
ThawHeight : thawHeight ,
1218
+ Musig2 : musig2 ,
1037
1219
}
1038
1220
fundingShim := & lnrpc.FundingShim {
1039
1221
Shim : & lnrpc.FundingShim_ChanPointShim {
0 commit comments