@@ -135,6 +135,196 @@ func testBasicSendUnidirectional(t *harnessTest) {
135135 wg .Wait ()
136136}
137137
138+ // testRestartReceiver tests that the receiver node's asset balance after a
139+ // single asset transfer does not change if the receiver node restarts.
140+ // Before the addition of this test, after restarting the receiver node
141+ // the asset balance would be erroneously incremented. This is because the
142+ // receiver node was not storing asset transfer in its database with the
143+ // appropriate field uniqueness constraints.
144+ func testRestartReceiverCheckBalance (t * harnessTest ) {
145+ var (
146+ ctxb = context .Background ()
147+ wg sync.WaitGroup
148+ )
149+
150+ const (
151+ // Number of units to send.
152+ numUnits = 10
153+ )
154+
155+ // Subscribe to receive assent send events from primary tapd node.
156+ eventNtfns , err := t .tapd .SubscribeSendAssetEventNtfns (
157+ ctxb , & taprpc.SubscribeSendAssetEventNtfnsRequest {},
158+ )
159+ require .NoError (t .t , err )
160+
161+ // Test to ensure that we execute the transaction broadcast state.
162+ // This test is executed in a goroutine to ensure that we can receive
163+ // the event notification from the tapd node as the rest of the test
164+ // proceeds.
165+ wg .Add (1 )
166+ go func () {
167+ defer wg .Done ()
168+
169+ broadcastState := tapfreighter .SendStateBroadcast .String ()
170+ targetEventSelector := func (event * taprpc.SendAssetEvent ) bool {
171+ switch eventTyped := event .Event .(type ) {
172+ case * taprpc.SendAssetEvent_ExecuteSendStateEvent :
173+ ev := eventTyped .ExecuteSendStateEvent
174+
175+ // Log send state execution.
176+ timestamp := time .UnixMicro (ev .Timestamp )
177+ t .Logf ("Executing send state (%v): %v" ,
178+ timestamp .Format (time .RFC3339Nano ),
179+ ev .SendState )
180+
181+ return ev .SendState == broadcastState
182+ }
183+
184+ return false
185+ }
186+
187+ timeout := 2 * defaultProofTransferReceiverAckTimeout
188+ ctx , cancel := context .WithTimeout (ctxb , timeout )
189+ defer cancel ()
190+ assertAssetSendNtfsEvent (
191+ t , ctx , eventNtfns , targetEventSelector , 1 ,
192+ )
193+ }()
194+
195+ // First, we'll make a normal assets with enough units to allow us to
196+ // send it around a few times.
197+ rpcAssets := MintAssetsConfirmBatch (
198+ t .t , t .lndHarness .Miner .Client , t .tapd ,
199+ []* mintrpc.MintAssetRequest {issuableAssets [0 ]},
200+ )
201+
202+ genInfo := rpcAssets [0 ].AssetGenesis
203+
204+ // Now that we have the asset created, we'll make a new node that'll
205+ // serve as the node which'll receive the assets. The existing tapd
206+ // node will be used to synchronize universe state.
207+ //
208+ // We will stipulate that the receiver node's custodian service should
209+ // not delay commencing the proof retrieval procedure once a suitable
210+ // on-chain asset transfer is detected. This will ensure that on restart
211+ // the receiver node will attempt to immediately retrieve the asset
212+ // proof even if the proof and asset are present.
213+ custodianProofRetrievalDelay := 0 * time .Second
214+
215+ recvTapd := setupTapdHarness (
216+ t .t , t , t .lndHarness .Bob , t .universeServer ,
217+ func (params * tapdHarnessParams ) {
218+ params .startupSyncNode = t .tapd
219+ params .startupSyncNumAssets = len (rpcAssets )
220+ params .custodianProofRetrievalDelay = & custodianProofRetrievalDelay
221+ },
222+ )
223+ defer func () {
224+ require .NoError (t .t , recvTapd .stop (! * noDelete ))
225+ }()
226+
227+ // Next, we'll attempt to complete two transfers with distinct
228+ // addresses from our main node to Bob.
229+ currentUnits := issuableAssets [0 ].Asset .Amount
230+
231+ // Issue a single address which will be reused for each send.
232+ bobAddr , err := recvTapd .NewAddr (ctxb , & taprpc.NewAddrRequest {
233+ AssetId : genInfo .AssetId ,
234+ Amt : numUnits ,
235+ AssetVersion : rpcAssets [0 ].Version ,
236+ })
237+ require .NoError (t .t , err )
238+
239+ t .t .Logf ("Performing send procedure" )
240+
241+ // Deduct what we sent from the expected current number of
242+ // units.
243+ currentUnits -= numUnits
244+
245+ AssertAddrCreated (t .t , recvTapd , rpcAssets [0 ], bobAddr )
246+
247+ sendResp := sendAssetsToAddr (t , t .tapd , bobAddr )
248+
249+ ConfirmAndAssertOutboundTransfer (
250+ t .t , t .lndHarness .Miner .Client , t .tapd , sendResp ,
251+ genInfo .AssetId ,
252+ []uint64 {currentUnits , numUnits }, 0 , 1 ,
253+ )
254+ AssertNonInteractiveRecvComplete (t .t , recvTapd , 1 )
255+
256+ // Close event stream.
257+ err = eventNtfns .CloseSend ()
258+ require .NoError (t .t , err )
259+
260+ wg .Wait ()
261+
262+ assertRecvBalance := func () {
263+ // Get asset balance by group from the receiver node.
264+ respGroup , err := recvTapd .ListBalances (
265+ ctxb , & taprpc.ListBalancesRequest {
266+ GroupBy : & taprpc.ListBalancesRequest_GroupKey {
267+ GroupKey : true ,
268+ },
269+ },
270+ )
271+ require .NoError (t .t , err )
272+
273+ // We expect to see a single asset group balance. The receiver
274+ // node received one asset only.
275+ require .Len (t .t , respGroup .AssetGroupBalances , 1 )
276+
277+ var assetGroupBalance * taprpc.AssetGroupBalance
278+
279+ for _ , value := range respGroup .AssetGroupBalances {
280+ assetGroupBalance = value
281+ break
282+ }
283+
284+ require .Equal (t .t , int (10 ), int (assetGroupBalance .Balance ))
285+
286+ // Get asset balance by asset ID from the receiver node.
287+ respAsset , err := recvTapd .ListBalances (
288+ ctxb , & taprpc.ListBalancesRequest {
289+ GroupBy : & taprpc.ListBalancesRequest_AssetId {
290+ AssetId : true ,
291+ },
292+ },
293+ )
294+ require .NoError (t .t , err )
295+
296+ // We expect to see a single asset group balance. The receiver
297+ // node received one asset only.
298+ require .Len (t .t , respAsset .AssetBalances , 1 )
299+
300+ var assetBalance * taprpc.AssetBalance
301+
302+ for _ , value := range respAsset .AssetBalances {
303+ assetBalance = value
304+ break
305+ }
306+
307+ require .Equal (t .t , assetBalance .Balance , uint64 (10 ))
308+ }
309+
310+ // Initial balance check.
311+ assertRecvBalance ()
312+
313+ // Restart the receiver node and then check the balance again.
314+ require .NoError (t .t , recvTapd .stop (false ))
315+ require .NoError (t .t , recvTapd .start (false ))
316+
317+ assertRecvBalance ()
318+
319+ // Restart the receiver node, mine some blocks, and then check the
320+ // balance again.
321+ require .NoError (t .t , recvTapd .stop (false ))
322+ t .lndHarness .MineBlocks (7 )
323+ require .NoError (t .t , recvTapd .start (false ))
324+
325+ assertRecvBalance ()
326+ }
327+
138328// testResumePendingPackageSend tests that we can properly resume a pending
139329// package send after a restart.
140330func testResumePendingPackageSend (t * harnessTest ) {
0 commit comments