16
16
17
17
use std:: cmp;
18
18
use std:: collections:: { HashSet , BTreeMap , VecDeque } ;
19
- use std:: str:: FromStr ;
19
+ use std:: io:: { BufRead , BufReader } ;
20
+ use std:: str:: { FromStr , from_utf8} ;
20
21
use std:: convert:: TryFrom ;
21
22
use std:: sync:: atomic:: { AtomicI64 , AtomicBool , Ordering as AtomicOrdering } ;
22
23
use std:: sync:: { Arc , Weak } ;
23
24
use std:: time:: { Instant , Duration } ;
24
25
25
26
use blockchain:: { BlockReceipts , BlockChain , BlockChainDB , BlockProvider , TreeRoute , ImportRoute , TransactionAddress , ExtrasInsert , BlockNumberKey } ;
26
- use bytes:: Bytes ;
27
+ use bytes:: { Bytes , ToPretty } ;
27
28
use call_contract:: { CallContract , RegistryInfo } ;
28
29
use ethcore_miner:: pool:: VerifiedTransaction ;
29
30
use ethereum_types:: { H256 , H264 , Address , U256 } ;
@@ -35,6 +36,8 @@ use journaldb;
35
36
use kvdb:: { DBValue , KeyValueDB , DBTransaction } ;
36
37
use parking_lot:: { Mutex , RwLock } ;
37
38
use rand:: OsRng ;
39
+ use rlp:: PayloadInfo ;
40
+ use rustc_hex:: FromHex ;
38
41
use types:: transaction:: { self , LocalizedTransaction , UnverifiedTransaction , SignedTransaction , Action } ;
39
42
use trie:: { TrieSpec , TrieFactory , Trie } ;
40
43
use types:: ancestry_action:: AncestryAction ;
@@ -43,6 +46,7 @@ use types::filter::Filter;
43
46
use types:: log_entry:: LocalizedLogEntry ;
44
47
use types:: receipt:: { Receipt , LocalizedReceipt } ;
45
48
use types:: { BlockNumber , header:: { Header , ExtendedHeader } } ;
49
+ use types:: data_format:: DataFormat ;
46
50
use vm:: { EnvInfo , LastHashes } ;
47
51
48
52
use block:: { LockedBlock , Drain , ClosedBlock , OpenBlock , enact_verified, SealedBlock } ;
@@ -52,7 +56,7 @@ use client::{
52
56
ReopenBlock , PrepareOpenBlock , ScheduleInfo , ImportSealedBlock ,
53
57
BroadcastProposalBlock , ImportBlock , StateOrBlock , StateInfo , StateClient , Call ,
54
58
AccountData , BlockChain as BlockChainTrait , BlockProducer , SealedBlockImporter ,
55
- ClientIoMessage , BlockChainReset
59
+ ClientIoMessage , BlockChainReset , ImportExportBlocks ,
56
60
} ;
57
61
use client:: {
58
62
BlockId , TransactionId , UncleId , TraceId , ClientConfig , BlockChainClient ,
@@ -64,7 +68,7 @@ use client::bad_blocks;
64
68
use engines:: { MAX_UNCLE_AGE , EthEngine , EpochTransition , ForkChoice , EngineError } ;
65
69
use engines:: epoch:: PendingTransition ;
66
70
use error:: {
67
- ImportErrorKind , ExecutionError , CallError , BlockError ,
71
+ ImportErrorKind , ExecutionError , CallError , BlockError , ImportError ,
68
72
QueueError , QueueErrorKind , Error as EthcoreError , EthcoreResult , ErrorKind as EthcoreErrorKind
69
73
} ;
70
74
use executive:: { Executive , Executed , TransactOptions , contract_address} ;
@@ -154,7 +158,7 @@ struct Importer {
154
158
pub import_lock : Mutex < ( ) > , // FIXME Maybe wrap the whole `Importer` instead?
155
159
156
160
/// Used to verify blocks
157
- pub verifier : Box < Verifier < Client > > ,
161
+ pub verifier : Box < dyn Verifier < Client > > ,
158
162
159
163
/// Queue containing pending blocks
160
164
pub block_queue : BlockQueue ,
@@ -197,7 +201,7 @@ pub struct Client {
197
201
pruning : journaldb:: Algorithm ,
198
202
199
203
/// Client uses this to store blocks, traces, etc.
200
- db : RwLock < Arc < BlockChainDB > > ,
204
+ db : RwLock < Arc < dyn BlockChainDB > > ,
201
205
202
206
state_db : RwLock < StateDB > ,
203
207
@@ -211,7 +215,7 @@ pub struct Client {
211
215
io_channel : RwLock < IoChannel < ClientIoMessage > > ,
212
216
213
217
/// List of actors to be notified on certain chain events
214
- notify : RwLock < Vec < Weak < ChainNotify > > > ,
218
+ notify : RwLock < Vec < Weak < dyn ChainNotify > > > ,
215
219
216
220
/// Queued transactions from IO
217
221
queue_transactions : IoChannelQueue ,
@@ -233,12 +237,12 @@ pub struct Client {
233
237
history : u64 ,
234
238
235
239
/// An action to be done if a mode/spec_name change happens
236
- on_user_defaults_change : Mutex < Option < Box < FnMut ( Option < Mode > ) + ' static + Send > > > ,
240
+ on_user_defaults_change : Mutex < Option < Box < dyn FnMut ( Option < Mode > ) + ' static + Send > > > ,
237
241
238
242
registrar_address : Option < Address > ,
239
243
240
244
/// A closure to call when we want to restart the client
241
- exit_handler : Mutex < Option < Box < Fn ( String ) + ' static + Send > > > ,
245
+ exit_handler : Mutex < Option < Box < dyn Fn ( String ) + ' static + Send > > > ,
242
246
243
247
importer : Importer ,
244
248
}
@@ -249,8 +253,13 @@ impl Importer {
249
253
engine : Arc < EthEngine > ,
250
254
message_channel : IoChannel < ClientIoMessage > ,
251
255
miner : Arc < Miner > ,
252
- ) -> Result < Importer , :: error:: Error > {
253
- let block_queue = BlockQueue :: new ( config. queue . clone ( ) , engine. clone ( ) , message_channel. clone ( ) , config. verifier_type . verifying_seal ( ) ) ;
256
+ ) -> Result < Importer , EthcoreError > {
257
+ let block_queue = BlockQueue :: new (
258
+ config. queue . clone ( ) ,
259
+ engine. clone ( ) ,
260
+ message_channel. clone ( ) ,
261
+ config. verifier_type . verifying_seal ( )
262
+ ) ;
254
263
255
264
Ok ( Importer {
256
265
import_lock : Mutex :: new ( ( ) ) ,
@@ -476,7 +485,16 @@ impl Importer {
476
485
//
477
486
// The header passed is from the original block data and is sealed.
478
487
// TODO: should return an error if ImportRoute is none, issue #9910
479
- fn commit_block < B > ( & self , block : B , header : & Header , block_data : encoded:: Block , pending : Option < PendingTransition > , client : & Client ) -> ImportRoute where B : Drain {
488
+ fn commit_block < B > (
489
+ & self ,
490
+ block : B ,
491
+ header : & Header ,
492
+ block_data : encoded:: Block ,
493
+ pending : Option < PendingTransition > ,
494
+ client : & Client
495
+ ) -> ImportRoute
496
+ where B : Drain
497
+ {
480
498
let hash = & header. hash ( ) ;
481
499
let number = header. number ( ) ;
482
500
let parent = header. parent_hash ( ) ;
@@ -2561,6 +2579,116 @@ impl ProvingBlockChainClient for Client {
2561
2579
2562
2580
impl SnapshotClient for Client { }
2563
2581
2582
+ impl ImportExportBlocks for Client {
2583
+ fn export_blocks < ' a > (
2584
+ & self ,
2585
+ mut out : Box < dyn std:: io:: Write + ' a > ,
2586
+ from : BlockId ,
2587
+ to : BlockId ,
2588
+ format : Option < DataFormat >
2589
+ ) -> Result < ( ) , String > {
2590
+ let from = self . block_number ( from) . ok_or ( "Starting block could not be found" ) ?;
2591
+ let to = self . block_number ( to) . ok_or ( "End block could not be found" ) ?;
2592
+ let format = format. unwrap_or_default ( ) ;
2593
+
2594
+ for i in from..=to {
2595
+ if i % 10000 == 0 {
2596
+ info ! ( "#{}" , i) ;
2597
+ }
2598
+ let b = self . block ( BlockId :: Number ( i) ) . ok_or ( "Error exporting incomplete chain" ) ?. into_inner ( ) ;
2599
+ match format {
2600
+ DataFormat :: Binary => {
2601
+ out. write ( & b) . map_err ( |e| format ! ( "Couldn't write to stream. Cause: {}" , e) ) ?;
2602
+ }
2603
+ DataFormat :: Hex => {
2604
+ out. write_fmt ( format_args ! ( "{}\n " , b. pretty( ) ) ) . map_err ( |e| format ! ( "Couldn't write to stream. Cause: {}" , e) ) ?;
2605
+ }
2606
+ }
2607
+ }
2608
+ Ok ( ( ) )
2609
+ }
2610
+
2611
+ fn import_blocks < ' a > (
2612
+ & self ,
2613
+ mut source : Box < dyn std:: io:: Read + ' a > ,
2614
+ format : Option < DataFormat >
2615
+ ) -> Result < ( ) , String > {
2616
+ const READAHEAD_BYTES : usize = 8 ;
2617
+
2618
+ let mut first_bytes: Vec < u8 > = vec ! [ 0 ; READAHEAD_BYTES ] ;
2619
+ let mut first_read = 0 ;
2620
+
2621
+ let format = match format {
2622
+ Some ( format) => format,
2623
+ None => {
2624
+ first_read = source. read ( & mut first_bytes) . map_err ( |_| "Error reading from the file/stream." ) ?;
2625
+ match first_bytes[ 0 ] {
2626
+ 0xf9 => DataFormat :: Binary ,
2627
+ _ => DataFormat :: Hex ,
2628
+ }
2629
+ }
2630
+ } ;
2631
+
2632
+ let do_import = |bytes : Vec < u8 > | {
2633
+ let block = Unverified :: from_rlp ( bytes) . map_err ( |_| "Invalid block rlp" ) ?;
2634
+ let number = block. header . number ( ) ;
2635
+ while self . queue_info ( ) . is_full ( ) { std:: thread:: sleep ( Duration :: from_secs ( 1 ) ) ; }
2636
+ match self . import_block ( block) {
2637
+ Err ( EthcoreError ( EthcoreErrorKind :: Import ( ImportErrorKind :: AlreadyInChain ) , _) ) => {
2638
+ trace ! ( "Skipping block #{}: already in chain." , number) ;
2639
+ } ,
2640
+ Err ( e) => {
2641
+ return Err ( format ! ( "Cannot import block #{}: {:?}" , number, e) ) ;
2642
+ } ,
2643
+ Ok ( _) => { } ,
2644
+ }
2645
+ Ok ( ( ) )
2646
+ } ;
2647
+
2648
+ match format {
2649
+ DataFormat :: Binary => {
2650
+ loop {
2651
+ let ( mut bytes, n) = if first_read > 0 {
2652
+ ( first_bytes. clone ( ) , first_read)
2653
+ } else {
2654
+ let mut bytes = vec ! [ 0 ; READAHEAD_BYTES ] ;
2655
+ let n = source. read ( & mut bytes)
2656
+ . map_err ( |err| format ! ( "Error reading from the file/stream: {:?}" , err) ) ?;
2657
+ ( bytes, n)
2658
+ } ;
2659
+ if n == 0 { break ; }
2660
+ first_read = 0 ;
2661
+ let s = PayloadInfo :: from ( & bytes)
2662
+ . map_err ( |e| format ! ( "Invalid RLP in the file/stream: {:?}" , e) ) ?. total ( ) ;
2663
+ bytes. resize ( s, 0 ) ;
2664
+ source. read_exact ( & mut bytes[ n..] )
2665
+ . map_err ( |err| format ! ( "Error reading from the file/stream: {:?}" , err) ) ?;
2666
+ do_import ( bytes) ?;
2667
+ }
2668
+ }
2669
+ DataFormat :: Hex => {
2670
+ for line in BufReader :: new ( source) . lines ( ) {
2671
+ let s = line
2672
+ . map_err ( |err| format ! ( "Error reading from the file/stream: {:?}" , err) ) ?;
2673
+ let s = if first_read > 0 {
2674
+ from_utf8 ( & first_bytes)
2675
+ . map_err ( |err| format ! ( "Invalid UTF-8: {:?}" , err) ) ?
2676
+ . to_owned ( ) + & ( s[ ..] )
2677
+ } else {
2678
+ s
2679
+ } ;
2680
+ first_read = 0 ;
2681
+ let bytes = s. from_hex ( )
2682
+ . map_err ( |err| format ! ( "Invalid hex in file/stream: {:?}" , err) ) ?;
2683
+ do_import ( bytes) ?;
2684
+ }
2685
+ }
2686
+ } ;
2687
+ self . flush_queue ( ) ;
2688
+ Ok ( ( ) )
2689
+ }
2690
+ }
2691
+
2564
2692
/// Returns `LocalizedReceipt` given `LocalizedTransaction`
2565
2693
/// and a vector of receipts from given block up to transaction index.
2566
2694
fn transaction_receipt (
0 commit comments