@@ -25,11 +25,15 @@ use katana_primitives::class::{
2525} ;
2626use katana_primitives:: contract:: { ContractAddress , Nonce , StorageKey , StorageValue } ;
2727use katana_primitives:: transaction:: TxHash ;
28+ use katana_primitives:: Felt ;
2829use katana_rpc_client:: starknet:: {
2930 Client as StarknetClient , Error as StarknetClientError , StarknetApiError ,
3031} ;
3132use katana_rpc_types:: class:: Class ;
32- use katana_rpc_types:: { GetBlockWithReceiptsResponse , StateUpdate , TxReceiptWithBlockInfo } ;
33+ use katana_rpc_types:: {
34+ ContractStorageKeys , GetBlockWithReceiptsResponse , GetStorageProofResponse , StateUpdate ,
35+ TxReceiptWithBlockInfo ,
36+ } ;
3337use parking_lot:: Mutex ;
3438use tracing:: { error, trace} ;
3539
@@ -246,6 +250,105 @@ impl Backend {
246250 }
247251 }
248252
253+ pub fn get_classes_proofs (
254+ & self ,
255+ classes : Vec < ClassHash > ,
256+ block_id : BlockNumber ,
257+ ) -> Result < Option < GetStorageProofResponse > , BackendClientError > {
258+ trace ! ( classes = %classes. len( ) , block = %block_id, "Requesting classes proofs." ) ;
259+ let ( req, rx) = BackendRequest :: classes_proof ( classes, block_id) ;
260+ self . request ( req) ?;
261+ match rx. recv ( ) ? {
262+ BackendResponse :: Proofs ( res) => {
263+ if let Some ( proofs) = handle_not_found_err ( res) ? {
264+ Ok ( Some ( proofs) )
265+ } else {
266+ Ok ( None )
267+ }
268+ }
269+ response => Err ( BackendClientError :: UnexpectedResponse ( anyhow ! ( "{response:?}" ) ) ) ,
270+ }
271+ }
272+
273+ pub fn get_contracts_proofs (
274+ & self ,
275+ contracts : Vec < ContractAddress > ,
276+ block_id : BlockNumber ,
277+ ) -> Result < Option < GetStorageProofResponse > , BackendClientError > {
278+ trace ! ( contracts = %contracts. len( ) , block = %block_id, "Requesting contracts proofs." ) ;
279+ let ( req, rx) = BackendRequest :: contracts_proof ( contracts, block_id) ;
280+ self . request ( req) ?;
281+ match rx. recv ( ) ? {
282+ BackendResponse :: Proofs ( res) => {
283+ if let Some ( proofs) = handle_not_found_err ( res) ? {
284+ Ok ( Some ( proofs) )
285+ } else {
286+ Ok ( None )
287+ }
288+ }
289+ response => Err ( BackendClientError :: UnexpectedResponse ( anyhow ! ( "{response:?}" ) ) ) ,
290+ }
291+ }
292+
293+ pub fn get_storages_proofs (
294+ & self ,
295+ storages : Vec < ContractStorageKeys > ,
296+ block_id : BlockNumber ,
297+ ) -> Result < Option < GetStorageProofResponse > , BackendClientError > {
298+ trace ! ( contracts = %storages. len( ) , block = %block_id, "Requesting storages proofs." ) ;
299+ let ( req, rx) = BackendRequest :: storages_proof ( storages, block_id) ;
300+ self . request ( req) ?;
301+ match rx. recv ( ) ? {
302+ BackendResponse :: Proofs ( res) => {
303+ if let Some ( proofs) = handle_not_found_err ( res) ? {
304+ Ok ( Some ( proofs) )
305+ } else {
306+ Ok ( None )
307+ }
308+ }
309+ response => Err ( BackendClientError :: UnexpectedResponse ( anyhow ! ( "{response:?}" ) ) ) ,
310+ }
311+ }
312+
313+ pub fn get_global_roots (
314+ & self ,
315+ block_id : BlockNumber ,
316+ ) -> Result < Option < GetStorageProofResponse > , BackendClientError > {
317+ trace ! ( block = %block_id, "Requesting state roots." ) ;
318+ let ( req, rx) = BackendRequest :: global_roots ( block_id) ;
319+ self . request ( req) ?;
320+ match rx. recv ( ) ? {
321+ BackendResponse :: GlobalRoots ( res) => {
322+ if let Some ( roots) = handle_not_found_err ( res) ? {
323+ Ok ( Some ( roots) )
324+ } else {
325+ Ok ( None )
326+ }
327+ }
328+ response => Err ( BackendClientError :: UnexpectedResponse ( anyhow ! ( "{response:?}" ) ) ) ,
329+ }
330+ }
331+
332+ pub fn get_storage_root (
333+ & self ,
334+ contract : ContractAddress ,
335+ block_id : BlockNumber ,
336+ ) -> Result < Option < Felt > , BackendClientError > {
337+ trace ! ( %contract, block = %block_id, "Requesting storage root." ) ;
338+ let ( req, rx) = BackendRequest :: storage_root ( contract, block_id) ;
339+ self . request ( req) ?;
340+ match rx. recv ( ) ? {
341+ BackendResponse :: StorageRoot ( res) => {
342+ if let Some ( root) = handle_not_found_err ( res) ? {
343+ Ok ( Some ( root) )
344+ } else {
345+ Ok ( None )
346+ }
347+ }
348+ response => Err ( BackendClientError :: UnexpectedResponse ( anyhow ! ( "{response:?}" ) ) ) ,
349+ }
350+ }
351+
249352 /// Send a request to the backend thread.
250353 fn request ( & self , req : BackendRequest ) -> Result < ( ) , BackendClientError > {
251354 self . sender . lock ( ) . try_send ( req) . map_err ( |e| e. into_send_error ( ) ) ?;
@@ -277,6 +380,9 @@ enum BackendResponse {
277380 Storage ( BackendResult < StorageValue > ) ,
278381 ClassHashAt ( BackendResult < ClassHash > ) ,
279382 ClassAt ( BackendResult < Class > ) ,
383+ StorageRoot ( BackendResult < Felt > ) ,
384+ GlobalRoots ( BackendResult < GetStorageProofResponse > ) ,
385+ Proofs ( BackendResult < GetStorageProofResponse > ) ,
280386}
281387
282388/// Errors that can occur when interacting with the backend.
@@ -295,16 +401,26 @@ struct Request<P> {
295401 sender : OneshotSender < BackendResponse > ,
296402}
297403
404+ #[ derive( Eq , Hash , PartialEq , Clone , Debug ) ]
405+ enum ProofsType {
406+ Classes ( Vec < ClassHash > ) ,
407+ Contracts ( Vec < ContractAddress > ) ,
408+ Storages ( Vec < ContractStorageKeys > ) ,
409+ }
410+
298411/// The types of request that can be sent to [`Backend`].
299412///
300413/// Each request consists of a payload and the sender half of a oneshot channel that will be used
301414/// to send the result back to the backend handle.
302415enum BackendRequest {
303416 Receipt ( Request < TxHash > ) ,
417+ GlobalRoots ( Request < BlockNumber > ) ,
418+ StorageRoot ( Request < ( ContractAddress , BlockNumber ) > ) ,
304419 Block ( Request < BlockHashOrNumber > ) ,
305420 StateUpdate ( Request < BlockHashOrNumber > ) ,
306- Nonce ( Request < ( ContractAddress , BlockNumber ) > ) ,
307421 Class ( Request < ( ClassHash , BlockNumber ) > ) ,
422+ Proofs ( Request < ( ProofsType , BlockNumber ) > ) ,
423+ Nonce ( Request < ( ContractAddress , BlockNumber ) > ) ,
308424 ClassHash ( Request < ( ContractAddress , BlockNumber ) > ) ,
309425 Storage ( Request < ( ( ContractAddress , StorageKey ) , BlockNumber ) > ) ,
310426}
@@ -364,16 +480,59 @@ impl BackendRequest {
364480 let ( sender, receiver) = oneshot ( ) ;
365481 ( BackendRequest :: Storage ( Request { payload : ( ( address, key) , block_id) , sender } ) , receiver)
366482 }
483+
484+ fn classes_proof (
485+ classes : Vec < ClassHash > ,
486+ block_id : BlockNumber ,
487+ ) -> ( BackendRequest , OneshotReceiver < BackendResponse > ) {
488+ let ( sender, receiver) = oneshot ( ) ;
489+ let payload = ( ProofsType :: Classes ( classes) , block_id) ;
490+ ( BackendRequest :: Proofs ( Request { payload, sender } ) , receiver)
491+ }
492+
493+ fn contracts_proof (
494+ contracts : Vec < ContractAddress > ,
495+ block_id : BlockNumber ,
496+ ) -> ( BackendRequest , OneshotReceiver < BackendResponse > ) {
497+ let ( sender, receiver) = oneshot ( ) ;
498+ let payload = ( ProofsType :: Contracts ( contracts) , block_id) ;
499+ ( BackendRequest :: Proofs ( Request { payload, sender } ) , receiver)
500+ }
501+
502+ fn storages_proof (
503+ storages : Vec < ContractStorageKeys > ,
504+ block_id : BlockNumber ,
505+ ) -> ( BackendRequest , OneshotReceiver < BackendResponse > ) {
506+ let ( sender, receiver) = oneshot ( ) ;
507+ let payload = ( ProofsType :: Storages ( storages) , block_id) ;
508+ ( BackendRequest :: Proofs ( Request { payload, sender } ) , receiver)
509+ }
510+
511+ fn global_roots ( block_id : BlockNumber ) -> ( BackendRequest , OneshotReceiver < BackendResponse > ) {
512+ let ( sender, receiver) = oneshot ( ) ;
513+ ( BackendRequest :: GlobalRoots ( Request { payload : block_id, sender } ) , receiver)
514+ }
515+
516+ fn storage_root (
517+ contract : ContractAddress ,
518+ block_id : BlockNumber ,
519+ ) -> ( BackendRequest , OneshotReceiver < BackendResponse > ) {
520+ let ( sender, receiver) = oneshot ( ) ;
521+ ( BackendRequest :: StorageRoot ( Request { payload : ( contract, block_id) , sender } ) , receiver)
522+ }
367523}
368524
369525type BackendRequestFuture = BoxFuture < ' static , BackendResponse > ;
370526
371527// Identifier for pending requests.
372528// This is used for request deduplication.
373- #[ derive( Eq , Hash , PartialEq , Clone , Copy , Debug ) ]
529+ #[ derive( Eq , Hash , PartialEq , Clone , Debug ) ]
374530enum BackendRequestIdentifier {
375531 Receipt ( TxHash ) ,
532+ GlobalRoots ( BlockNumber ) ,
533+ StorageRoot ( ContractAddress , BlockNumber ) ,
376534 Block ( BlockHashOrNumber ) ,
535+ Proofs ( ProofsType , BlockNumber ) ,
377536 StateUpdate ( BlockHashOrNumber ) ,
378537 Nonce ( ContractAddress , BlockNumber ) ,
379538 Class ( ClassHash , BlockNumber ) ,
@@ -554,6 +713,86 @@ impl BackendWorker {
554713 } ) ,
555714 ) ;
556715 }
716+
717+ BackendRequest :: Proofs ( Request { payload : ( r#type, block_id) , sender } ) => {
718+ let req_key = BackendRequestIdentifier :: Proofs ( r#type. clone ( ) , block_id) ;
719+ let block_id = BlockIdOrTag :: from ( block_id) ;
720+
721+ let request: BoxFuture < ' static , BackendResponse > = match r#type {
722+ ProofsType :: Classes ( classes) => Box :: pin ( async move {
723+ let res = provider
724+ . get_storage_proof ( block_id, Some ( classes) , None , None )
725+ . await
726+ . map_err ( |e| BackendError :: StarknetProvider ( Arc :: new ( e) ) ) ;
727+
728+ BackendResponse :: Proofs ( res)
729+ } ) ,
730+
731+ ProofsType :: Contracts ( contracts) => Box :: pin ( async move {
732+ let res = provider
733+ . get_storage_proof ( block_id, None , Some ( contracts) , None )
734+ . await
735+ . map_err ( |e| BackendError :: StarknetProvider ( Arc :: new ( e) ) ) ;
736+
737+ BackendResponse :: Proofs ( res)
738+ } ) ,
739+
740+ ProofsType :: Storages ( storage_keys) => Box :: pin ( async move {
741+ let res = provider
742+ . get_storage_proof ( block_id, None , None , Some ( storage_keys) )
743+ . await
744+ . map_err ( |e| BackendError :: StarknetProvider ( Arc :: new ( e) ) ) ;
745+
746+ BackendResponse :: Proofs ( res)
747+ } ) ,
748+ } ;
749+
750+ self . dedup_request ( req_key, sender, request) ;
751+ }
752+
753+ BackendRequest :: GlobalRoots ( Request { payload : block_id, sender } ) => {
754+ let req_key = BackendRequestIdentifier :: GlobalRoots ( block_id) ;
755+ let block_id = BlockIdOrTag :: from ( block_id) ;
756+
757+ self . dedup_request (
758+ req_key,
759+ sender,
760+ Box :: pin ( async move {
761+ let res = provider
762+ . get_storage_proof ( block_id, None , None , None )
763+ . await
764+ . map_err ( |e| BackendError :: StarknetProvider ( Arc :: new ( e) ) ) ;
765+
766+ BackendResponse :: GlobalRoots ( res)
767+ } ) ,
768+ ) ;
769+ }
770+
771+ BackendRequest :: StorageRoot ( Request { payload : ( contract, block_id) , sender } ) => {
772+ let req_key = BackendRequestIdentifier :: StorageRoot ( contract, block_id) ;
773+ let block_id = BlockIdOrTag :: from ( block_id) ;
774+
775+ self . dedup_request (
776+ req_key,
777+ sender,
778+ Box :: pin ( async move {
779+ let res = provider
780+ . get_storage_proof ( block_id, None , Some ( vec ! [ contract] ) , None )
781+ . await
782+ . map ( |mut proof| {
783+ proof
784+ . contracts_proof
785+ . contract_leaves_data
786+ . pop ( )
787+ . expect ( "must exist" )
788+ . storage_root
789+ } )
790+ . map_err ( |e| BackendError :: StarknetProvider ( Arc :: new ( e) ) ) ;
791+
792+ BackendResponse :: StorageRoot ( res)
793+ } ) ,
794+ ) ;
795+ }
557796 }
558797 }
559798
@@ -563,7 +802,7 @@ impl BackendWorker {
563802 sender : OneshotSender < BackendResponse > ,
564803 rpc_call_future : BoxFuture < ' static , BackendResponse > ,
565804 ) {
566- if let Entry :: Vacant ( e) = self . request_dedup_map . entry ( req_key) {
805+ if let Entry :: Vacant ( e) = self . request_dedup_map . entry ( req_key. clone ( ) ) {
567806 self . pending_requests . push ( ( req_key, rpc_call_future) ) ;
568807 e. insert ( vec ! [ sender] ) ;
569808 } else {
0 commit comments