@@ -951,6 +951,248 @@ func testReattemptFailedSendUniCourier(t *harnessTest) {
951
951
wg .Wait ()
952
952
}
953
953
954
+ // testSpendChangeOutputWhenProofTransferFail tests that a tapd node is able
955
+ // to spend a change output even if the proof transfer for the previous
956
+ // transaction fails.
957
+ func testSpendChangeOutputWhenProofTransferFail (t * harnessTest ) {
958
+ var (
959
+ ctxb = context .Background ()
960
+ wg sync.WaitGroup
961
+ )
962
+
963
+ // For this test we will use the universe server as the proof courier.
964
+ proofCourier := t .universeServer
965
+
966
+ // Make a new tapd node which will send an asset to a receiving tapd
967
+ // node.
968
+ sendTapd := setupTapdHarness (
969
+ t .t , t , t .lndHarness .Bob , t .universeServer ,
970
+ func (params * tapdHarnessParams ) {
971
+ params .expectErrExit = true
972
+ params .proofCourier = proofCourier
973
+ },
974
+ )
975
+ defer func () {
976
+ // Any node that has been started within an itest should be
977
+ // explicitly stopped within the same itest.
978
+ require .NoError (t .t , sendTapd .stop (! * noDelete ))
979
+ }()
980
+
981
+ // Use the primary tapd node as the receiver node.
982
+ recvTapd := t .tapd
983
+
984
+ // Use the sending node to mint an asset for sending.
985
+ rpcAssets := MintAssetsConfirmBatch (
986
+ t .t , t .lndHarness .Miner .Client , sendTapd ,
987
+ []* mintrpc.MintAssetRequest {simpleAssets [0 ]},
988
+ )
989
+
990
+ genInfo := rpcAssets [0 ].AssetGenesis
991
+
992
+ // After minting an asset with the sending node, we need to synchronize
993
+ // the Universe state to ensure the receiving node is updated and aware
994
+ // of the asset.
995
+ t .syncUniverseState (sendTapd , recvTapd , len (rpcAssets ))
996
+
997
+ // Create a new address for the receiver node. We will use the universe
998
+ // server as the proof courier.
999
+ proofCourierAddr := fmt .Sprintf (
1000
+ "%s://%s" , proof .UniverseRpcCourierType ,
1001
+ proofCourier .service .rpcHost (),
1002
+ )
1003
+ t .Logf ("Proof courier address: %s" , proofCourierAddr )
1004
+
1005
+ recvAddr , err := recvTapd .NewAddr (ctxb , & taprpc.NewAddrRequest {
1006
+ AssetId : genInfo .AssetId ,
1007
+ Amt : 10 ,
1008
+ ProofCourierAddr : proofCourierAddr ,
1009
+ })
1010
+ require .NoError (t .t , err )
1011
+ AssertAddrCreated (t .t , recvTapd , rpcAssets [0 ], recvAddr )
1012
+
1013
+ // Soon we will be attempting to send an asset to the receiver node. We
1014
+ // want any associated proof delivery attempt to fail. Therefore, we
1015
+ // will take the proof courier service offline.
1016
+ t .Log ("Stopping proof courier service" )
1017
+ require .NoError (t .t , proofCourier .Stop ())
1018
+
1019
+ // Now that the proof courier service is offline, the sending node's
1020
+ // attempt to transfer the asset proof should fail.
1021
+ //
1022
+ // We will soon start the asset transfer process. However, before we
1023
+ // start, we subscribe to the send events from the sending tapd node so
1024
+ // that we can be sure that a proof delivery has been attempted
1025
+ // unsuccessfully. We assert that at least a single proof delivery
1026
+ // attempt has been made by identifying a backoff wait event.
1027
+ events := SubscribeSendEvents (t .t , sendTapd )
1028
+
1029
+ wg .Add (1 )
1030
+ go func () {
1031
+ defer wg .Done ()
1032
+
1033
+ // Define a target event selector to match the backoff wait
1034
+ // event. This function selects for a specific event type.
1035
+ targetEventSelector := func (
1036
+ event * tapdevrpc.SendAssetEvent ) bool {
1037
+
1038
+ return AssertSendEventProofTransferBackoffWaitTypeSend (
1039
+ t , event ,
1040
+ )
1041
+ }
1042
+
1043
+ // Set the context timeout for detecting a single proof delivery
1044
+ // attempt to something reasonable.
1045
+ timeout := 2 * defaultProofTransferReceiverAckTimeout
1046
+
1047
+ assertAssetNtfsEvent (
1048
+ t , events , timeout , targetEventSelector , 1 ,
1049
+ )
1050
+ }()
1051
+
1052
+ // Start asset transfer and then mine to confirm the associated on-chain
1053
+ // tx. The on-chain tx should be mined successfully, but we expect the
1054
+ // asset proof transfer to be unsuccessful.
1055
+ sendAssetsToAddr (t , sendTapd , recvAddr )
1056
+ MineBlocks (t .t , t .lndHarness .Miner .Client , 1 , 1 )
1057
+
1058
+ // There may be a delay between mining the anchoring transaction and
1059
+ // recognizing its on-chain confirmation. To handle this potential
1060
+ // delay, we use require.Eventually to ensure the transfer details are
1061
+ // correctly listed after confirmation.
1062
+ require .Eventually (t .t , func () bool {
1063
+ // Ensure that the transaction took place as expected.
1064
+ listTransfersResp , err := sendTapd .ListTransfers (
1065
+ ctxb , & taprpc.ListTransfersRequest {},
1066
+ )
1067
+ require .NoError (t .t , err )
1068
+
1069
+ require .Len (t .t , listTransfersResp .Transfers , 1 )
1070
+
1071
+ firstTransfer := listTransfersResp .Transfers [0 ]
1072
+ require .NotEqual (t .t , firstTransfer .AnchorTxHeightHint , 0 )
1073
+ require .NotEmpty (t .t , firstTransfer .AnchorTxBlockHash )
1074
+
1075
+ // Assert proof transfer status for each transfer output.
1076
+ require .Len (t .t , firstTransfer .Outputs , 2 )
1077
+
1078
+ // First output should have a proof delivery status of not
1079
+ // applicable. This indicates that a proof will not be delivered
1080
+ // for this output.
1081
+ firstOutput := firstTransfer .Outputs [0 ]
1082
+ require .Equal (
1083
+ t .t , taprpc .ProofDeliveryStatusNotApplicable ,
1084
+ firstOutput .ProofDeliveryStatus ,
1085
+ )
1086
+
1087
+ // The second output should have a proof delivery status of
1088
+ // pending. This indicates that the proof deliver has not yet
1089
+ // completed successfully.
1090
+ secondOutput := firstTransfer .Outputs [1 ]
1091
+ require .Equal (
1092
+ t .t , taprpc .ProofDeliveryStatusPending ,
1093
+ secondOutput .ProofDeliveryStatus ,
1094
+ )
1095
+
1096
+ return true
1097
+ }, defaultWaitTimeout , 200 * time .Millisecond )
1098
+
1099
+ // Wait to ensure that the asset transfer proof deliver attempt has been
1100
+ // made.
1101
+ wg .Wait ()
1102
+
1103
+ // Attempt to send the change output to the receiver node. This
1104
+ // operation should select the change output from the previous
1105
+ // transaction and transmit it to the receiver node, despite the fact
1106
+ // that proof delivery for the previous transaction remains incomplete
1107
+ // (due to the proof courier being shut down). We will generate a new
1108
+ // address for this new transaction.
1109
+ recvAddr , err = recvTapd .NewAddr (ctxb , & taprpc.NewAddrRequest {
1110
+ AssetId : genInfo .AssetId ,
1111
+ Amt : 42 ,
1112
+ ProofCourierAddr : proofCourierAddr ,
1113
+ })
1114
+ require .NoError (t .t , err )
1115
+ AssertAddrCreated (t .t , recvTapd , rpcAssets [0 ], recvAddr )
1116
+
1117
+ sendAssetsToAddr (t , sendTapd , recvAddr )
1118
+ MineBlocks (t .t , t .lndHarness .Miner .Client , 1 , 1 )
1119
+
1120
+ // There may be a delay between mining the anchoring transaction and
1121
+ // recognizing its on-chain confirmation. To handle this potential
1122
+ // delay, we use require.Eventually to ensure the transfer details are
1123
+ // correctly listed after confirmation.
1124
+ require .Eventually (t .t , func () bool {
1125
+ // Ensure that the transaction took place as expected.
1126
+ listTransfersResp , err := sendTapd .ListTransfers (
1127
+ ctxb , & taprpc.ListTransfersRequest {},
1128
+ )
1129
+ require .NoError (t .t , err )
1130
+
1131
+ require .Len (t .t , listTransfersResp .Transfers , 2 )
1132
+
1133
+ // Inspect the first transfer.
1134
+ firstTransfer := listTransfersResp .Transfers [0 ]
1135
+ require .NotEqual (t .t , firstTransfer .AnchorTxHeightHint , 0 )
1136
+ require .NotEmpty (t .t , firstTransfer .AnchorTxBlockHash )
1137
+
1138
+ // Assert proof transfer status for each transfer output.
1139
+ require .Len (t .t , firstTransfer .Outputs , 2 )
1140
+
1141
+ // First output should have a proof delivery status of not
1142
+ // applicable. This indicates that a proof will not be delivered
1143
+ // for this output.
1144
+ firstOutput := firstTransfer .Outputs [0 ]
1145
+ require .Equal (
1146
+ t .t , taprpc .ProofDeliveryStatusNotApplicable ,
1147
+ firstOutput .ProofDeliveryStatus ,
1148
+ )
1149
+
1150
+ // The second output should have a proof delivery status of
1151
+ // pending. This indicates that the proof deliver has not yet
1152
+ // completed successfully.
1153
+ secondOutput := firstTransfer .Outputs [1 ]
1154
+ require .Equal (
1155
+ t .t , taprpc .ProofDeliveryStatusPending ,
1156
+ secondOutput .ProofDeliveryStatus ,
1157
+ )
1158
+
1159
+ // Inspect the second transfer.
1160
+ secondTransfer := listTransfersResp .Transfers [1 ]
1161
+ require .NotEqual (t .t , secondTransfer .AnchorTxHeightHint , 0 )
1162
+ require .NotEmpty (t .t , secondTransfer .AnchorTxBlockHash )
1163
+
1164
+ // Assert proof transfer status for each transfer output.
1165
+ require .Len (t .t , secondTransfer .Outputs , 2 )
1166
+
1167
+ // First output should have a proof delivery status of not
1168
+ // applicable. This indicates that a proof will not be delivered
1169
+ // for this output.
1170
+ firstOutput = secondTransfer .Outputs [0 ]
1171
+ require .Equal (
1172
+ t .t , taprpc .ProofDeliveryStatusNotApplicable ,
1173
+ firstOutput .ProofDeliveryStatus ,
1174
+ )
1175
+
1176
+ // The second output should have a proof delivery status of
1177
+ // pending. This indicates that the proof deliver has not yet
1178
+ // completed successfully.
1179
+ secondOutput = secondTransfer .Outputs [1 ]
1180
+ require .Equal (
1181
+ t .t , taprpc .ProofDeliveryStatusPending ,
1182
+ secondOutput .ProofDeliveryStatus ,
1183
+ )
1184
+
1185
+ return true
1186
+ }, defaultWaitTimeout , 200 * time .Millisecond )
1187
+
1188
+ // Restart the proof courier service.
1189
+ t .Log ("Starting proof courier service" )
1190
+ require .NoError (t .t , proofCourier .Start (nil ))
1191
+
1192
+ // TODO(ffranr): Assert proof transfer complete after proof courier
1193
+ // restart.
1194
+ }
1195
+
954
1196
// testReattemptFailedReceiveUniCourier ensures that a failed attempt to receive
955
1197
// an asset proof is retried by the receiving Tapd node. This test focuses on
956
1198
// the universe proof courier.
0 commit comments