1
- use std:: { collections :: HashMap , sync:: Arc } ;
1
+ use std:: sync:: Arc ;
2
2
3
3
use anyhow:: Context ;
4
4
use async_trait:: async_trait;
5
5
use slog:: { debug, Logger } ;
6
6
7
7
use crate :: {
8
- crypto_helper:: { MKMap , MKMapNode , MKTree , MKTreeNode } ,
9
- entities:: {
10
- BlockRange , CardanoDbBeacon , CardanoTransaction , ProtocolMessage , ProtocolMessagePartKey ,
11
- TransactionHash ,
12
- } ,
8
+ crypto_helper:: { MKMap , MKMapNode , MKTreeNode } ,
9
+ entities:: { BlockRange , CardanoDbBeacon , ProtocolMessage , ProtocolMessagePartKey } ,
13
10
signable_builder:: SignableBuilder ,
14
11
StdResult ,
15
12
} ;
@@ -23,65 +20,55 @@ use mockall::automock;
23
20
#[ async_trait]
24
21
pub trait TransactionsImporter : Send + Sync {
25
22
/// Returns all transactions up to the given beacon
26
- async fn import ( & self , up_to_beacon : ImmutableFileNumber )
27
- -> StdResult < Vec < CardanoTransaction > > ;
23
+ async fn import ( & self , up_to_beacon : ImmutableFileNumber ) -> StdResult < ( ) > ;
24
+ }
25
+
26
+ /// Block Range Merkle roots retriever
27
+ #[ cfg_attr( test, automock) ]
28
+ #[ async_trait]
29
+ pub trait BlockRangeRootRetriever : Send + Sync {
30
+ /// Returns a Merkle map of the block ranges roots up to a given beacon
31
+ async fn retrieve_block_range_roots (
32
+ & self ,
33
+ up_to_beacon : ImmutableFileNumber ,
34
+ ) -> StdResult < Box < dyn Iterator < Item = ( BlockRange , MKTreeNode ) > > > ;
35
+
36
+ /// Returns a Merkle map of the block ranges roots up to a given beacon
37
+ async fn compute_merkle_map_from_block_range_roots (
38
+ & self ,
39
+ up_to_beacon : ImmutableFileNumber ,
40
+ ) -> StdResult < MKMap < BlockRange , MKMapNode < BlockRange > > > {
41
+ let block_range_roots_iterator = self
42
+ . retrieve_block_range_roots ( up_to_beacon)
43
+ . await ?
44
+ . map ( |( block_range, root) | ( block_range, root. into ( ) ) ) ;
45
+ let mk_hash_map = MKMap :: new_from_iter ( block_range_roots_iterator)
46
+ . with_context ( || "ProverService failed to compute the merkelized structure that proves ownership of the transaction" ) ?;
47
+
48
+ Ok ( mk_hash_map)
49
+ }
28
50
}
29
51
30
52
/// A [CardanoTransactionsSignableBuilder] builder
31
53
pub struct CardanoTransactionsSignableBuilder {
32
54
transaction_importer : Arc < dyn TransactionsImporter > ,
55
+ block_range_root_retriever : Arc < dyn BlockRangeRootRetriever > ,
33
56
logger : Logger ,
34
57
}
35
58
36
59
impl CardanoTransactionsSignableBuilder {
37
60
/// Constructor
38
- pub fn new ( transaction_importer : Arc < dyn TransactionsImporter > , logger : Logger ) -> Self {
61
+ pub fn new (
62
+ transaction_importer : Arc < dyn TransactionsImporter > ,
63
+ block_range_root_retriever : Arc < dyn BlockRangeRootRetriever > ,
64
+ logger : Logger ,
65
+ ) -> Self {
39
66
Self {
40
67
transaction_importer,
68
+ block_range_root_retriever,
41
69
logger,
42
70
}
43
71
}
44
-
45
- // Note: Code duplicated from aggregator Prover service as is.
46
- // This will be not be the case when we use the cached intermediate merkle roots.
47
- fn compute_merkle_map_from_transactions (
48
- & self ,
49
- transactions : Vec < CardanoTransaction > ,
50
- ) -> StdResult < MKMap < BlockRange , MKMapNode < BlockRange > > > {
51
- let mut transactions_by_block_ranges: HashMap < BlockRange , Vec < TransactionHash > > =
52
- HashMap :: new ( ) ;
53
- for transaction in transactions {
54
- let block_range = BlockRange :: from_block_number ( transaction. block_number ) ;
55
- transactions_by_block_ranges
56
- . entry ( block_range)
57
- . or_default ( )
58
- . push ( transaction. transaction_hash ) ;
59
- }
60
- let mk_hash_map = MKMap :: new_from_iter (
61
- transactions_by_block_ranges
62
- . into_iter ( )
63
- . try_fold (
64
- vec ! [ ] ,
65
- |mut acc, ( block_range, transactions) | -> StdResult < Vec < ( _ , MKMapNode < _ > ) > > {
66
- acc. push ( ( block_range, MKTree :: new ( & transactions) ?. into ( ) ) ) ;
67
- Ok ( acc)
68
- } ,
69
- ) ?,
70
- )
71
- . with_context ( || "ProverService failed to compute the merkelized structure that proves ownership of the transaction" ) ?;
72
-
73
- Ok ( mk_hash_map)
74
- }
75
-
76
- fn compute_merkle_root ( & self , transactions : Vec < CardanoTransaction > ) -> StdResult < MKTreeNode > {
77
- let mk_map = self . compute_merkle_map_from_transactions ( transactions) ?;
78
-
79
- let mk_root = mk_map. compute_root ( ) . with_context ( || {
80
- "CardanoTransactionsSignableBuilder failed to compute MKHashMap root"
81
- } ) ?;
82
-
83
- Ok ( mk_root)
84
- }
85
72
}
86
73
87
74
#[ async_trait]
@@ -95,11 +82,15 @@ impl SignableBuilder<CardanoDbBeacon> for CardanoTransactionsSignableBuilder {
95
82
"Compute protocol message for CardanoTransactions at beacon: {beacon}"
96
83
) ;
97
84
98
- let transactions = self
99
- . transaction_importer
85
+ self . transaction_importer
100
86
. import ( beacon. immutable_file_number )
101
87
. await ?;
102
- let mk_root = self . compute_merkle_root ( transactions) ?;
88
+
89
+ let mk_root = self
90
+ . block_range_root_retriever
91
+ . compute_merkle_map_from_block_range_roots ( beacon. immutable_file_number )
92
+ . await ?
93
+ . compute_root ( ) ?;
103
94
104
95
let mut protocol_message = ProtocolMessage :: new ( ) ;
105
96
protocol_message. set_message_part (
@@ -117,104 +108,21 @@ impl SignableBuilder<CardanoDbBeacon> for CardanoTransactionsSignableBuilder {
117
108
118
109
#[ cfg( test) ]
119
110
mod tests {
120
- use crate :: test_utils:: TestLogger ;
121
-
122
- use super :: * ;
123
-
124
- #[ tokio:: test]
125
- async fn test_compute_merkle_root_in_same_block_range ( ) {
126
- let transaction_1 = CardanoTransaction :: new ( "tx-hash-123" , 1 , 10 , "block_hash" , 1 ) ;
127
- let transaction_2 = CardanoTransaction :: new ( "tx-hash-456" , 2 , 20 , "block_hash" , 1 ) ;
128
- let transaction_3 = CardanoTransaction :: new ( "tx-hash-789" , 3 , 30 , "block_hash" , 1 ) ;
129
- let transaction_4 = CardanoTransaction :: new ( "tx-hash-abc" , 4 , 40 , "block_hash" , 1 ) ;
130
-
131
- for tx in [
132
- & transaction_1,
133
- & transaction_2,
134
- & transaction_3,
135
- & transaction_4,
136
- ] {
137
- assert ! (
138
- tx. block_number < BlockRange :: LENGTH ,
139
- "all manipulated transactions should be in the same block range"
140
- ) ;
141
- }
142
-
143
- let cardano_transaction_signable_builder = CardanoTransactionsSignableBuilder :: new (
144
- Arc :: new ( MockTransactionsImporter :: new ( ) ) ,
145
- TestLogger :: stdout ( ) ,
146
- ) ;
147
111
148
- let merkle_root_reference = cardano_transaction_signable_builder
149
- . compute_merkle_root ( vec ! [
150
- transaction_1. clone( ) ,
151
- transaction_2. clone( ) ,
152
- transaction_3. clone( ) ,
153
- ] )
154
- . unwrap ( ) ;
112
+ use crate :: { entities:: CardanoTransaction , test_utils:: TestLogger } ;
155
113
156
- {
157
- let transactions_set = vec ! [ transaction_1. clone( ) ] ;
158
- let mk_root = cardano_transaction_signable_builder
159
- . compute_merkle_root ( transactions_set)
160
- . unwrap ( ) ;
161
- assert_ne ! ( merkle_root_reference, mk_root) ;
162
- }
163
- {
164
- let transactions_set = vec ! [ transaction_1. clone( ) , transaction_2. clone( ) ] ;
165
- let mk_root = cardano_transaction_signable_builder
166
- . compute_merkle_root ( transactions_set)
167
- . unwrap ( ) ;
168
- assert_ne ! ( merkle_root_reference, mk_root) ;
169
- }
170
- {
171
- let transactions_set = vec ! [
172
- transaction_1. clone( ) ,
173
- transaction_2. clone( ) ,
174
- transaction_3. clone( ) ,
175
- transaction_4. clone( ) ,
176
- ] ;
177
- let mk_root = cardano_transaction_signable_builder
178
- . compute_merkle_root ( transactions_set)
179
- . unwrap ( ) ;
180
- assert_ne ! ( merkle_root_reference, mk_root) ;
181
- }
182
-
183
- {
184
- // In a same block range Transactions in a different order return a different merkle root.
185
- let transactions_set = vec ! [
186
- transaction_1. clone( ) ,
187
- transaction_3. clone( ) ,
188
- transaction_2. clone( ) ,
189
- ] ;
190
- let mk_root = cardano_transaction_signable_builder
191
- . compute_merkle_root ( transactions_set)
192
- . unwrap ( ) ;
193
- assert_ne ! ( merkle_root_reference, mk_root) ;
194
- }
195
- }
196
-
197
- #[ tokio:: test]
198
- async fn test_compute_merkle_root_order_of_block_range_does_not_matter ( ) {
199
- let transaction_1 =
200
- CardanoTransaction :: new ( "tx-hash-123" , BlockRange :: LENGTH - 1 , 10 , "block_hash" , 1 ) ;
201
- let transaction_2 =
202
- CardanoTransaction :: new ( "tx-hash-456" , BlockRange :: LENGTH + 1 , 20 , "block_hash" , 1 ) ;
203
-
204
- let cardano_transaction_signable_builder = CardanoTransactionsSignableBuilder :: new (
205
- Arc :: new ( MockTransactionsImporter :: new ( ) ) ,
206
- TestLogger :: stdout ( ) ,
207
- ) ;
208
-
209
- let merkle_root_reference = cardano_transaction_signable_builder
210
- . compute_merkle_root ( vec ! [ transaction_1. clone( ) , transaction_2. clone( ) ] )
211
- . unwrap ( ) ;
212
-
213
- let mk_root = cardano_transaction_signable_builder
214
- . compute_merkle_root ( vec ! [ transaction_2. clone( ) , transaction_1. clone( ) ] )
215
- . unwrap ( ) ;
114
+ use super :: * ;
216
115
217
- assert_eq ! ( merkle_root_reference, mk_root) ;
116
+ fn compute_mk_map_from_transactions (
117
+ transactions : Vec < CardanoTransaction > ,
118
+ ) -> MKMap < BlockRange , MKMapNode < BlockRange > > {
119
+ MKMap :: new_from_iter ( transactions. iter ( ) . map ( |tx| {
120
+ (
121
+ BlockRange :: from_block_number ( tx. block_number ) ,
122
+ MKMapNode :: TreeNode ( tx. transaction_hash . clone ( ) . into ( ) ) ,
123
+ )
124
+ } ) )
125
+ . unwrap ( )
218
126
}
219
127
220
128
#[ tokio:: test]
@@ -229,13 +137,20 @@ mod tests {
229
137
CardanoTransaction :: new( "tx-hash-456" , 20 , 2 , "block_hash" , 12 ) ,
230
138
CardanoTransaction :: new( "tx-hash-789" , 30 , 3 , "block_hash" , 13 ) ,
231
139
] ;
232
- let imported_transactions = transactions. clone ( ) ;
140
+ let mk_map = compute_mk_map_from_transactions ( transactions. clone ( ) ) ;
233
141
let mut transaction_importer = MockTransactionsImporter :: new ( ) ;
234
142
transaction_importer
235
143
. expect_import ( )
236
- . return_once ( move |_| Ok ( imported_transactions) ) ;
144
+ . return_once ( move |_| Ok ( ( ) ) ) ;
145
+ let retrieved_transactions = transactions. clone ( ) ;
146
+ let mut block_range_root_retriever = MockBlockRangeRootRetriever :: new ( ) ;
147
+ block_range_root_retriever
148
+ . expect_compute_merkle_map_from_block_range_roots ( )
149
+ . return_once ( move |_| Ok ( compute_mk_map_from_transactions ( retrieved_transactions) ) ) ;
150
+
237
151
let cardano_transactions_signable_builder = CardanoTransactionsSignableBuilder :: new (
238
152
Arc :: new ( transaction_importer) ,
153
+ Arc :: new ( block_range_root_retriever) ,
239
154
TestLogger :: stdout ( ) ,
240
155
) ;
241
156
@@ -246,13 +161,10 @@ mod tests {
246
161
. unwrap ( ) ;
247
162
248
163
// Assert
249
- let mk_root = cardano_transactions_signable_builder
250
- . compute_merkle_root ( transactions)
251
- . unwrap ( ) ;
252
164
let mut signable_expected = ProtocolMessage :: new ( ) ;
253
165
signable_expected. set_message_part (
254
166
ProtocolMessagePartKey :: CardanoTransactionsMerkleRoot ,
255
- mk_root . to_hex ( ) ,
167
+ mk_map . compute_root ( ) . unwrap ( ) . to_hex ( ) ,
256
168
) ;
257
169
signable_expected. set_message_part (
258
170
ProtocolMessagePartKey :: LatestImmutableFileNumber ,
@@ -262,14 +174,17 @@ mod tests {
262
174
}
263
175
264
176
#[ tokio:: test]
265
- async fn test_compute_signable_with_no_transaction_return_error ( ) {
177
+ async fn test_compute_signable_with_no_block_range_root_return_error ( ) {
266
178
let beacon = CardanoDbBeacon :: default ( ) ;
267
179
let mut transaction_importer = MockTransactionsImporter :: new ( ) ;
268
- transaction_importer
269
- . expect_import ( )
270
- . return_once ( |_| Ok ( vec ! [ ] ) ) ;
180
+ transaction_importer. expect_import ( ) . return_once ( |_| Ok ( ( ) ) ) ;
181
+ let mut block_range_root_retriever = MockBlockRangeRootRetriever :: new ( ) ;
182
+ block_range_root_retriever
183
+ . expect_compute_merkle_map_from_block_range_roots ( )
184
+ . return_once ( move |_| Ok ( compute_mk_map_from_transactions ( vec ! [ ] ) ) ) ;
271
185
let cardano_transactions_signable_builder = CardanoTransactionsSignableBuilder :: new (
272
186
Arc :: new ( transaction_importer) ,
187
+ Arc :: new ( block_range_root_retriever) ,
273
188
TestLogger :: stdout ( ) ,
274
189
) ;
275
190
0 commit comments