1717use std:: cmp;
1818use std:: collections:: { HashSet , BTreeMap , VecDeque } ;
1919use std:: str:: FromStr ;
20+ use std:: str:: from_utf8;
2021use std:: sync:: atomic:: { AtomicUsize , AtomicBool , Ordering as AtomicOrdering } ;
2122use std:: sync:: { Arc , Weak } ;
22- use std:: time:: { Instant , Duration } ;
23+ use std:: io:: { BufReader , BufRead } ;
24+ use std:: time:: { Duration , Instant } ;
2325
2426use blockchain:: { BlockReceipts , BlockChain , BlockChainDB , BlockProvider , TreeRoute , ImportRoute , TransactionAddress , ExtrasInsert , BlockNumberKey } ;
2527use bytes:: Bytes ;
26- use call_contract :: { CallContract , RegistryInfo } ;
27- use ethcore_miner :: pool :: VerifiedTransaction ;
28- use ethereum_types :: { H256 , H264 , Address , U256 } ;
29- use evm :: Schedule ;
28+ use rlp :: PayloadInfo ;
29+ use bytes :: ToPretty ;
30+ use error :: Error ;
31+ use ethereum_types :: { Address , H256 , H264 , U256 } ;
3032use hash:: keccak;
31- use io:: IoChannel ;
33+ use call_contract:: CallContract ;
34+ use ethcore_miner:: pool:: VerifiedTransaction ;
3235use itertools:: Itertools ;
33- use journaldb;
34- use kvdb:: { DBValue , KeyValueDB , DBTransaction } ;
36+ use kvdb:: { DBTransaction , DBValue , KeyValueDB } ;
3537use parking_lot:: { Mutex , RwLock } ;
3638use rand:: OsRng ;
3739use types:: transaction:: { self , LocalizedTransaction , UnverifiedTransaction , SignedTransaction , Action } ;
@@ -43,6 +45,7 @@ use types::log_entry::LocalizedLogEntry;
4345use types:: receipt:: { Receipt , LocalizedReceipt } ;
4446use types:: { BlockNumber , header:: { Header , ExtendedHeader } } ;
4547use vm:: { EnvInfo , LastHashes } ;
48+ use types:: data_format:: DataFormat ;
4649
4750use block:: { LockedBlock , Drain , ClosedBlock , OpenBlock , enact_verified, SealedBlock } ;
4851use client:: ancient_import:: AncientVerifier ;
@@ -51,8 +54,9 @@ use client::{
5154 ReopenBlock , PrepareOpenBlock , ScheduleInfo , ImportSealedBlock ,
5255 BroadcastProposalBlock , ImportBlock , StateOrBlock , StateInfo , StateClient , Call ,
5356 AccountData , BlockChain as BlockChainTrait , BlockProducer , SealedBlockImporter ,
54- ClientIoMessage , BlockChainReset
57+ ClientIoMessage , BlockChainReset , ImportExportBlocks
5558} ;
59+ use rustc_hex:: FromHex ;
5660use client:: {
5761 BlockId , TransactionId , UncleId , TraceId , ClientConfig , BlockChainClient ,
5862 TraceFilter , CallAnalytics , Mode ,
@@ -80,7 +84,9 @@ use verification::queue::kind::blocks::Unverified;
8084use verification:: { PreverifiedBlock , Verifier , BlockQueue } ;
8185use verification;
8286use ansi_term:: Colour ;
83-
87+ use call_contract:: RegistryInfo ;
88+ use io:: IoChannel ;
89+ use vm:: Schedule ;
8490// re-export
8591pub use types:: blockchain_info:: BlockChainInfo ;
8692pub use types:: block_status:: BlockStatus ;
@@ -2568,6 +2574,116 @@ impl Drop for Client {
25682574 }
25692575}
25702576
2577+ impl ImportExportBlocks for Client {
2578+ fn export_blocks < ' a > (
2579+ & self ,
2580+ mut out : Box < dyn std:: io:: Write + ' a > ,
2581+ from : BlockId ,
2582+ to : BlockId ,
2583+ format : Option < DataFormat >
2584+ ) -> Result < ( ) , String > {
2585+ let from = self . block_number ( from) . ok_or ( "Starting block could not be found" ) ?;
2586+ let to = self . block_number ( to) . ok_or ( "End block could not be found" ) ?;
2587+ let format = format. unwrap_or_default ( ) ;
2588+
2589+ for i in from..=to {
2590+ if i % 10000 == 0 {
2591+ info ! ( "#{}" , i) ;
2592+ }
2593+ let b = self . block ( BlockId :: Number ( i) ) . ok_or ( "Error exporting incomplete chain" ) ?. into_inner ( ) ;
2594+ match format {
2595+ DataFormat :: Binary => {
2596+ out. write ( & b) . map_err ( |e| format ! ( "Couldn't write to stream. Cause: {}" , e) ) ?;
2597+ }
2598+ DataFormat :: Hex => {
2599+ out. write_fmt ( format_args ! ( "{}\n " , b. pretty( ) ) ) . map_err ( |e| format ! ( "Couldn't write to stream. Cause: {}" , e) ) ?;
2600+ }
2601+ }
2602+ }
2603+ Ok ( ( ) )
2604+ }
2605+
2606+ fn import_blocks < ' a > (
2607+ & self ,
2608+ mut source : Box < dyn std:: io:: Read + ' a > ,
2609+ format : Option < DataFormat >
2610+ ) -> Result < ( ) , String > {
2611+ const READAHEAD_BYTES : usize = 8 ;
2612+
2613+ let mut first_bytes: Vec < u8 > = vec ! [ 0 ; READAHEAD_BYTES ] ;
2614+ let mut first_read = 0 ;
2615+
2616+ let format = match format {
2617+ Some ( format) => format,
2618+ None => {
2619+ first_read = source. read ( & mut first_bytes) . map_err ( |_| "Error reading from the file/stream." ) ?;
2620+ match first_bytes[ 0 ] {
2621+ 0xf9 => DataFormat :: Binary ,
2622+ _ => DataFormat :: Hex ,
2623+ }
2624+ }
2625+ } ;
2626+
2627+ let do_import = |bytes : Vec < u8 > | {
2628+ let block = Unverified :: from_rlp ( bytes) . map_err ( |_| "Invalid block rlp" ) ?;
2629+ let number = block. header . number ( ) ;
2630+ while self . queue_info ( ) . is_full ( ) { std:: thread:: sleep ( Duration :: from_secs ( 1 ) ) ; }
2631+ match self . import_block ( block) {
2632+ Err ( Error ( EthcoreErrorKind :: Import ( ImportErrorKind :: AlreadyInChain ) , _) ) => {
2633+ trace ! ( "Skipping block #{}: already in chain." , number) ;
2634+ }
2635+ Err ( e) => {
2636+ return Err ( format ! ( "Cannot import block #{}: {:?}" , number, e) ) ;
2637+ } ,
2638+ Ok ( _) => { } ,
2639+ }
2640+ Ok ( ( ) )
2641+ } ;
2642+
2643+ match format {
2644+ DataFormat :: Binary => {
2645+ loop {
2646+ let ( mut bytes, n) = if first_read > 0 {
2647+ ( first_bytes. clone ( ) , first_read)
2648+ } else {
2649+ let mut bytes = vec ! [ 0 ; READAHEAD_BYTES ] ;
2650+ let n = source. read ( & mut bytes)
2651+ . map_err ( |err| format ! ( "Error reading from the file/stream: {:?}" , err) ) ?;
2652+ ( bytes, n)
2653+ } ;
2654+ if n == 0 { break ; }
2655+ first_read = 0 ;
2656+ let s = PayloadInfo :: from ( & bytes)
2657+ . map_err ( |e| format ! ( "Invalid RLP in the file/stream: {:?}" , e) ) ?. total ( ) ;
2658+ bytes. resize ( s, 0 ) ;
2659+ source. read_exact ( & mut bytes[ n..] )
2660+ . map_err ( |err| format ! ( "Error reading from the file/stream: {:?}" , err) ) ?;
2661+ do_import ( bytes) ?;
2662+ }
2663+ }
2664+ DataFormat :: Hex => {
2665+ for line in BufReader :: new ( source) . lines ( ) {
2666+ let s = line
2667+ . map_err ( |err| format ! ( "Error reading from the file/stream: {:?}" , err) ) ?;
2668+ let s = if first_read > 0 {
2669+ from_utf8 ( & first_bytes)
2670+ . map_err ( |err| format ! ( "Invalid UTF-8: {:?}" , err) ) ?
2671+ . to_owned ( ) + & ( s[ ..] )
2672+ } else {
2673+ s
2674+ } ;
2675+ first_read = 0 ;
2676+ let bytes = s. from_hex ( )
2677+ . map_err ( |err| format ! ( "Invalid hex in file/stream: {:?}" , err) ) ?;
2678+ do_import ( bytes) ?;
2679+ }
2680+ }
2681+ } ;
2682+ self . flush_queue ( ) ;
2683+ Ok ( ( ) )
2684+ }
2685+ }
2686+
25712687/// Returns `LocalizedReceipt` given `LocalizedTransaction`
25722688/// and a vector of receipts from given block up to transaction index.
25732689fn transaction_receipt (
0 commit comments