1
1
use crate :: { migration_info:: DataSource , MigrationInfo } ;
2
2
use std:: { collections:: HashMap , time:: Duration } ;
3
3
4
- use alloy_primitives:: { bytes:: Buf , B256 } ;
4
+ use alloy_primitives:: { bytes:: Buf , Address , B256 } ;
5
5
use eyre:: { bail, eyre} ;
6
6
use futures:: { stream:: FuturesUnordered , StreamExt } ;
7
7
use indicatif:: { ProgressBar , ProgressFinish , ProgressState , ProgressStyle } ;
@@ -70,19 +70,23 @@ impl<MI: MigrationInfo + Send + Sync> MigrationTrait for Migration<MI> {
70
70
pub struct Model {
71
71
#[ sea_orm( primary_key) ]
72
72
number : i64 ,
73
- extra_data : Vec < u8 > ,
74
- state_root : Vec < u8 > ,
75
- difficulty : i8 ,
73
+ extra_data : Option < Vec < u8 > > ,
74
+ state_root : Option < Vec < u8 > > ,
75
+ coinbase : Option < Vec < u8 > > ,
76
+ nonce : Option < String > ,
77
+ difficulty : Option < i8 > ,
76
78
}
77
79
impl ActiveModelBehavior for ActiveModel { }
78
80
79
81
impl From < ( i64 , HeaderMetadata ) > for ActiveModel {
80
82
fn from ( ( bn, header) : ( i64 , HeaderMetadata ) ) -> Self {
81
83
Self {
82
84
number : ActiveValue :: Set ( bn) ,
83
- extra_data : ActiveValue :: Set ( header. extra_data ) ,
84
- state_root : ActiveValue :: Set ( header. state_root . to_vec ( ) ) ,
85
- difficulty : ActiveValue :: Set ( header. difficulty as i8 ) ,
85
+ extra_data : ActiveValue :: Set ( Some ( header. extra_data ) ) ,
86
+ state_root : ActiveValue :: Set ( Some ( header. state_root . to_vec ( ) ) ) ,
87
+ coinbase : ActiveValue :: Set ( header. coinbase . map ( |c| c. to_vec ( ) ) ) ,
88
+ nonce : ActiveValue :: Set ( header. nonce . map ( |x| format ! ( "{x:x}" ) ) ) ,
89
+ difficulty : ActiveValue :: Set ( Some ( header. difficulty as i8 ) ) ,
86
90
}
87
91
}
88
92
}
@@ -107,7 +111,8 @@ async fn download(url: &str) -> eyre::Result<Vec<u8>> {
107
111
if total_size == 0 {
108
112
bail ! ( "empty file" ) ;
109
113
}
110
- let iterations = total_size / CHUNK_SIZE + if total_size % CHUNK_SIZE != 0 { 1 } else { 0 } ;
114
+ let iterations =
115
+ total_size / CHUNK_SIZE + if !total_size. is_multiple_of ( CHUNK_SIZE ) { 1 } else { 0 } ;
111
116
112
117
// create a progress bar.
113
118
let pb = ProgressBar :: new ( total_size) .
@@ -213,8 +218,8 @@ fn decode_to_headers(data: Vec<u8>) -> eyre::Result<Vec<HeaderMetadata>> {
213
218
214
219
// decode all available data.
215
220
let mut headers = Vec :: with_capacity ( data_buf. len ( ) / HEADER_LOWER_SIZE_LIMIT ) ;
216
- while let Some ( data ) = decoder . next ( data_buf ) {
217
- headers. push ( data ) ;
221
+ while !data_buf . is_empty ( ) {
222
+ headers. push ( decoder . next ( data_buf ) . map_err ( |err| DbErr :: Custom ( err . to_string ( ) ) ) ? ) ;
218
223
}
219
224
220
225
Ok ( headers)
@@ -225,6 +230,8 @@ fn decode_to_headers(data: Vec<u8>) -> eyre::Result<Vec<HeaderMetadata>> {
225
230
struct HeaderMetadata {
226
231
extra_data : Vec < u8 > ,
227
232
state_root : Vec < u8 > ,
233
+ coinbase : Option < Vec < u8 > > ,
234
+ nonce : Option < u64 > ,
228
235
difficulty : u8 ,
229
236
}
230
237
@@ -260,33 +267,56 @@ impl MetadataDecoder {
260
267
}
261
268
262
269
/// Decodes the next header metadata from the buffer, advancing it.
263
- fn next ( & self , buf : & mut & [ u8 ] ) -> Option < HeaderMetadata > {
270
+ fn next ( & self , buf : & mut & [ u8 ] ) -> eyre :: Result < HeaderMetadata > {
264
271
// sanity check.
265
272
if buf. len ( ) < 2 {
266
- return None
273
+ bail ! ( "header buffer too small to read seal flag and vanity index" ) ;
267
274
}
268
275
269
276
// get flag and vanity index.
270
277
let flag = buf[ 0 ] ;
271
278
let vanity_index = buf[ 1 ] ;
272
279
280
+ let has_coinbase = ( flag & 0b00010000 ) != 0 ;
281
+ let has_nonce = ( flag & 0b00100000 ) != 0 ;
273
282
let difficulty = if flag & 0b01000000 == 0 { 2 } else { 1 } ;
274
283
let seal_length = if flag & 0b10000000 == 0 { 65 } else { 85 } ;
275
- let vanity = self . vanity . get ( & vanity_index) ?;
284
+ let vanity = self . vanity . get ( & vanity_index) . ok_or ( eyre ! ( "vanity not found" ) ) ?;
276
285
277
- if buf. len ( ) < B256 :: len_bytes ( ) + seal_length + 2 {
278
- return None
286
+ // flag + vanity index + state root + coinbase + nonce + seal
287
+ let total_expected_size = 2 * size_of :: < u8 > ( ) +
288
+ B256 :: len_bytes ( ) +
289
+ Address :: len_bytes ( ) * has_coinbase as usize +
290
+ size_of :: < u64 > ( ) * has_nonce as usize +
291
+ seal_length;
292
+
293
+ if buf. len ( ) < total_expected_size {
294
+ bail ! ( "header buffer too small: got {}, expected {}" , buf. len( ) , total_expected_size) ;
279
295
}
280
296
buf. advance ( 2 ) ;
281
297
282
298
let state_root = buf[ ..B256 :: len_bytes ( ) ] . to_vec ( ) ;
283
299
buf. advance ( B256 :: len_bytes ( ) ) ;
284
300
301
+ let mut coinbase = None ;
302
+ if has_coinbase {
303
+ coinbase = Some ( buf[ ..Address :: len_bytes ( ) ] . to_vec ( ) ) ;
304
+ buf. advance ( Address :: len_bytes ( ) ) ;
305
+ }
306
+
307
+ let mut nonce = None ;
308
+ if has_nonce {
309
+ nonce = Some ( u64:: from_be_bytes (
310
+ buf[ ..size_of :: < u64 > ( ) ] . try_into ( ) . expect ( "32 bytes slice" ) ,
311
+ ) ) ;
312
+ buf. advance ( size_of :: < u64 > ( ) ) ;
313
+ }
314
+
285
315
let seal = & buf[ ..seal_length] ;
286
316
let extra_data = [ vanity, seal] . concat ( ) ;
287
317
buf. advance ( seal_length) ;
288
318
289
- Some ( HeaderMetadata { extra_data, state_root, difficulty } )
319
+ Ok ( HeaderMetadata { extra_data, state_root, coinbase , nonce , difficulty } )
290
320
}
291
321
}
292
322
@@ -316,7 +346,13 @@ mod tests {
316
346
let header_data = bytes ! ( "c00020695989e9038823e35f0e88fbc44659ffdbfa1fe89fbeb2689b43f15fa64cb548c3f81f3d998b6652900e1c3183736c238fe4290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ) ;
317
347
let header = decoder. next ( & mut header_data. as_ref ( ) ) . unwrap ( ) ;
318
348
319
- let expected_header = HeaderMetadata { extra_data : bytes ! ( "0x000000000000000000000000000000000000000000000000000000000000000048c3f81f3d998b6652900e1c3183736c238fe4290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ) . to_vec ( ) , state_root : b256 ! ( "20695989e9038823e35f0e88fbc44659ffdbfa1fe89fbeb2689b43f15fa64cb5" ) . to_vec ( ) , difficulty : 1 } ;
349
+ let expected_header = HeaderMetadata {
350
+ extra_data : bytes ! ( "0x000000000000000000000000000000000000000000000000000000000000000048c3f81f3d998b6652900e1c3183736c238fe4290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ) . to_vec ( ) ,
351
+ state_root : b256 ! ( "20695989e9038823e35f0e88fbc44659ffdbfa1fe89fbeb2689b43f15fa64cb5" ) . to_vec ( ) ,
352
+ coinbase : None ,
353
+ nonce : None ,
354
+ difficulty : 1 ,
355
+ } ;
320
356
assert_eq ! ( header, expected_header)
321
357
}
322
358
}
0 commit comments