@@ -2,6 +2,7 @@ use std::error::Error;
22use std:: path:: { Path , PathBuf } ;
33
44use starknet_api:: transaction:: fields:: Proof ;
5+ use starknet_api:: transaction:: TransactionHash ;
56use starknet_types_core:: felt:: Felt ;
67use thiserror:: Error ;
78use tokio:: io:: AsyncWriteExt ;
@@ -13,9 +14,22 @@ mod proof_storage_test;
1314#[ async_trait:: async_trait]
1415pub trait ProofStorage : Send + Sync {
1516 type Error : Error ;
16- async fn set_proof ( & self , facts_hash : Felt , proof : Proof ) -> Result < ( ) , Self :: Error > ;
17- async fn get_proof ( & self , facts_hash : Felt ) -> Result < Option < Proof > , Self :: Error > ;
18- async fn contains_proof ( & self , facts_hash : Felt ) -> Result < bool , Self :: Error > ;
17+ async fn set_proof (
18+ & self ,
19+ facts_hash : Felt ,
20+ tx_hash : TransactionHash ,
21+ proof : Proof ,
22+ ) -> Result < ( ) , Self :: Error > ;
23+ async fn get_proof (
24+ & self ,
25+ facts_hash : Felt ,
26+ tx_hash : TransactionHash ,
27+ ) -> Result < Option < Proof > , Self :: Error > ;
28+ async fn contains_proof (
29+ & self ,
30+ facts_hash : Felt ,
31+ tx_hash : TransactionHash ,
32+ ) -> Result < bool , Self :: Error > ;
1933}
2034
2135#[ derive( Debug , Error ) ]
@@ -40,27 +54,30 @@ impl FsProofStorage {
4054 Ok ( Self { persistent_root } )
4155 }
4256
43- /// Returns the directory that will hold the proof of a certain proof facts hash.
44- /// For a proof facts hash: 0xa1b2c3d4... (rest of hash) , the structure is:
57+ /// Returns the directory that will hold the proof of a certain proof facts hash and tx hash .
58+ /// For a proof facts hash: 0xa1b2c3d4... and tx hash, the structure is:
4559 /// a1/
4660 /// └── b2/
4761 /// └── a1b2c3d4.../
48- fn get_proof_dir ( & self , facts_hash : Felt ) -> PathBuf {
49- let facts_hash = hex:: encode ( facts_hash. to_bytes_be ( ) ) ;
50- let ( first_msb_byte, second_msb_byte, _rest_of_bytes) =
51- ( & facts_hash[ ..2 ] , & facts_hash[ 2 ..4 ] , & facts_hash[ 4 ..] ) ;
52- PathBuf :: from ( first_msb_byte) . join ( second_msb_byte) . join ( facts_hash)
62+ /// └── <tx_hash_hex>/
63+ fn get_proof_dir ( & self , facts_hash : Felt , tx_hash : TransactionHash ) -> PathBuf {
64+ let facts_hash_hex = hex:: encode ( facts_hash. to_bytes_be ( ) ) ;
65+ let ( first_msb_byte, second_msb_byte, _rest) =
66+ ( & facts_hash_hex[ ..2 ] , & facts_hash_hex[ 2 ..4 ] , & facts_hash_hex[ 4 ..] ) ;
67+ let tx_hash_hex = hex:: encode ( tx_hash. 0 . to_bytes_be ( ) ) ;
68+ PathBuf :: from ( first_msb_byte) . join ( second_msb_byte) . join ( & facts_hash_hex) . join ( tx_hash_hex)
5369 }
5470
55- fn get_persistent_dir ( & self , facts_hash : Felt ) -> PathBuf {
56- self . persistent_root . join ( self . get_proof_dir ( facts_hash) )
71+ fn get_persistent_dir ( & self , facts_hash : Felt , tx_hash : TransactionHash ) -> PathBuf {
72+ self . persistent_root . join ( self . get_proof_dir ( facts_hash, tx_hash ) )
5773 }
5874
5975 async fn get_persistent_dir_with_create (
6076 & self ,
6177 facts_hash : Felt ,
78+ tx_hash : TransactionHash ,
6279 ) -> FsProofStorageResult < PathBuf > {
63- let path = self . get_persistent_dir ( facts_hash) ;
80+ let path = self . get_persistent_dir ( facts_hash, tx_hash ) ;
6481 if let Some ( parent) = path. parent ( ) {
6582 tokio:: fs:: create_dir_all ( parent) . await ?;
6683 }
@@ -71,9 +88,10 @@ impl FsProofStorage {
7188 async fn create_tmp_dir (
7289 & self ,
7390 facts_hash : Felt ,
91+ tx_hash : TransactionHash ,
7492 ) -> FsProofStorageResult < ( tempfile:: TempDir , PathBuf ) > {
75- // Compute the final persistent directory for this `facts_hash`
76- let persistent_dir = self . get_persistent_dir ( facts_hash) ;
93+ // Compute the final persistent directory for this `facts_hash` and `tx_hash`
94+ let persistent_dir = self . get_persistent_dir ( facts_hash, tx_hash ) ;
7795 let parent_dir = persistent_dir
7896 . parent ( )
7997 . expect ( "Proof persistent dir should have a parent" )
@@ -106,26 +124,32 @@ impl FsProofStorage {
106124 }
107125
108126 /// Reads a proof from a file in binary format.
109- async fn read_proof_from_file ( & self , facts_hash : Felt ) -> FsProofStorageResult < Proof > {
110- let file_path = self . get_persistent_dir ( facts_hash) . join ( "proof" ) ;
127+ async fn read_proof_from_file (
128+ & self ,
129+ facts_hash : Felt ,
130+ tx_hash : TransactionHash ,
131+ ) -> FsProofStorageResult < Proof > {
132+ let file_path = self . get_persistent_dir ( facts_hash, tx_hash) . join ( "proof" ) ;
111133 let buffer = tokio:: fs:: read ( & file_path) . await ?;
112134 Ok ( Proof :: from ( buffer) )
113135 }
114136
115137 async fn write_proof_atomically (
116138 & self ,
117139 facts_hash : Felt ,
140+ tx_hash : TransactionHash ,
118141 proof : Proof ,
119142 ) -> FsProofStorageResult < ( ) > {
120143 // Write proof to a temporary directory.
121- let ( _tmp_root, tmp_dir) = self . create_tmp_dir ( facts_hash) . await ?;
144+ let ( _tmp_root, tmp_dir) = self . create_tmp_dir ( facts_hash, tx_hash ) . await ?;
122145 self . write_proof_to_file ( & tmp_dir, & proof) . await ?;
123146
124147 // Atomically rename directory to persistent one.
125148 // If a concurrent write already placed the proof at the persistent path, the rename
126149 // will fail (e.g. ENOTEMPTY on Linux). Since proofs are deterministic for a given
127- // facts_hash, the existing proof is identical and we can safely treat this as success.
128- let persistent_dir = self . get_persistent_dir_with_create ( facts_hash) . await ?;
150+ // facts_hash and tx_hash, the existing proof is identical and we can safely treat this as
151+ // success.
152+ let persistent_dir = self . get_persistent_dir_with_create ( facts_hash, tx_hash) . await ?;
129153 match tokio:: fs:: rename ( & tmp_dir, & persistent_dir) . await {
130154 Ok ( ( ) ) => Ok ( ( ) ) ,
131155 Err ( _)
@@ -142,16 +166,25 @@ impl FsProofStorage {
142166impl ProofStorage for FsProofStorage {
143167 type Error = FsProofStorageError ;
144168
145- async fn set_proof ( & self , facts_hash : Felt , proof : Proof ) -> Result < ( ) , Self :: Error > {
146- self . write_proof_atomically ( facts_hash, proof) . await
169+ async fn set_proof (
170+ & self ,
171+ facts_hash : Felt ,
172+ tx_hash : TransactionHash ,
173+ proof : Proof ,
174+ ) -> Result < ( ) , Self :: Error > {
175+ self . write_proof_atomically ( facts_hash, tx_hash, proof) . await
147176 }
148177
149- async fn get_proof ( & self , facts_hash : Felt ) -> Result < Option < Proof > , Self :: Error > {
150- if !self . contains_proof ( facts_hash) . await ? {
178+ async fn get_proof (
179+ & self ,
180+ facts_hash : Felt ,
181+ tx_hash : TransactionHash ,
182+ ) -> Result < Option < Proof > , Self :: Error > {
183+ if !self . contains_proof ( facts_hash, tx_hash) . await ? {
151184 return Ok ( None ) ;
152185 }
153186
154- match self . read_proof_from_file ( facts_hash) . await {
187+ match self . read_proof_from_file ( facts_hash, tx_hash ) . await {
155188 Ok ( proof) => Ok ( Some ( proof) ) ,
156189 Err ( FsProofStorageError :: IoError ( e) ) if e. kind ( ) == std:: io:: ErrorKind :: NotFound => {
157190 Ok ( None )
@@ -160,7 +193,11 @@ impl ProofStorage for FsProofStorage {
160193 }
161194 }
162195
163- async fn contains_proof ( & self , facts_hash : Felt ) -> Result < bool , Self :: Error > {
164- Ok ( tokio:: fs:: try_exists ( self . get_persistent_dir ( facts_hash) ) . await ?)
196+ async fn contains_proof (
197+ & self ,
198+ facts_hash : Felt ,
199+ tx_hash : TransactionHash ,
200+ ) -> Result < bool , Self :: Error > {
201+ Ok ( tokio:: fs:: try_exists ( self . get_persistent_dir ( facts_hash, tx_hash) ) . await ?)
165202 }
166203}
0 commit comments