@@ -8,17 +8,16 @@ import (
88 "github.com/stretchr/testify/require"
99)
1010
11- // testZeroValueAnchorSweep tests that zero-value anchor outputs (tombstones)
11+ // testZeroValueAnchorSweep tests that zero-value anchor outputs
1212// are automatically swept when creating new on-chain transactions.
1313func testZeroValueAnchorSweep (t * harnessTest ) {
1414 ctxb := context .Background ()
1515
16- // First, mint some simple assets .
16+ // First, mint some simple asset .
1717 rpcAssets := MintAssetsConfirmBatch (
1818 t .t , t .lndHarness .Miner ().Client , t .tapd ,
1919 []* mintrpc.MintAssetRequest {simpleAssets [0 ]},
2020 )
21-
2221 genInfo := rpcAssets [0 ].AssetGenesis
2322 assetAmount := simpleAssets [0 ].Asset .Amount
2423
@@ -29,88 +28,194 @@ func testZeroValueAnchorSweep(t *harnessTest) {
2928 require .NoError (t .t , secondTapd .stop (! * noDelete ))
3029 }()
3130
32- // Create an address for Bob to receive ALL assets (full value send).
33- // This should create a tombstone output on Alice's side.
3431 bobAddr , err := secondTapd .NewAddr (ctxb , & taprpc.NewAddrRequest {
3532 AssetId : genInfo .AssetId ,
36- Amt : assetAmount , // Send ALL
33+ Amt : assetAmount ,
3734 AssetVersion : rpcAssets [0 ].Version ,
3835 })
3936 require .NoError (t .t , err )
4037
41- // Send ALL assets to Bob, which should create a tombstone output .
38+ // Send ALL assets to Bob, which should create a tombstone.
4239 sendResp , _ := sendAssetsToAddr (t , t .tapd , bobAddr )
4340
44- // Confirm the send and wait for completion.
4541 ConfirmAndAssertOutboundTransfer (
4642 t .t , t .lndHarness .Miner ().Client , t .tapd , sendResp ,
4743 genInfo .AssetId ,
4844 []uint64 {0 , assetAmount }, 0 , 1 ,
4945 )
5046 AssertNonInteractiveRecvComplete (t .t , secondTapd , 1 )
5147
52- // At this point, Alice should have a tombstone UTXO.
53- // Check Alice's UTXOs to see if there are any without assets (tombstones).
54- aliceUtxos , err := t .tapd .ListUtxos (ctxb , & taprpc.ListUtxosRequest {})
48+ // Check Alice's UTXOs for tombstone script keys.
49+ utxos , err := t .tapd .ListUtxos (ctxb , & taprpc.ListUtxosRequest {
50+ ScriptKeyType : & taprpc.ScriptKeyTypeQuery {
51+ Type : & taprpc.ScriptKeyTypeQuery_ExplicitType {
52+ ExplicitType : taprpc .
53+ ScriptKeyType_SCRIPT_KEY_TOMBSTONE ,
54+ },
55+ },
56+ })
5557 require .NoError (t .t , err )
58+ require .Len (t .t , utxos .ManagedUtxos , 1 )
5659
57- tombstoneCount := 0
58- for _ , utxo := range aliceUtxos .ManagedUtxos {
59- if len (utxo .Assets ) == 0 {
60- tombstoneCount ++
61- t .t .Logf ("Found tombstone UTXO: %s, value=%d" ,
62- utxo .OutPoint , utxo .AmtSat )
60+ tombstoneOp := ""
61+ for outpoint , utxo := range utxos .ManagedUtxos {
62+ if ! utxo .Swept {
63+ tombstoneOp = outpoint
64+ break
6365 }
6466 }
6567
66- t .t .Logf ("Alice has %d tombstone UTXOs before sweep" , tombstoneCount )
67- require .Greater (t .t , tombstoneCount , 0 , "Should have at least one tombstone UTXO" )
68-
69- // Now mint more assets for Alice so she can create another transaction
70- // that should sweep the tombstones.
68+ // Test 1: Send transaction sweeps tombstones.
7169 rpcAssets2 := MintAssetsConfirmBatch (
7270 t .t , t .lndHarness .Miner ().Client , t .tapd ,
73- []* mintrpc.MintAssetRequest {simpleAssets [1 ]},
71+ []* mintrpc.MintAssetRequest {simpleAssets [0 ]},
7472 )
75-
7673 genInfo2 := rpcAssets2 [0 ].AssetGenesis
77- assetAmount2 := simpleAssets [1 ].Asset .Amount
7874
79- // Create another address for Bob.
75+ // Send full amount of the new asset. This should sweep Alice's
76+ // first tombstone and create a new one.
8077 bobAddr2 , err := secondTapd .NewAddr (ctxb , & taprpc.NewAddrRequest {
8178 AssetId : genInfo2 .AssetId ,
82- Amt : assetAmount2 ,
79+ Amt : assetAmount ,
8380 AssetVersion : rpcAssets2 [0 ].Version ,
8481 })
8582 require .NoError (t .t , err )
8683
87- // Send the new assets. This should sweep Alice's tombstone UTXOs.
8884 sendResp2 , _ := sendAssetsToAddr (t , t .tapd , bobAddr2 )
8985
90- // Confirm the send.
9186 ConfirmAndAssertOutboundTransfer (
9287 t .t , t .lndHarness .Miner ().Client , t .tapd , sendResp2 ,
9388 genInfo2 .AssetId ,
94- []uint64 {0 , assetAmount2 }, 1 , 2 ,
89+ []uint64 {0 , assetAmount }, 1 , 2 ,
9590 )
9691 AssertNonInteractiveRecvComplete (t .t , secondTapd , 2 )
9792
98- // Check Alice's UTXOs again. The tombstones should have been swept.
99- finalAliceUtxos , err := t .tapd .ListUtxos (ctxb , & taprpc.ListUtxosRequest {})
93+ // Check Alice's UTXOs again. The tombstone should have been swept.
94+ utxosAfterSend , err := t .tapd .ListUtxos (ctxb , & taprpc.ListUtxosRequest {
95+ ScriptKeyType : & taprpc.ScriptKeyTypeQuery {
96+ Type : & taprpc.ScriptKeyTypeQuery_ExplicitType {
97+ ExplicitType : taprpc .
98+ ScriptKeyType_SCRIPT_KEY_TOMBSTONE ,
99+ },
100+ },
101+ })
100102 require .NoError (t .t , err )
103+ require .Len (t .t , utxosAfterSend .ManagedUtxos , 2 )
104+
105+ // After the sweep, check that the first tombstone
106+ // is now marked as swept.
107+ sweptUtxo , ok := utxosAfterSend .ManagedUtxos [tombstoneOp ]
108+ require .True (t .t , ok )
109+ require .True (t .t , sweptUtxo .Swept )
110+
111+ tombstoneOp2 := ""
112+ for outpoint , utxo := range utxosAfterSend .ManagedUtxos {
113+ if ! utxo .Swept {
114+ tombstoneOp2 = outpoint
115+ break
116+ }
117+ }
118+ require .NotEmpty (t .t , tombstoneOp2 )
101119
102- finalTombstoneCount := 0
103- for _ , utxo := range finalAliceUtxos .ManagedUtxos {
104- if len (utxo .Assets ) == 0 {
105- finalTombstoneCount ++
106- t .t .Logf ("Found tombstone UTXO after sweep: %s, value=%d" ,
107- utxo .OutPoint , utxo .AmtSat )
120+ // Test 2: Burning transaction sweeps tombstones.
121+ rpcAssets3 := MintAssetsConfirmBatch (
122+ t .t , t .lndHarness .Miner ().Client , t .tapd ,
123+ []* mintrpc.MintAssetRequest {simpleAssets [0 ]},
124+ )
125+ genInfo3 := rpcAssets3 [0 ].AssetGenesis
126+
127+ // Full burn the asset to create a zero-value burn UTXO
128+ // and sweep the second tombstone.
129+ burnResp , err := t .tapd .BurnAsset (ctxb , & taprpc.BurnAssetRequest {
130+ Asset : & taprpc.BurnAssetRequest_AssetId {
131+ AssetId : genInfo3 .AssetId ,
132+ },
133+ AmountToBurn : assetAmount ,
134+ ConfirmationText : "assets will be destroyed" ,
135+ })
136+ require .NoError (t .t , err )
137+
138+ AssertAssetOutboundTransferWithOutputs (
139+ t .t , t .lndHarness .Miner ().Client , t .tapd , burnResp .BurnTransfer ,
140+ [][]byte {genInfo3 .AssetId },
141+ []uint64 {assetAmount }, 2 , 3 , 1 , true ,
142+ )
143+
144+ // Second tombstone should be swept.
145+ utxosAfterBurn , err := t .tapd .ListUtxos (ctxb , & taprpc.ListUtxosRequest {
146+ ScriptKeyType : & taprpc.ScriptKeyTypeQuery {
147+ Type : & taprpc.ScriptKeyTypeQuery_ExplicitType {
148+ ExplicitType : taprpc .
149+ ScriptKeyType_SCRIPT_KEY_TOMBSTONE ,
150+ },
151+ },
152+ },
153+ )
154+ require .NoError (t .t , err )
155+
156+ sweptTombstone2 , ok := utxosAfterBurn .ManagedUtxos [tombstoneOp2 ]
157+ require .True (t .t , ok )
158+ require .True (t .t , sweptTombstone2 .Swept )
159+
160+ burnUtxos , err := t .tapd .ListUtxos (ctxb , & taprpc.ListUtxosRequest {
161+ ScriptKeyType : & taprpc.ScriptKeyTypeQuery {
162+ Type : & taprpc.ScriptKeyTypeQuery_ExplicitType {
163+ ExplicitType : taprpc .
164+ ScriptKeyType_SCRIPT_KEY_BURN ,
165+ },
166+ },
167+ })
168+ require .NoError (t .t , err )
169+ require .Len (t .t , burnUtxos .ManagedUtxos , 1 )
170+
171+ burnOutpoint := ""
172+ for outpoint , utxo := range burnUtxos .ManagedUtxos {
173+ if ! utxo .Swept {
174+ burnOutpoint = outpoint
175+ break
108176 }
109177 }
178+ require .NotEmpty (t .t , burnOutpoint )
179+
180+ // Test 3: Send transactions sweeps zero-value burns.
181+ rpcAssets4 := MintAssetsConfirmBatch (
182+ t .t , t .lndHarness .Miner ().Client , t .tapd ,
183+ []* mintrpc.MintAssetRequest {simpleAssets [0 ]},
184+ )
185+ genInfo4 := rpcAssets4 [0 ].AssetGenesis
186+
187+ // Send partial amouunt. This should NOT create a tombstone output
188+ // and sweep the burn UTXO.
189+ partialAmount := assetAmount / 2
190+ bobAddr3 , err := secondTapd .NewAddr (ctxb , & taprpc.NewAddrRequest {
191+ AssetId : genInfo4 .AssetId ,
192+ Amt : partialAmount ,
193+ AssetVersion : rpcAssets4 [0 ].Version ,
194+ })
195+ require .NoError (t .t , err )
196+
197+ sendResp3 , _ := sendAssetsToAddr (t , t .tapd , bobAddr3 )
110198
111- t .t .Logf ("Alice has %d tombstone UTXOs after sweep" , finalTombstoneCount )
199+ ConfirmAndAssertOutboundTransfer (
200+ t .t , t .lndHarness .Miner ().Client , t .tapd , sendResp3 ,
201+ genInfo4 .AssetId ,
202+ []uint64 {partialAmount , partialAmount }, 3 , 4 ,
203+ )
204+ AssertNonInteractiveRecvComplete (t .t , secondTapd , 3 )
205+
206+ // Burn UTXO should be swept.
207+ finalBurnUtxos , err := t .tapd .ListUtxos (ctxb , & taprpc.ListUtxosRequest {
208+ ScriptKeyType : & taprpc.ScriptKeyTypeQuery {
209+ Type : & taprpc.ScriptKeyTypeQuery_ExplicitType {
210+ ExplicitType : taprpc .
211+ ScriptKeyType_SCRIPT_KEY_BURN ,
212+ },
213+ },
214+ })
215+ require .NoError (t .t , err )
216+ require .Len (t .t , finalBurnUtxos .ManagedUtxos , 1 )
112217
113- // We expect no tombstones after the sweep transaction.
114- require .Equal (t .t , 0 , finalTombstoneCount ,
115- "All tombstones should be swept" )
218+ sweptBurnUtxo , ok := finalBurnUtxos . ManagedUtxos [ burnOutpoint ]
219+ require .True (t .t , ok )
220+ require . True ( t . t , sweptBurnUtxo . Swept )
116221}
0 commit comments