@@ -14,13 +14,13 @@ use sqlx::types::BigDecimal;
1414
1515use super :: {
1616 helpers:: format_merkle_path,
17- types:: { AppResponse , GetProofMerklePathQueryParams } ,
17+ types:: { AppResponse , GetReceiptsQueryParams } ,
1818} ;
1919
2020use crate :: {
2121 config:: Config ,
2222 db:: Db ,
23- server:: types:: { SubmitProofRequestRisc0 , SubmitProofRequestSP1 } ,
23+ server:: types:: { GetReceiptsResponse , SubmitProofRequestRisc0 , SubmitProofRequestSP1 } ,
2424 verifiers:: { verify_sp1_proof, VerificationError } ,
2525} ;
2626
@@ -45,7 +45,7 @@ impl BatcherServer {
4545 App :: new ( )
4646 . app_data ( Data :: new ( state. clone ( ) ) )
4747 . route ( "/nonce/{address}" , web:: get ( ) . to ( Self :: get_nonce) )
48- . route ( "/proof/merkle " , web:: get ( ) . to ( Self :: get_proof_merkle_path ) )
48+ . route ( "/receipts " , web:: get ( ) . to ( Self :: get_receipts ) )
4949 . route ( "/proof/sp1" , web:: post ( ) . to ( Self :: post_proof_sp1) )
5050 . route ( "/proof/risc0" , web:: post ( ) . to ( Self :: post_proof_risc0) )
5151 } )
@@ -56,20 +56,28 @@ impl BatcherServer {
5656 . expect ( "Server to never end" ) ;
5757 }
5858
59+ // Returns the nonce (number of submitted tasks) for a given address
5960 async fn get_nonce ( req : HttpRequest ) -> impl Responder {
60- let Some ( address ) = req. match_info ( ) . get ( "address" ) else {
61+ let Some ( address_raw ) = req. match_info ( ) . get ( "address" ) else {
6162 return HttpResponse :: BadRequest ( )
6263 . json ( AppResponse :: new_unsucessfull ( "Missing address" , 400 ) ) ;
6364 } ;
6465
65- // TODO: validate valid ethereum address
66+ // Check that the address is a valid ethereum address
67+ if alloy:: primitives:: Address :: from_str ( address_raw. trim ( ) ) . is_err ( ) {
68+ return HttpResponse :: BadRequest ( )
69+ . json ( AppResponse :: new_unsucessfull ( "Invalid address" , 400 ) ) ;
70+ }
71+
72+ let address = address_raw. to_lowercase ( ) ;
73+
6674 let Some ( state) = req. app_data :: < Data < BatcherServer > > ( ) else {
6775 return HttpResponse :: InternalServerError ( )
6876 . json ( AppResponse :: new_unsucessfull ( "Internal server error" , 500 ) ) ;
6977 } ;
7078
7179 let state = state. get_ref ( ) ;
72- match state. db . count_tasks_by_address ( address) . await {
80+ match state. db . count_tasks_by_address ( & address) . await {
7381 Ok ( count) => HttpResponse :: Ok ( ) . json ( AppResponse :: new_sucessfull ( serde_json:: json!(
7482 {
7583 "nonce" : count
@@ -80,6 +88,7 @@ impl BatcherServer {
8088 }
8189 }
8290
91+ // Posts an SP1 proof to the batcher, recovering the address from the signature
8392 async fn post_proof_sp1 (
8493 req : HttpRequest ,
8594 MultipartForm ( data) : MultipartForm < SubmitProofRequestSP1 > ,
@@ -172,6 +181,7 @@ impl BatcherServer {
172181 & proof_content,
173182 & vk_content,
174183 None ,
184+ data. nonce . 0 as i64 ,
175185 )
176186 . await
177187 {
@@ -184,65 +194,89 @@ impl BatcherServer {
184194 }
185195
186196 /// TODO: complete for risc0 (see `post_proof_sp1`)
197+ // Posts a Risc0 proof to the batcher, recovering the address from the signature
187198 async fn post_proof_risc0 (
188199 _req : HttpRequest ,
189200 MultipartForm ( _) : MultipartForm < SubmitProofRequestRisc0 > ,
190201 ) -> impl Responder {
191202 HttpResponse :: Ok ( ) . json ( AppResponse :: new_sucessfull ( serde_json:: json!( { } ) ) )
192203 }
193204
194- async fn get_proof_merkle_path (
205+ // Returns the last 100 receipt merkle proofs for the address received in the URL.
206+ // In case of also receiving a nonce on the query param, it returns only the merkle proof for that nonce.
207+ async fn get_receipts (
195208 req : HttpRequest ,
196- params : web:: Query < GetProofMerklePathQueryParams > ,
209+ params : web:: Query < GetReceiptsQueryParams > ,
197210 ) -> impl Responder {
198211 let Some ( state) = req. app_data :: < Data < BatcherServer > > ( ) else {
199- return HttpResponse :: InternalServerError ( )
200- . json ( AppResponse :: new_unsucessfull ( "Internal server error" , 500 ) ) ;
212+ return HttpResponse :: InternalServerError ( ) . json ( AppResponse :: new_unsucessfull (
213+ "Internal server error: Failed to get app data" ,
214+ 500 ,
215+ ) ) ;
201216 } ;
202217
203218 let state = state. get_ref ( ) ;
204219
205- // TODO: maybe also accept proof commitment in query param
206- let Some ( id) = params. id . clone ( ) else {
207- return HttpResponse :: BadRequest ( ) . json ( AppResponse :: new_unsucessfull (
208- "Provide task `id` query param" ,
209- 400 ,
210- ) ) ;
211- } ;
212-
213- if id. is_empty ( ) {
214- return HttpResponse :: BadRequest ( ) . json ( AppResponse :: new_unsucessfull (
215- "Proof id cannot be empty" ,
216- 400 ,
217- ) ) ;
220+ if alloy:: primitives:: Address :: from_str ( params. address . clone ( ) . trim ( ) ) . is_err ( ) {
221+ return HttpResponse :: BadRequest ( )
222+ . json ( AppResponse :: new_unsucessfull ( "Invalid address" , 400 ) ) ;
218223 }
219224
220- let Ok ( proof_id ) = sqlx :: types :: Uuid :: parse_str ( & id ) else {
221- return HttpResponse :: BadRequest ( )
222- . json ( AppResponse :: new_unsucessfull ( "Proof id invalid uuid" , 400 ) ) ;
225+ let limit = match params . limit {
226+ Some ( received_limit ) => received_limit . min ( 100 ) ,
227+ None => 100 ,
223228 } ;
224229
225- let db_result = state. db . get_merkle_path_by_task_id ( proof_id) . await ;
226- let merkle_path = match db_result {
227- Ok ( Some ( merkle_path) ) => merkle_path,
228- Ok ( None ) => {
229- return HttpResponse :: NotFound ( ) . json ( AppResponse :: new_unsucessfull (
230- "Proof merkle path not found" ,
231- 404 ,
232- ) )
233- }
234- Err ( _) => {
235- return HttpResponse :: InternalServerError ( )
236- . json ( AppResponse :: new_unsucessfull ( "Internal server error" , 500 ) ) ;
237- }
230+ let address = params. address . to_lowercase ( ) ;
231+
232+ let query = if let Some ( nonce) = params. nonce {
233+ state
234+ . db
235+ . get_tasks_by_address_and_nonce ( & address, nonce)
236+ . await
237+ } else {
238+ state
239+ . db
240+ . get_tasks_by_address_with_limit ( & address, limit)
241+ . await
238242 } ;
239243
240- match format_merkle_path ( & merkle_path) {
241- Ok ( merkle_path) => {
242- HttpResponse :: Ok ( ) . json ( AppResponse :: new_sucessfull ( serde_json:: json!( {
243- "merkle_path" : merkle_path
244- } ) ) )
245- }
244+ let Ok ( receipts) = query else {
245+ return HttpResponse :: InternalServerError ( ) . json ( AppResponse :: new_unsucessfull (
246+ "Internal server error: Failed to get tasks by address and nonce" ,
247+ 500 ,
248+ ) ) ;
249+ } ;
250+
251+ let responses: Result < Vec < GetReceiptsResponse > , String > = receipts
252+ . into_iter ( )
253+ . map ( |receipt| {
254+ let Some ( merkle_path) = receipt. merkle_path else {
255+ return Ok ( GetReceiptsResponse {
256+ status : receipt. status ,
257+ merkle_path : Vec :: new ( ) ,
258+ nonce : receipt. nonce ,
259+ address : receipt. address ,
260+ } ) ;
261+ } ;
262+
263+ let Ok ( formatted) = format_merkle_path ( & merkle_path) else {
264+ return Err ( "Error formatting merkle path" . into ( ) ) ;
265+ } ;
266+
267+ Ok ( GetReceiptsResponse {
268+ status : receipt. status ,
269+ merkle_path : formatted,
270+ nonce : receipt. nonce ,
271+ address : receipt. address ,
272+ } )
273+ } )
274+ . collect ( ) ;
275+
276+ match responses {
277+ Ok ( resp) => HttpResponse :: Ok ( ) . json ( AppResponse :: new_sucessfull ( serde_json:: json!( {
278+ "receipts" : resp
279+ } ) ) ) ,
246280 Err ( _) => HttpResponse :: InternalServerError ( )
247281 . json ( AppResponse :: new_unsucessfull ( "Internal server error" , 500 ) ) ,
248282 }
0 commit comments