Skip to content

Commit 6379c0d

Browse files
authored
Merge pull request #644 from lightninglabs/itest-recovered-receiver-send
Ensure receiver node backoff retries finally succeed in asset send via universe proof courier
2 parents 3e6579c + 48e9fe9 commit 6379c0d

File tree

2 files changed

+96
-50
lines changed

2 files changed

+96
-50
lines changed

itest/send_test.go

Lines changed: 93 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"encoding/hex"
7+
"fmt"
78
"io"
89
"strings"
910
"sync"
@@ -621,30 +622,90 @@ func testReattemptFailedReceiveUniCourier(t *harnessTest) {
621622
wg sync.WaitGroup
622623
)
623624

624-
// Make a new node which will send the asset to the primary tapd node.
625-
// We expect this node to fail because our send call will time out
626-
// whilst the porter continues to attempt to send the asset.
627-
sendTapd := setupTapdHarness(
625+
// This tapd node will send the asset to the receiving tapd node.
626+
// It will also transfer proof the related transfer proofs to the
627+
// proof courier.
628+
sendTapd := t.tapd
629+
630+
// Initialise a receiver tapd node. This node will attempt to retrieve
631+
// the transfer proofs from the proof courier.
632+
receiveTapd := setupTapdHarness(
628633
t.t, t, t.lndHarness.Bob, t.universeServer,
629634
func(params *tapdHarnessParams) {
630635
params.expectErrExit = true
636+
params.proofSendBackoffCfg = &proof.BackoffCfg{
637+
BackoffResetWait: 1 * time.Second,
638+
NumTries: 200,
639+
InitialBackoff: 1 * time.Second,
640+
MaxBackoff: 1 * time.Second,
641+
}
631642
},
632643
)
633644

634-
// Use the primary node as the receiver node.
635-
receiveTapd := t.tapd
645+
// Mint an asset for sending using the sending tapd node.
646+
rpcAssets := MintAssetsConfirmBatch(
647+
t.t, t.lndHarness.Miner.Client, sendTapd,
648+
[]*mintrpc.MintAssetRequest{simpleAssets[0]},
649+
)
650+
651+
genInfo := rpcAssets[0].AssetGenesis
652+
653+
// Synchronize the Universe state of the second node, with the receiver
654+
// node.
655+
t.syncUniverseState(sendTapd, receiveTapd, len(rpcAssets))
656+
657+
// Create a new address for the receiver node.
658+
recvAddr, err := receiveTapd.NewAddr(ctxb, &taprpc.NewAddrRequest{
659+
AssetId: genInfo.AssetId,
660+
Amt: 10,
661+
})
662+
require.NoError(t.t, err)
663+
AssertAddrCreated(t.t, receiveTapd, rpcAssets[0], recvAddr)
664+
665+
// Stop receiving tapd node to simulate an offline receiver.
666+
t.Logf("Stopping the receiving tapd node")
667+
require.NoError(t.t, receiveTapd.stop(false))
668+
669+
// Send asset and then mine to confirm the associated on-chain tx.
670+
sendAssetsToAddr(t, sendTapd, recvAddr)
671+
_ = MineBlocks(t.t, t.lndHarness.Miner.Client, 1, 1)
672+
673+
// At this point, the proof courier service is running. We will
674+
// therefore pause to allow the sender to transfer the proof to the
675+
// proof courier service.
676+
time.Sleep(2 * time.Second)
677+
678+
// Next, we're going to simulate a failed attempt at proof retrieval by
679+
// the receiver node. The receiver node will fail to retrieve the proof
680+
// from the proof courier. We simulate this failure by stopping the
681+
// proof courier service and then restarting the receiver tapd node.
682+
t.Logf("Stopping the proof courier service")
683+
require.NoError(t.t, t.proofCourier.Stop())
684+
685+
// Restart receiving tapd node.
686+
t.Logf("Re-starting receiving tapd node")
687+
require.NoError(t.t, receiveTapd.start(false))
688+
// Defer stopping the receiving tapd node to ensure that it is stopped
689+
// cleanly at the end of the test.
690+
defer func() {
691+
err := receiveTapd.stop(false)
692+
fmt.Println("Error stopping receiver tapd node: ", err)
693+
}()
636694

637695
// Subscribe to receive asset receive events from receiving tapd node.
696+
// We'll use these events to ensure that the receiver node is making
697+
// multiple attempts to retrieve the asset proof.
638698
eventNtfns, err := receiveTapd.SubscribeReceiveAssetEventNtfns(
639699
ctxb, &taprpc.SubscribeReceiveAssetEventNtfnsRequest{},
640700
)
641701
require.NoError(t.t, err)
642702

643-
// Test to ensure that we receive the expected number of backoff wait
644-
// event notifications.
703+
// Test to ensure that we receive the minimum expected number of backoff
704+
// wait event notifications.
705+
//
645706
// This test is executed in a goroutine to ensure that we can receive
646-
// the event notification(s) from the tapd node as the rest of the test
647-
// proceeds.
707+
// the event notification(s) from the tapd node as soon as the proof
708+
// courier service is restarted.
648709
wg.Add(1)
649710
go func() {
650711
defer wg.Done()
@@ -670,11 +731,8 @@ func testReattemptFailedReceiveUniCourier(t *harnessTest) {
670731
return false
671732
}
672733

673-
// Expected number of events is one less than the number of
674-
// tries because the first attempt does not count as a backoff
675-
// event.
676-
nodeBackoffCfg := t.tapd.clientCfg.HashMailCourier.BackoffCfg
677-
expectedEventCount := nodeBackoffCfg.NumTries - 1
734+
// Expected minimum number of events to receive.
735+
expectedEventCount := 3
678736

679737
// Context timeout scales with expected number of events.
680738
timeout := time.Duration(expectedEventCount) *
@@ -690,40 +748,24 @@ func testReattemptFailedReceiveUniCourier(t *harnessTest) {
690748
)
691749
}()
692750

693-
// Mint an asset for sending.
694-
rpcAssets := MintAssetsConfirmBatch(
695-
t.t, t.lndHarness.Miner.Client, sendTapd,
696-
[]*mintrpc.MintAssetRequest{simpleAssets[0]},
697-
)
698-
699-
genInfo := rpcAssets[0].AssetGenesis
700-
701-
// Synchronize the Universe state of the second node, with the main
702-
// node.
703-
t.syncUniverseState(sendTapd, receiveTapd, len(rpcAssets))
704-
705-
// Create a new address for the receiver node.
706-
recvAddr, err := t.tapd.NewAddr(ctxb, &taprpc.NewAddrRequest{
707-
AssetId: genInfo.AssetId,
708-
Amt: 10,
709-
})
710-
require.NoError(t.t, err)
711-
AssertAddrCreated(t.t, receiveTapd, rpcAssets[0], recvAddr)
712-
713-
// Simulate a failed attempt at sending the asset proof by stopping
714-
// the proof courier service.
715-
//
716-
// In following the hashmail proof courier protocol, the receiver node
717-
// returns a proof received confirmation message via the courier.
718-
// We can simulate a proof transfer failure by stopping the receiving
719-
// tapd node. The courier service should still be operational.
720-
require.NoError(t.t, t.proofCourier.Stop())
721-
722-
// Send asset and then mine to confirm the associated on-chain tx.
723-
sendAssetsToAddr(t, sendTapd, recvAddr)
724-
_ = MineBlocks(t.t, t.lndHarness.Miner.Client, 1, 1)
725-
751+
// Wait for the receiver node's backoff attempts to complete.
752+
t.Logf("Waiting for the receiving tapd node to complete backoff " +
753+
"proof retrieval attempts")
726754
wg.Wait()
755+
t.Logf("Finished waiting for the receiving tapd node to complete " +
756+
"backoff procedure")
757+
758+
// Restart the proof courier so that the receiver node can receive the
759+
// asset proof. The receiver tapd node should continue to make
760+
// attempts to retrieve the asset proof. Once the proof courier is
761+
// restarted, the receiver node should receive the transfer proof(s).
762+
t.Logf("Restarting proof courier service")
763+
require.NoError(t.t, t.proofCourier.Start(nil))
764+
765+
// Confirm that the receiver tapd node eventually receives the transfer
766+
// proof(s).
767+
t.Logf("Attempting to confirm asset received by receiver node")
768+
AssertNonInteractiveRecvComplete(t.t, receiveTapd, 1)
727769
}
728770

729771
// testOfflineReceiverEventuallyReceives tests that a receiver node will
@@ -932,7 +974,9 @@ func assertAssetRecvNtfsEvent(t *harnessTest, ctx context.Context,
932974
}
933975
}
934976

935-
require.Equal(t.t, expectedCount, countFound)
977+
require.Equal(t.t, expectedCount, countFound, "unexpected number of "+
978+
"asset receive event notifications (expected=%d, actual=%d)",
979+
expectedCount, countFound)
936980
}
937981

938982
// testMultiInputSendNonInteractiveSingleID tests that we can properly

itest/universerpc_harness.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ func (h *UniverseRPCHarness) Start(_ chan error) error {
4343

4444
// Stop stops the service.
4545
func (h *UniverseRPCHarness) Stop() error {
46-
return h.service.stop(true)
46+
// Don't delete temporary data on stop. This will allow us to cleanly
47+
// restart the service mid-test.
48+
return h.service.stop(false)
4749
}
4850

4951
// Ensure that NewUniverseRPCHarness implements the proof.CourierHarness

0 commit comments

Comments
 (0)