@@ -12,11 +12,8 @@ use mithril_common::{
12
12
StdResult ,
13
13
} ;
14
14
15
- #[ cfg( test) ]
16
- use mockall:: automock;
17
-
18
15
/// Prover service is the cryptographic engine in charge of producing cryptographic proofs for transactions
19
- #[ cfg_attr( test, automock) ]
16
+ #[ cfg_attr( test, mockall :: automock) ]
20
17
#[ async_trait]
21
18
pub trait ProverService : Sync + Send {
22
19
/// Compute the cryptographic proofs for the given transactions
@@ -28,11 +25,17 @@ pub trait ProverService: Sync + Send {
28
25
}
29
26
30
27
/// Transactions retriever
31
- #[ cfg_attr( test, automock) ]
28
+ #[ cfg_attr( test, mockall :: automock) ]
32
29
#[ async_trait]
33
30
pub trait TransactionsRetriever : Sync + Send {
34
- /// Get transactions up to given beacon using chronological order
31
+ /// Get all transactions up to given beacon using chronological order
35
32
async fn get_up_to ( & self , beacon : & CardanoDbBeacon ) -> StdResult < Vec < CardanoTransaction > > ;
33
+
34
+ /// Get a list of transactions by hashes using chronological order
35
+ async fn get_by_hashes (
36
+ & self ,
37
+ hashes : Vec < TransactionHash > ,
38
+ ) -> StdResult < Vec < CardanoTransaction > > ;
36
39
}
37
40
38
41
/// Mithril prover
@@ -48,9 +51,24 @@ impl MithrilProverService {
48
51
}
49
52
}
50
53
54
+ async fn get_transactions_by_hashes_with_block_range (
55
+ & self ,
56
+ hashes : Vec < TransactionHash > ,
57
+ ) -> StdResult < Vec < ( BlockRange , CardanoTransaction ) > > {
58
+ let transactions = self . transaction_retriever . get_by_hashes ( hashes) . await ?;
59
+ let transactions_with_block_range = transactions
60
+ . into_iter ( )
61
+ . map ( |transaction| {
62
+ let block_range = BlockRange :: from_block_number ( transaction. block_number ) ;
63
+ ( block_range, transaction)
64
+ } )
65
+ . collect :: < Vec < _ > > ( ) ;
66
+ Ok ( transactions_with_block_range)
67
+ }
68
+
51
69
fn compute_merkle_map_from_transactions (
52
70
& self ,
53
- transactions : & [ CardanoTransaction ] ,
71
+ transactions : Vec < CardanoTransaction > ,
54
72
) -> StdResult < MKMap < BlockRange , MKMapNode < BlockRange > > > {
55
73
let mut transactions_by_block_ranges: HashMap < BlockRange , Vec < TransactionHash > > =
56
74
HashMap :: new ( ) ;
@@ -59,9 +77,9 @@ impl MithrilProverService {
59
77
transactions_by_block_ranges
60
78
. entry ( block_range)
61
79
. or_default ( )
62
- . push ( transaction. transaction_hash . to_owned ( ) ) ;
80
+ . push ( transaction. transaction_hash ) ;
63
81
}
64
- let mk_hash_map = MKMap :: new (
82
+ let mk_hash_map = MKMap :: new_from_iter (
65
83
transactions_by_block_ranges
66
84
. into_iter ( )
67
85
. try_fold (
@@ -70,8 +88,7 @@ impl MithrilProverService {
70
88
acc. push ( ( block_range, MKTree :: new ( & transactions) ?. into ( ) ) ) ;
71
89
Ok ( acc)
72
90
} ,
73
- ) ?
74
- . as_slice ( ) ,
91
+ ) ?,
75
92
)
76
93
. with_context ( || "ProverService failed to compute the merkelized structure that proves ownership of the transaction" ) ?;
77
94
@@ -86,17 +103,16 @@ impl ProverService for MithrilProverService {
86
103
up_to : & CardanoDbBeacon ,
87
104
transaction_hashes : & [ TransactionHash ] ,
88
105
) -> StdResult < Vec < CardanoTransactionsSetProof > > {
106
+ // 1 - Get transactions to prove per block range
107
+ let transactions_to_prove = self
108
+ . get_transactions_by_hashes_with_block_range ( transaction_hashes. to_vec ( ) )
109
+ . await ?;
110
+
111
+ // 2 - Compute Transactions Merkle Tree
89
112
let transactions = self . transaction_retriever . get_up_to ( up_to) . await ?;
90
- let mk_map = self . compute_merkle_map_from_transactions ( & transactions) ?;
91
- let transactions_to_prove = transactions
92
- . iter ( )
93
- . filter_map ( |transaction| {
94
- let block_range = BlockRange :: from_block_number ( transaction. block_number ) ;
95
- transaction_hashes
96
- . contains ( & transaction. transaction_hash )
97
- . then ( || ( block_range, transaction. to_owned ( ) ) )
98
- } )
99
- . collect :: < Vec < _ > > ( ) ;
113
+ let mk_map = self . compute_merkle_map_from_transactions ( transactions) ?;
114
+
115
+ // 3 - Compute proof for each transaction to prove
100
116
let mut transaction_hashes_certified = vec ! [ ] ;
101
117
for ( _block_range, transaction) in transactions_to_prove {
102
118
let mk_tree_node_transaction_hash: MKTreeNode =
@@ -105,9 +121,10 @@ impl ProverService for MithrilProverService {
105
121
. compute_proof ( & [ mk_tree_node_transaction_hash] )
106
122
. is_ok ( )
107
123
{
108
- transaction_hashes_certified. push ( transaction. transaction_hash . to_string ( ) ) ;
124
+ transaction_hashes_certified. push ( transaction. transaction_hash ) ;
109
125
}
110
126
}
127
+
111
128
if !transaction_hashes_certified. is_empty ( ) {
112
129
let mk_leaves: Vec < MKTreeNode > = transaction_hashes_certified
113
130
. iter ( )
@@ -154,15 +171,31 @@ mod tests {
154
171
( hashes, transactions)
155
172
}
156
173
174
+ fn build_prover < F > ( retriever_mock_config : F ) -> MithrilProverService
175
+ where
176
+ F : FnOnce ( & mut MockTransactionsRetriever ) ,
177
+ {
178
+ let mut transaction_retriever = MockTransactionsRetriever :: new ( ) ;
179
+ retriever_mock_config ( & mut transaction_retriever) ;
180
+
181
+ MithrilProverService :: new ( Arc :: new ( transaction_retriever) )
182
+ }
183
+
157
184
#[ tokio:: test]
158
185
async fn compute_proof_for_one_set_with_multiple_transactions ( ) {
159
186
let ( transaction_hashes, transactions) = generate_transactions ( 3 ) ;
160
- let mut transaction_retriever = MockTransactionsRetriever :: new ( ) ;
161
- transaction_retriever
162
- . expect_get_up_to ( )
163
- . with ( eq ( fake_data:: beacon ( ) ) )
164
- . return_once ( move |_| Ok ( transactions) ) ;
165
- let prover = MithrilProverService :: new ( Arc :: new ( transaction_retriever) ) ;
187
+ let prover = build_prover ( |retriever_mock| {
188
+ let transactions_by_hashes_res = transactions. clone ( ) ;
189
+ retriever_mock
190
+ . expect_get_by_hashes ( )
191
+ . with ( eq ( transaction_hashes. clone ( ) ) )
192
+ . return_once ( move |_| Ok ( transactions_by_hashes_res) ) ;
193
+ retriever_mock
194
+ . expect_get_up_to ( )
195
+ . with ( eq ( fake_data:: beacon ( ) ) )
196
+ . return_once ( move |_| Ok ( transactions) ) ;
197
+ } ) ;
198
+
166
199
let transactions_set_proof = prover
167
200
. compute_transactions_proofs ( & fake_data:: beacon ( ) , & transaction_hashes)
168
201
. await
@@ -178,13 +211,18 @@ mod tests {
178
211
179
212
#[ tokio:: test]
180
213
async fn cant_compute_proof_for_unknown_transaction ( ) {
181
- let ( transaction_hashes, _transactions) = generate_transactions ( 3 ) ;
182
- let mut transaction_retriever = MockTransactionsRetriever :: new ( ) ;
183
- transaction_retriever
184
- . expect_get_up_to ( )
185
- . with ( eq ( fake_data:: beacon ( ) ) )
186
- . returning ( |_| Ok ( vec ! [ ] ) ) ;
187
- let prover = MithrilProverService :: new ( Arc :: new ( transaction_retriever) ) ;
214
+ let ( transaction_hashes, transactions) = generate_transactions ( 3 ) ;
215
+ let prover = build_prover ( |retriever_mock| {
216
+ retriever_mock
217
+ . expect_get_by_hashes ( )
218
+ . with ( eq ( transaction_hashes. clone ( ) ) )
219
+ . return_once ( move |_| Ok ( transactions) ) ;
220
+ retriever_mock
221
+ . expect_get_up_to ( )
222
+ . with ( eq ( fake_data:: beacon ( ) ) )
223
+ . returning ( |_| Ok ( vec ! [ ] ) ) ;
224
+ } ) ;
225
+
188
226
let transactions_set_proof = prover
189
227
. compute_transactions_proofs ( & fake_data:: beacon ( ) , & transaction_hashes)
190
228
. await
@@ -196,14 +234,20 @@ mod tests {
196
234
#[ tokio:: test]
197
235
async fn compute_proof_for_one_set_of_three_known_transactions_and_two_unknowns ( ) {
198
236
let ( transaction_hashes, transactions) = generate_transactions ( 5 ) ;
199
- // The last two are not in the "store"
200
- let transactions = transactions[ 0 ..=2 ] . to_vec ( ) ;
201
- let mut transaction_retriever = MockTransactionsRetriever :: new ( ) ;
202
- transaction_retriever
203
- . expect_get_up_to ( )
204
- . with ( eq ( fake_data:: beacon ( ) ) )
205
- . return_once ( move |_| Ok ( transactions) ) ;
206
- let prover = MithrilProverService :: new ( Arc :: new ( transaction_retriever) ) ;
237
+ let prover = build_prover ( |retriever_mock| {
238
+ // The last two are not in the "store"
239
+ let transactions = transactions[ 0 ..=2 ] . to_vec ( ) ;
240
+ let transactions_by_hashes_res = transactions. clone ( ) ;
241
+ retriever_mock
242
+ . expect_get_by_hashes ( )
243
+ . with ( eq ( transaction_hashes. clone ( ) ) )
244
+ . return_once ( move |_| Ok ( transactions_by_hashes_res) ) ;
245
+ retriever_mock
246
+ . expect_get_up_to ( )
247
+ . with ( eq ( fake_data:: beacon ( ) ) )
248
+ . return_once ( move |_| Ok ( transactions) ) ;
249
+ } ) ;
250
+
207
251
let transactions_set_proof = prover
208
252
. compute_transactions_proofs ( & fake_data:: beacon ( ) , & transaction_hashes)
209
253
. await
@@ -220,13 +264,13 @@ mod tests {
220
264
#[ tokio:: test]
221
265
async fn cant_compute_proof_if_retriever_fail ( ) {
222
266
let ( transaction_hashes, _transactions) = generate_transactions ( 3 ) ;
223
- let mut transaction_retriever = MockTransactionsRetriever :: new ( ) ;
224
- transaction_retriever
225
- . expect_get_up_to ( )
226
- . with ( eq ( fake_data:: beacon ( ) ) )
227
- . returning ( |_| Err ( anyhow ! ( "Error" ) ) ) ;
267
+ let prover = build_prover ( |retriever_mock| {
268
+ retriever_mock
269
+ . expect_get_by_hashes ( )
270
+ . with ( eq ( transaction_hashes. clone ( ) ) )
271
+ . returning ( |_| Err ( anyhow ! ( "Error" ) ) ) ;
272
+ } ) ;
228
273
229
- let prover = MithrilProverService :: new ( Arc :: new ( transaction_retriever) ) ;
230
274
prover
231
275
. compute_transactions_proofs ( & fake_data:: beacon ( ) , & transaction_hashes)
232
276
. await
0 commit comments