@@ -24,7 +24,7 @@ use zebra_chain::{
24
24
parallel:: tree:: NoteCommitmentTrees ,
25
25
parameters:: { Network , GENESIS_PREVIOUS_BLOCK_HASH } ,
26
26
sapling,
27
- serialization:: TrustedPreallocate ,
27
+ serialization:: { CompactSizeMessage , TrustedPreallocate , ZcashSerialize as _ } ,
28
28
transaction:: { self , Transaction } ,
29
29
transparent,
30
30
value_balance:: ValueBalance ,
@@ -39,6 +39,7 @@ use crate::{
39
39
transparent:: { AddressBalanceLocation , OutputLocation } ,
40
40
} ,
41
41
zebra_db:: { metrics:: block_precommit_metrics, ZebraDb } ,
42
+ FromDisk , RawBytes ,
42
43
} ,
43
44
BoxError , HashOrHeight ,
44
45
} ;
@@ -132,6 +133,19 @@ impl ZebraDb {
132
133
Some ( header)
133
134
}
134
135
136
+ /// Returns the raw [`block::Header`] with [`block::Hash`] or [`Height`], if
137
+ /// it exists in the finalized chain.
138
+ #[ allow( clippy:: unwrap_in_result) ]
139
+ fn raw_block_header ( & self , hash_or_height : HashOrHeight ) -> Option < RawBytes > {
140
+ // Block Header
141
+ let block_header_by_height = self . db . cf_handle ( "block_header_by_height" ) . unwrap ( ) ;
142
+
143
+ let height = hash_or_height. height_or_else ( |hash| self . height ( hash) ) ?;
144
+ let header: RawBytes = self . db . zs_get ( & block_header_by_height, & height) ?;
145
+
146
+ Some ( header)
147
+ }
148
+
135
149
/// Returns the [`Block`] with [`block::Hash`] or
136
150
/// [`Height`], if it exists in the finalized chain.
137
151
//
@@ -161,6 +175,56 @@ impl ZebraDb {
161
175
} ) )
162
176
}
163
177
178
+ /// Returns the [`Block`] with [`block::Hash`] or [`Height`], if it exists
179
+ /// in the finalized chain, and its serialized size.
180
+ #[ allow( clippy:: unwrap_in_result) ]
181
+ pub fn block_and_size ( & self , hash_or_height : HashOrHeight ) -> Option < ( Arc < Block > , usize ) > {
182
+ let ( raw_header, raw_txs) = self . raw_block ( hash_or_height) ?;
183
+
184
+ let header = Arc :: < block:: Header > :: from_bytes ( raw_header. raw_bytes ( ) ) ;
185
+ let txs: Vec < _ > = raw_txs
186
+ . iter ( )
187
+ . map ( |raw_tx| Arc :: < Transaction > :: from_bytes ( raw_tx. raw_bytes ( ) ) )
188
+ . collect ( ) ;
189
+
190
+ // Compute the size of the block from the size of header and size of
191
+ // transactions. This requires summing them all and also adding the
192
+ // size of the CompactSize-encoded transaction count.
193
+ // See https://developer.bitcoin.org/reference/block_chain.html#serialized-blocks
194
+ let tx_count = CompactSizeMessage :: try_from ( txs. len ( ) ) . unwrap ( ) ;
195
+ let tx_raw = tx_count. zcash_serialize_to_vec ( ) . unwrap ( ) ;
196
+ let size = raw_header. raw_bytes ( ) . len ( )
197
+ + raw_txs
198
+ . iter ( )
199
+ . map ( |raw_tx| raw_tx. raw_bytes ( ) . len ( ) )
200
+ . sum :: < usize > ( )
201
+ + tx_raw. len ( ) ;
202
+
203
+ let block = Block {
204
+ header,
205
+ transactions : txs,
206
+ } ;
207
+ Some ( ( Arc :: new ( block) , size) )
208
+ }
209
+
210
+ /// Returns the raw [`Block`] with [`block::Hash`] or
211
+ /// [`Height`], if it exists in the finalized chain.
212
+ #[ allow( clippy:: unwrap_in_result) ]
213
+ fn raw_block ( & self , hash_or_height : HashOrHeight ) -> Option < ( RawBytes , Vec < RawBytes > ) > {
214
+ // Block
215
+ let height = hash_or_height. height_or_else ( |hash| self . height ( hash) ) ?;
216
+ let header = self . raw_block_header ( height. into ( ) ) ?;
217
+
218
+ // Transactions
219
+
220
+ let transactions = self
221
+ . raw_transactions_by_height ( height)
222
+ . map ( |( _, tx) | tx)
223
+ . collect ( ) ;
224
+
225
+ Some ( ( header, transactions) )
226
+ }
227
+
164
228
/// Returns the Sapling [`note commitment tree`](sapling::tree::NoteCommitmentTree) specified by
165
229
/// a hash or height, if it exists in the finalized state.
166
230
#[ allow( clippy:: unwrap_in_result) ]
@@ -233,6 +297,19 @@ impl ZebraDb {
233
297
)
234
298
}
235
299
300
+ /// Returns an iterator of all raw [`Transaction`]s for a provided block
301
+ /// height in finalized state.
302
+ #[ allow( clippy:: unwrap_in_result) ]
303
+ fn raw_transactions_by_height (
304
+ & self ,
305
+ height : Height ,
306
+ ) -> impl Iterator < Item = ( TransactionLocation , RawBytes ) > + ' _ {
307
+ self . raw_transactions_by_location_range (
308
+ TransactionLocation :: min_for_height ( height)
309
+ ..=TransactionLocation :: max_for_height ( height) ,
310
+ )
311
+ }
312
+
236
313
/// Returns an iterator of all [`Transaction`]s in the provided range
237
314
/// of [`TransactionLocation`]s in finalized state.
238
315
#[ allow( clippy:: unwrap_in_result) ]
@@ -247,6 +324,20 @@ impl ZebraDb {
247
324
self . db . zs_forward_range_iter ( tx_by_loc, range)
248
325
}
249
326
327
+ /// Returns an iterator of all raw [`Transaction`]s in the provided range
328
+ /// of [`TransactionLocation`]s in finalized state.
329
+ #[ allow( clippy:: unwrap_in_result) ]
330
+ fn raw_transactions_by_location_range < R > (
331
+ & self ,
332
+ range : R ,
333
+ ) -> impl Iterator < Item = ( TransactionLocation , RawBytes ) > + ' _
334
+ where
335
+ R : RangeBounds < TransactionLocation > ,
336
+ {
337
+ let tx_by_loc = self . db . cf_handle ( "tx_by_loc" ) . unwrap ( ) ;
338
+ self . db . zs_forward_range_iter ( tx_by_loc, range)
339
+ }
340
+
250
341
/// Returns the [`TransactionLocation`] for [`transaction::Hash`],
251
342
/// if it exists in the finalized chain.
252
343
#[ allow( clippy:: unwrap_in_result) ]
0 commit comments