@@ -4,40 +4,6 @@ use crate::compute::{
44} ;
55use log:: error;
66use reqwest:: { blocking:: Client , header:: AUTHORIZATION } ;
7- use serde:: Serialize ;
8-
9- /// Represents payload that can be sent to the worker API to report the outcome of the
10- /// pre‑compute stage.
11- ///
12- /// The JSON structure expected by the REST endpoint is:
13- /// ```json
14- /// {
15- /// "cause": "<ReplicateStatusCause as string>"
16- /// }
17- /// ```
18- ///
19- /// # Arguments
20- ///
21- /// * `cause` - A reference to the ReplicateStatusCause indicating why the pre-compute operation exited
22- ///
23- /// # Example
24- ///
25- /// ```rust
26- /// use tee_worker_pre_compute::api::worker_api::ExitMessage;
27- /// use tee_worker_pre_compute::compute::errors::ReplicateStatusCause;
28- ///
29- /// let exit_message = ExitMessage::from(&ReplicateStatusCause::PreComputeInvalidTeeSignature);
30- /// ```
31- #[ derive( Serialize , Debug ) ]
32- pub struct ExitMessage < ' a > {
33- pub cause : & ' a ReplicateStatusCause ,
34- }
35-
36- impl < ' a > From < & ' a ReplicateStatusCause > for ExitMessage < ' a > {
37- fn from ( cause : & ' a ReplicateStatusCause ) -> Self {
38- Self { cause }
39- }
40- }
417
428/// Thin wrapper around a [`Client`] that knows how to reach the iExec worker API.
439///
@@ -93,21 +59,21 @@ impl WorkerApiClient {
9359 Self :: new ( & base_url)
9460 }
9561
96- /// Sends an exit cause for a pre-compute operation to the Worker API.
62+ /// Sends exit causes for a pre-compute operation to the Worker API.
9763 ///
98- /// This method reports the exit cause of a pre-compute operation to the Worker API,
64+ /// This method reports the exit causes of a pre-compute operation to the Worker API,
9965 /// which can be used for tracking and debugging purposes.
10066 ///
10167 /// # Arguments
10268 ///
10369 /// * `authorization` - The authorization token to use for the API request
104- /// * `chain_task_id` - The chain task ID for which to report the exit cause
105- /// * `exit_cause ` - The exit cause to report
70+ /// * `chain_task_id` - The chain task ID for which to report the exit causes
71+ /// * `exit_causes ` - The list of exit causes to report
10672 ///
10773 /// # Returns
10874 ///
109- /// * `Ok(())` - If the exit cause was successfully reported
110- /// * `Err(Error)` - If the exit cause could not be reported due to an HTTP error
75+ /// * `Ok(())` - If the exit causes were successfully reported
76+ /// * `Err(Error)` - If the exit causes could not be reported due to an HTTP error
11177 ///
11278 /// # Errors
11379 ///
@@ -117,33 +83,33 @@ impl WorkerApiClient {
11783 /// # Example
11884 ///
11985 /// ```rust
120- /// use tee_worker_pre_compute::api::worker_api::{ExitMessage, WorkerApiClient} ;
86+ /// use tee_worker_pre_compute::api::worker_api::WorkerApiClient;
12187 /// use tee_worker_pre_compute::compute::errors::ReplicateStatusCause;
12288 ///
12389 /// let client = WorkerApiClient::new("http://worker:13100");
124- /// let exit_message = ExitMessage::from(& ReplicateStatusCause::PreComputeInvalidTeeSignature) ;
90+ /// let exit_causes = vec![ ReplicateStatusCause::PreComputeInvalidTeeSignature] ;
12591 ///
126- /// match client.send_exit_cause_for_pre_compute_stage (
92+ /// match client.send_exit_causes_for_pre_compute_stage (
12793 /// "authorization_token",
12894 /// "0x123456789abcdef",
129- /// &exit_message ,
95+ /// &exit_causes ,
13096 /// ) {
131- /// Ok(()) => println!("Exit cause reported successfully"),
132- /// Err(error) => eprintln!("Failed to report exit cause : {error}"),
97+ /// Ok(()) => println!("Exit causes reported successfully"),
98+ /// Err(error) => eprintln!("Failed to report exit causes : {error}"),
13399 /// }
134100 /// ```
135- pub fn send_exit_cause_for_pre_compute_stage (
101+ pub fn send_exit_causes_for_pre_compute_stage (
136102 & self ,
137103 authorization : & str ,
138104 chain_task_id : & str ,
139- exit_cause : & ExitMessage ,
105+ exit_causes : & [ ReplicateStatusCause ] ,
140106 ) -> Result < ( ) , ReplicateStatusCause > {
141- let url = format ! ( "{}/compute/pre/{chain_task_id}/exit" , self . base_url) ;
107+ let url = format ! ( "{}/compute/pre/{chain_task_id}/exit-causes " , self . base_url) ;
142108 match self
143109 . client
144110 . post ( & url)
145111 . header ( AUTHORIZATION , authorization)
146- . json ( exit_cause )
112+ . json ( exit_causes )
147113 . send ( )
148114 {
149115 Ok ( resp) => {
@@ -152,12 +118,12 @@ impl WorkerApiClient {
152118 Ok ( ( ) )
153119 } else {
154120 let body = resp. text ( ) . unwrap_or_default ( ) ;
155- error ! ( "Failed to send exit cause : [status:{status}, body:{body}]" ) ;
121+ error ! ( "Failed to send exit causes : [status:{status}, body:{body}]" ) ;
156122 Err ( ReplicateStatusCause :: PreComputeFailedUnknownIssue )
157123 }
158124 }
159125 Err ( err) => {
160- error ! ( "HTTP request failed when sending exit cause to {url}: {err:?}" ) ;
126+ error ! ( "HTTP request failed when sending exit causes to {url}: {err:?}" ) ;
161127 Err ( ReplicateStatusCause :: PreComputeFailedUnknownIssue )
162128 }
163129 }
@@ -175,36 +141,52 @@ mod tests {
175141 matchers:: { body_json, header, method, path} ,
176142 } ;
177143
178- // region ExitMessage()
144+ // region Serialization tests
179145 #[ test]
180- fn should_serialize_exit_message ( ) {
181- let causes = [
146+ fn serialize_replicate_status_cause_succeeds_when_single_cause ( ) {
147+ let causes = vec ! [
182148 (
183149 ReplicateStatusCause :: PreComputeInvalidTeeSignature ,
184- " PRE_COMPUTE_INVALID_TEE_SIGNATURE",
150+ r#"{"cause":" PRE_COMPUTE_INVALID_TEE_SIGNATURE","message":"Invalid TEE signature"}"# ,
185151 ) ,
186152 (
187153 ReplicateStatusCause :: PreComputeWorkerAddressMissing ,
188- " PRE_COMPUTE_WORKER_ADDRESS_MISSING",
154+ r#"{"cause":" PRE_COMPUTE_WORKER_ADDRESS_MISSING","message":"Worker address related environment variable is missing"}"# ,
189155 ) ,
190156 (
191- ReplicateStatusCause :: PreComputeFailedUnknownIssue ,
192- "PRE_COMPUTE_FAILED_UNKNOWN_ISSUE" ,
157+ ReplicateStatusCause :: PreComputeDatasetUrlMissing ( "0xDatasetAdress1" . to_string( ) ) ,
158+ r#"{"cause":"PRE_COMPUTE_DATASET_URL_MISSING","message":"Dataset URL related environment variable is missing for dataset 0xDatasetAdress1"}"# ,
159+ ) ,
160+ (
161+ ReplicateStatusCause :: PreComputeInvalidDatasetChecksum (
162+ "0xDatasetAdress2" . to_string( ) ,
163+ ) ,
164+ r#"{"cause":"PRE_COMPUTE_INVALID_DATASET_CHECKSUM","message":"Invalid dataset checksum for dataset 0xDatasetAdress2"}"# ,
193165 ) ,
194166 ] ;
195167
196- for ( cause, message) in causes {
197- let exit_message = ExitMessage :: from ( & cause) ;
198- let serialized = to_string ( & exit_message) . expect ( "Failed to serialize" ) ;
199- let expected = format ! ( "{{\" cause\" :\" {message}\" }}" ) ;
200- assert_eq ! ( serialized, expected) ;
168+ for ( cause, expected_json) in causes {
169+ let serialized = to_string ( & cause) . expect ( "Failed to serialize" ) ;
170+ assert_eq ! ( serialized, expected_json) ;
201171 }
202172 }
173+
174+ #[ test]
175+ fn serialize_vec_of_causes_succeeds_when_multiple_causes ( ) {
176+ let causes = vec ! [
177+ ReplicateStatusCause :: PreComputeDatasetUrlMissing ( "0xDatasetAdress" . to_string( ) ) ,
178+ ReplicateStatusCause :: PreComputeInvalidDatasetChecksum ( "0xDatasetAdress" . to_string( ) ) ,
179+ ] ;
180+
181+ let serialized = to_string ( & causes) . expect ( "Failed to serialize" ) ;
182+ let expected = r#"[{"cause":"PRE_COMPUTE_DATASET_URL_MISSING","message":"Dataset URL related environment variable is missing for dataset 0xDatasetAdress"},{"cause":"PRE_COMPUTE_INVALID_DATASET_CHECKSUM","message":"Invalid dataset checksum for dataset 0xDatasetAdress"}]"# ;
183+ assert_eq ! ( serialized, expected) ;
184+ }
203185 // endregion
204186
205187 // region get_worker_api_client
206188 #[ test]
207- fn should_get_worker_api_client_with_env_var ( ) {
189+ fn from_env_creates_client_with_custom_host_when_env_var_set ( ) {
208190 with_vars (
209191 vec ! [ ( WorkerHostEnvVar . name( ) , Some ( "custom-worker-host:9999" ) ) ] ,
210192 || {
@@ -215,29 +197,32 @@ mod tests {
215197 }
216198
217199 #[ test]
218- fn should_get_worker_api_client_without_env_var ( ) {
200+ fn from_env_creates_client_with_default_host_when_env_var_unset ( ) {
219201 temp_env:: with_vars_unset ( vec ! [ WorkerHostEnvVar . name( ) ] , || {
220202 let client = WorkerApiClient :: from_env ( ) ;
221203 assert_eq ! ( client. base_url, format!( "http://{DEFAULT_WORKER_HOST}" ) ) ;
222204 } ) ;
223205 }
224206 // endregion
225207
226- // region send_exit_cause_for_pre_compute_stage ()
208+ // region send_exit_causes_for_pre_compute_stage ()
227209 const CHALLENGE : & str = "challenge" ;
228210 const CHAIN_TASK_ID : & str = "0x123456789abcdef" ;
229211
230212 #[ tokio:: test]
231- async fn should_send_exit_cause ( ) {
213+ async fn send_exit_causes_succeeds_when_api_returns_success ( ) {
232214 let mock_server = MockServer :: start ( ) . await ;
233215 let server_url = mock_server. uri ( ) ;
234216
235- let expected_body = json ! ( {
236- "cause" : ReplicateStatusCause :: PreComputeInvalidTeeSignature ,
237- } ) ;
217+ let expected_body = json ! ( [
218+ {
219+ "cause" : "PRE_COMPUTE_INVALID_TEE_SIGNATURE" ,
220+ "message" : "Invalid TEE signature"
221+ }
222+ ] ) ;
238223
239224 Mock :: given ( method ( "POST" ) )
240- . and ( path ( format ! ( "/compute/pre/{CHAIN_TASK_ID}/exit" ) ) )
225+ . and ( path ( format ! ( "/compute/pre/{CHAIN_TASK_ID}/exit-causes " ) ) )
241226 . and ( header ( "Authorization" , CHALLENGE ) )
242227 . and ( body_json ( & expected_body) )
243228 . respond_with ( ResponseTemplate :: new ( 200 ) )
@@ -246,13 +231,12 @@ mod tests {
246231 . await ;
247232
248233 let result = tokio:: task:: spawn_blocking ( move || {
249- let exit_message =
250- ExitMessage :: from ( & ReplicateStatusCause :: PreComputeInvalidTeeSignature ) ;
234+ let exit_causes = vec ! [ ReplicateStatusCause :: PreComputeInvalidTeeSignature ] ;
251235 let worker_api_client = WorkerApiClient :: new ( & server_url) ;
252- worker_api_client. send_exit_cause_for_pre_compute_stage (
236+ worker_api_client. send_exit_causes_for_pre_compute_stage (
253237 CHALLENGE ,
254238 CHAIN_TASK_ID ,
255- & exit_message ,
239+ & exit_causes ,
256240 )
257241 } )
258242 . await
@@ -262,26 +246,25 @@ mod tests {
262246 }
263247
264248 #[ tokio:: test]
265- async fn should_not_send_exit_cause ( ) {
249+ async fn send_exit_causes_fails_when_api_returns_error ( ) {
266250 testing_logger:: setup ( ) ;
267251 let mock_server = MockServer :: start ( ) . await ;
268252 let server_url = mock_server. uri ( ) ;
269253
270254 Mock :: given ( method ( "POST" ) )
271- . and ( path ( format ! ( "/compute/pre/{CHAIN_TASK_ID}/exit" ) ) )
255+ . and ( path ( format ! ( "/compute/pre/{CHAIN_TASK_ID}/exit-causes " ) ) )
272256 . respond_with ( ResponseTemplate :: new ( 503 ) . set_body_string ( "Service Unavailable" ) )
273257 . expect ( 1 )
274258 . mount ( & mock_server)
275259 . await ;
276260
277261 let result = tokio:: task:: spawn_blocking ( move || {
278- let exit_message =
279- ExitMessage :: from ( & ReplicateStatusCause :: PreComputeFailedUnknownIssue ) ;
262+ let exit_causes = vec ! [ ReplicateStatusCause :: PreComputeFailedUnknownIssue ] ;
280263 let worker_api_client = WorkerApiClient :: new ( & server_url) ;
281- let response = worker_api_client. send_exit_cause_for_pre_compute_stage (
264+ let response = worker_api_client. send_exit_causes_for_pre_compute_stage (
282265 CHALLENGE ,
283266 CHAIN_TASK_ID ,
284- & exit_message ,
267+ & exit_causes ,
285268 ) ;
286269 testing_logger:: validate ( |captured_logs| {
287270 let logs = captured_logs
@@ -292,7 +275,7 @@ mod tests {
292275 assert_eq ! ( logs. len( ) , 1 ) ;
293276 assert_eq ! (
294277 logs[ 0 ] . body,
295- "Failed to send exit cause : [status:503 Service Unavailable, body:Service Unavailable]"
278+ "Failed to send exit causes : [status:503 Service Unavailable, body:Service Unavailable]"
296279 ) ;
297280 } ) ;
298281 response
@@ -308,14 +291,14 @@ mod tests {
308291 }
309292
310293 #[ test]
311- fn test_send_exit_cause_http_request_failure ( ) {
294+ fn send_exit_causes_fails_when_http_request_invalid ( ) {
312295 testing_logger:: setup ( ) ;
313- let exit_message = ExitMessage :: from ( & ReplicateStatusCause :: PreComputeFailedUnknownIssue ) ;
296+ let exit_causes = vec ! [ ReplicateStatusCause :: PreComputeFailedUnknownIssue ] ;
314297 let worker_api_client = WorkerApiClient :: new ( "wrong_url" ) ;
315- let result = worker_api_client. send_exit_cause_for_pre_compute_stage (
298+ let result = worker_api_client. send_exit_causes_for_pre_compute_stage (
316299 CHALLENGE ,
317300 CHAIN_TASK_ID ,
318- & exit_message ,
301+ & exit_causes ,
319302 ) ;
320303 testing_logger:: validate ( |captured_logs| {
321304 let logs = captured_logs
@@ -326,7 +309,7 @@ mod tests {
326309 assert_eq ! ( logs. len( ) , 1 ) ;
327310 assert_eq ! (
328311 logs[ 0 ] . body,
329- "HTTP request failed when sending exit cause to wrong_url/compute/pre/0x123456789abcdef/exit: reqwest::Error { kind: Builder, source: RelativeUrlWithoutBase }"
312+ "HTTP request failed when sending exit causes to wrong_url/compute/pre/0x123456789abcdef/exit-causes : reqwest::Error { kind: Builder, source: RelativeUrlWithoutBase }"
330313 ) ;
331314 } ) ;
332315 assert ! ( result. is_err( ) ) ;
0 commit comments