@@ -7,12 +7,15 @@ import (
7
7
"fmt"
8
8
"net/url"
9
9
"testing"
10
+ "time"
10
11
11
12
"github.com/btcsuite/btcd/btcec/v2/schnorr"
12
13
"github.com/btcsuite/btcd/btcutil"
13
14
"github.com/btcsuite/btcd/btcutil/hdkeychain"
14
15
"github.com/btcsuite/btcd/btcutil/psbt"
16
+ "github.com/btcsuite/btcd/chaincfg/chainhash"
15
17
"github.com/btcsuite/btcd/txscript"
18
+ "github.com/btcsuite/btcd/wire"
16
19
"github.com/btcsuite/btcwallet/waddrmgr"
17
20
"github.com/davecgh/go-spew/spew"
18
21
"github.com/lightninglabs/taproot-assets/address"
@@ -2611,18 +2614,80 @@ func testPsbtExternalCommit(t *harnessTest) {
2611
2614
2612
2615
btcPacket = signPacket (t .t , aliceLnd , btcPacket )
2613
2616
btcPacket = FinalizePacket (t .t , aliceLnd .RPC , btcPacket )
2617
+
2618
+ transferLabel := "itest-psbt-external-commit"
2619
+
2620
+ // Subscribe to the send event stream so we can verify the sender's
2621
+ // state transitions during this test.
2622
+ ctx , streamCancel := context .WithCancel (ctxb )
2623
+ stream , err := aliceTapd .SubscribeSendEvents (
2624
+ ctx , & taprpc.SubscribeSendEventsRequest {
2625
+ FilterLabel : transferLabel ,
2626
+ },
2627
+ )
2628
+ require .NoError (t .t , err )
2629
+ sendEvents := & EventSubscription [* taprpc.SendEvent ]{
2630
+ ClientEventStream : stream ,
2631
+ Cancel : streamCancel ,
2632
+ }
2633
+
2634
+ // Execute the transfer but skip anchor transaction broadcast. This
2635
+ // simulates a packaging workflow where broadcasting is handled
2636
+ // externally.
2614
2637
sendResp := PublishAndLogTransfer (
2615
2638
t .t , aliceTapd , btcPacket , activeAssets , passiveAssets ,
2616
- commitResp ,
2639
+ commitResp , withSkipAnchorTxBroadcast (),
2640
+ withLabel (transferLabel ),
2617
2641
)
2618
2642
2643
+ // Assert that the state machine transitions directly to waiting for
2644
+ // tx confirmation, skipping the broadcast state.
2645
+ require .Eventually (t .t , func () bool {
2646
+ isMatchingState := func (msg * taprpc.SendEvent ) bool {
2647
+ lastState := tapfreighter .SendStateStorePreBroadcast
2648
+ nextState := tapfreighter .SendStateWaitTxConf
2649
+
2650
+ return msg .SendState == lastState .String () &&
2651
+ msg .NextSendState == nextState .String ()
2652
+ }
2653
+
2654
+ for {
2655
+ msg , err := sendEvents .Recv ()
2656
+ if err != nil {
2657
+ return false
2658
+ }
2659
+
2660
+ return isMatchingState (msg )
2661
+ }
2662
+ }, defaultWaitTimeout , time .Second )
2663
+
2664
+ // Unmarshal the anchor transaction.
2665
+ var anchorTx wire.MsgTx
2666
+ reader := bytes .NewReader (sendResp .Transfer .AnchorTx )
2667
+ err = anchorTx .Deserialize (reader )
2668
+ require .NoError (t .t , err )
2669
+
2670
+ // Ensure that the anchor PSBT matches the returned anchor
2671
+ // transaction.
2672
+ require .Equal (t .t , anchorTx .TxHash (), btcPacket .UnsignedTx .TxHash ())
2673
+
2674
+ // Assert that the anchor transaction is not in the mempool.
2675
+ miner := t .lndHarness .Miner ()
2676
+ miner .AssertTxnsNotInMempool ([]chainhash.Hash {
2677
+ anchorTx .TxHash (),
2678
+ })
2679
+
2680
+ // Add the anchor transaction to the mempool and mine.
2681
+ miner .MineBlockWithTx (& anchorTx )
2682
+
2683
+ // Assert that the transfer has the correct number of outputs.
2619
2684
expectedAmounts := []uint64 {
2620
2685
targetAsset .Amount - assetsToSend , assetsToSend ,
2621
2686
}
2622
- ConfirmAndAssertOutboundTransferWithOutputs (
2687
+ AssertAssetOutboundTransferWithOutputs (
2623
2688
t .t , t .lndHarness .Miner ().Client , aliceTapd ,
2624
- sendResp , targetAssetGenesis .AssetId , expectedAmounts ,
2625
- 0 , 1 , len (expectedAmounts ),
2689
+ sendResp . Transfer , targetAssetGenesis .AssetId , expectedAmounts ,
2690
+ 0 , 1 , len (expectedAmounts ), false ,
2626
2691
)
2627
2692
2628
2693
// And now the event should be completed on both sides.
0 commit comments