|
15 | 15 | // along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
16 | 16 |
|
17 | 17 | use std::cmp;
|
18 |
| -use std::collections::{HashSet, BTreeMap, VecDeque}; |
| 18 | +use std::collections::{BTreeMap, HashSet, VecDeque}; |
19 | 19 | use std::convert::TryFrom;
|
20 |
| -use std::sync::atomic::{AtomicUsize, AtomicBool, AtomicI64, Ordering as AtomicOrdering}; |
| 20 | +use std::io::{BufRead, BufReader}; |
| 21 | +use std::str::from_utf8; |
21 | 22 | use std::sync::{Arc, Weak};
|
22 |
| -use std::time::{Instant, Duration}; |
| 23 | +use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicI64, Ordering as AtomicOrdering}; |
| 24 | +use std::time::{Duration, Instant}; |
23 | 25 |
|
24 |
| -use blockchain::{BlockReceipts, BlockChain, BlockChainDB, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert, BlockNumberKey}; |
| 26 | +use ansi_term::Colour; |
25 | 27 | use 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 bytes::ToPretty; |
| 29 | +use ethereum_types::{Address, H256, H264, U256}; |
30 | 30 | use hash::keccak;
|
31 |
| -use io::IoChannel; |
| 31 | +use hash_db::EMPTY_PREFIX; |
32 | 32 | use itertools::Itertools;
|
33 |
| -use journaldb; |
34 |
| -use kvdb::{DBValue, KeyValueDB, DBTransaction}; |
| 33 | +use kvdb::{DBTransaction, DBValue, KeyValueDB}; |
35 | 34 | use parking_lot::{Mutex, RwLock};
|
36 | 35 | use rand::rngs::OsRng;
|
37 |
| -use types::transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Action}; |
38 |
| -use trie::{TrieSpec, TrieFactory, Trie}; |
39 |
| -use types::ancestry_action::AncestryAction; |
40 |
| -use types::encoded; |
41 |
| -use types::filter::Filter; |
42 |
| -use types::log_entry::LocalizedLogEntry; |
43 |
| -use types::receipt::{Receipt, LocalizedReceipt}; |
44 |
| -use types::{BlockNumber, header::{Header, ExtendedHeader}}; |
45 |
| -use vm::{EnvInfo, LastHashes}; |
46 |
| -use hash_db::EMPTY_PREFIX; |
47 |
| -use block::{LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock}; |
48 |
| -use client::ancient_import::AncientVerifier; |
| 36 | +use rlp::PayloadInfo; |
| 37 | +use rustc_hex::FromHex; |
| 38 | +use trie::{Trie, TrieFactory, TrieSpec}; |
| 39 | + |
| 40 | +use block::{ClosedBlock, Drain, enact_verified, LockedBlock, OpenBlock, SealedBlock}; |
| 41 | +use blockchain::{ |
| 42 | + BlockChain, |
| 43 | + BlockChainDB, |
| 44 | + BlockNumberKey, |
| 45 | + BlockProvider, |
| 46 | + BlockReceipts, |
| 47 | + ExtrasInsert, |
| 48 | + ImportRoute, |
| 49 | + TransactionAddress, |
| 50 | + TreeRoute |
| 51 | +}; |
| 52 | +use call_contract::{CallContract, RegistryInfo}; |
| 53 | +use client::bad_blocks; |
49 | 54 | use client::{
|
50 | 55 | Nonce, Balance, ChainInfo, BlockInfo, TransactionInfo,
|
51 | 56 | ReopenBlock, PrepareOpenBlock, ScheduleInfo, ImportSealedBlock,
|
52 | 57 | BroadcastProposalBlock, ImportBlock, StateOrBlock, StateInfo, StateClient, Call,
|
53 | 58 | AccountData, BlockChain as BlockChainTrait, BlockProducer, SealedBlockImporter,
|
54 |
| - ClientIoMessage, BlockChainReset |
| 59 | + ClientIoMessage, BlockChainReset, ImportExportBlocks |
55 | 60 | };
|
56 | 61 | use client::{
|
57 | 62 | BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient,
|
58 | 63 | TraceFilter, CallAnalytics, Mode,
|
59 | 64 | ChainNotify, NewBlocks, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType,
|
60 |
| - IoClient, BadBlocks, |
| 65 | + IoClient, BadBlocks |
61 | 66 | };
|
62 |
| -use client::bad_blocks; |
| 67 | +use client::ancient_import::AncientVerifier; |
| 68 | +use db::{keys::BlockDetails, Readable, Writable}; |
63 | 69 | use engines::{MAX_UNCLE_AGE, Engine, EpochTransition, ForkChoice, EngineError, SealingState};
|
64 | 70 | use engines::epoch::PendingTransition;
|
65 | 71 | use error::{
|
66 | 72 | ImportError, ExecutionError, CallError, BlockError,
|
67 | 73 | QueueError, Error as EthcoreError, EthcoreResult,
|
68 | 74 | };
|
| 75 | +use ethcore_miner::pool::VerifiedTransaction; |
| 76 | +use evm::Schedule; |
69 | 77 | use executive::{Executive, Executed, TransactOptions, contract_address};
|
70 | 78 | use factory::{Factories, VmFactory};
|
| 79 | +use io::IoChannel; |
| 80 | +use journaldb; |
71 | 81 | use miner::{Miner, MinerService};
|
72 | 82 | use snapshot::{self, io as snapshot_io, SnapshotClient};
|
73 | 83 | use spec::Spec;
|
74 | 84 | use state::{self, State};
|
75 | 85 | use state_db::StateDB;
|
76 |
| -use trace::{self, TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; |
| 86 | +use trace::{self, Database as TraceDatabase, ImportRequest as TraceImportRequest, LocalizedTrace, TraceDB}; |
77 | 87 | use transaction_ext::Transaction;
|
78 |
| -use verification::queue::kind::BlockLike; |
79 |
| -use verification::queue::kind::blocks::Unverified; |
80 |
| -use verification::{PreverifiedBlock, Verifier, BlockQueue}; |
| 88 | +use types::{ |
| 89 | + ancestry_action::AncestryAction, |
| 90 | + BlockNumber, |
| 91 | + encoded, |
| 92 | + data_format::DataFormat, |
| 93 | + filter::Filter, |
| 94 | + header::{Header, ExtendedHeader}, |
| 95 | + log_entry::LocalizedLogEntry, |
| 96 | + receipt::{LocalizedReceipt, Receipt}, |
| 97 | + transaction::{self, Action, LocalizedTransaction, SignedTransaction, UnverifiedTransaction}, |
| 98 | +}; |
81 | 99 | use verification;
|
82 |
| -use ansi_term::Colour; |
| 100 | +use verification::{BlockQueue, Verifier, PreverifiedBlock}; |
| 101 | +use verification::queue::kind::blocks::Unverified; |
| 102 | +use verification::queue::kind::BlockLike; |
| 103 | +use vm::{CreateContractAddress, EnvInfo, LastHashes}; |
83 | 104 |
|
84 | 105 | // re-export
|
85 | 106 | pub use types::blockchain_info::BlockChainInfo;
|
86 | 107 | pub use types::block_status::BlockStatus;
|
87 | 108 | pub use blockchain::CacheSize as BlockChainCacheSize;
|
88 | 109 | pub use verification::QueueInfo as BlockQueueInfo;
|
89 |
| -use db::{Writable, Readable, keys::BlockDetails}; |
90 | 110 |
|
91 | 111 | use_contract!(registry, "res/contracts/registrar.json");
|
92 | 112 |
|
@@ -2560,6 +2580,116 @@ impl ProvingBlockChainClient for Client {
|
2560 | 2580 |
|
2561 | 2581 | impl SnapshotClient for Client {}
|
2562 | 2582 |
|
| 2583 | +impl ImportExportBlocks for Client { |
| 2584 | + fn export_blocks<'a>( |
| 2585 | + &self, |
| 2586 | + mut out: Box<dyn std::io::Write + 'a>, |
| 2587 | + from: BlockId, |
| 2588 | + to: BlockId, |
| 2589 | + format: Option<DataFormat> |
| 2590 | + ) -> Result<(), String> { |
| 2591 | + let from = self.block_number(from).ok_or("Starting block could not be found")?; |
| 2592 | + let to = self.block_number(to).ok_or("End block could not be found")?; |
| 2593 | + let format = format.unwrap_or_default(); |
| 2594 | + |
| 2595 | + for i in from..=to { |
| 2596 | + if i % 10000 == 0 { |
| 2597 | + info!("#{}", i); |
| 2598 | + } |
| 2599 | + let b = self.block(BlockId::Number(i)).ok_or("Error exporting incomplete chain")?.into_inner(); |
| 2600 | + match format { |
| 2601 | + DataFormat::Binary => { |
| 2602 | + out.write(&b).map_err(|e| format!("Couldn't write to stream. Cause: {}", e))?; |
| 2603 | + } |
| 2604 | + DataFormat::Hex => { |
| 2605 | + out.write_fmt(format_args!("{}\n", b.pretty())).map_err(|e| format!("Couldn't write to stream. Cause: {}", e))?; |
| 2606 | + } |
| 2607 | + } |
| 2608 | + } |
| 2609 | + Ok(()) |
| 2610 | + } |
| 2611 | + |
| 2612 | + fn import_blocks<'a>( |
| 2613 | + &self, |
| 2614 | + mut source: Box<dyn std::io::Read + 'a>, |
| 2615 | + format: Option<DataFormat> |
| 2616 | + ) -> Result<(), String> { |
| 2617 | + const READAHEAD_BYTES: usize = 8; |
| 2618 | + |
| 2619 | + let mut first_bytes: Vec<u8> = vec![0; READAHEAD_BYTES]; |
| 2620 | + let mut first_read = 0; |
| 2621 | + |
| 2622 | + let format = match format { |
| 2623 | + Some(format) => format, |
| 2624 | + None => { |
| 2625 | + first_read = source.read(&mut first_bytes).map_err(|_| "Error reading from the file/stream.")?; |
| 2626 | + match first_bytes[0] { |
| 2627 | + 0xf9 => DataFormat::Binary, |
| 2628 | + _ => DataFormat::Hex, |
| 2629 | + } |
| 2630 | + } |
| 2631 | + }; |
| 2632 | + |
| 2633 | + let do_import = |bytes: Vec<u8>| { |
| 2634 | + let block = Unverified::from_rlp(bytes).map_err(|_| "Invalid block rlp")?; |
| 2635 | + let number = block.header.number(); |
| 2636 | + while self.queue_info().is_full() { std::thread::sleep(Duration::from_secs(1)); } |
| 2637 | + match self.import_block(block) { |
| 2638 | + Err(EthcoreError::Import(ImportError::AlreadyInChain)) => { |
| 2639 | + trace!("Skipping block #{}: already in chain.", number); |
| 2640 | + } |
| 2641 | + Err(e) => { |
| 2642 | + return Err(format!("Cannot import block #{}: {:?}", number, e)); |
| 2643 | + }, |
| 2644 | + Ok(_) => {}, |
| 2645 | + } |
| 2646 | + Ok(()) |
| 2647 | + }; |
| 2648 | + |
| 2649 | + match format { |
| 2650 | + DataFormat::Binary => { |
| 2651 | + loop { |
| 2652 | + let (mut bytes, n) = if first_read > 0 { |
| 2653 | + (first_bytes.clone(), first_read) |
| 2654 | + } else { |
| 2655 | + let mut bytes = vec![0; READAHEAD_BYTES]; |
| 2656 | + let n = source.read(&mut bytes) |
| 2657 | + .map_err(|err| format!("Error reading from the file/stream: {:?}", err))?; |
| 2658 | + (bytes, n) |
| 2659 | + }; |
| 2660 | + if n == 0 { break; } |
| 2661 | + first_read = 0; |
| 2662 | + let s = PayloadInfo::from(&bytes) |
| 2663 | + .map_err(|e| format!("Invalid RLP in the file/stream: {:?}", e))?.total(); |
| 2664 | + bytes.resize(s, 0); |
| 2665 | + source.read_exact(&mut bytes[n..]) |
| 2666 | + .map_err(|err| format!("Error reading from the file/stream: {:?}", err))?; |
| 2667 | + do_import(bytes)?; |
| 2668 | + } |
| 2669 | + } |
| 2670 | + DataFormat::Hex => { |
| 2671 | + for line in BufReader::new(source).lines() { |
| 2672 | + let s = line |
| 2673 | + .map_err(|err| format!("Error reading from the file/stream: {:?}", err))?; |
| 2674 | + let s = if first_read > 0 { |
| 2675 | + from_utf8(&first_bytes) |
| 2676 | + .map_err(|err| format!("Invalid UTF-8: {:?}", err))? |
| 2677 | + .to_owned() + &(s[..]) |
| 2678 | + } else { |
| 2679 | + s |
| 2680 | + }; |
| 2681 | + first_read = 0; |
| 2682 | + let bytes = s.from_hex() |
| 2683 | + .map_err(|err| format!("Invalid hex in file/stream: {:?}", err))?; |
| 2684 | + do_import(bytes)?; |
| 2685 | + } |
| 2686 | + } |
| 2687 | + }; |
| 2688 | + self.flush_queue(); |
| 2689 | + Ok(()) |
| 2690 | + } |
| 2691 | +} |
| 2692 | + |
2563 | 2693 | /// Returns `LocalizedReceipt` given `LocalizedTransaction`
|
2564 | 2694 | /// and a vector of receipts from given block up to transaction index.
|
2565 | 2695 | fn transaction_receipt(
|
@@ -2607,7 +2737,28 @@ fn transaction_receipt(
|
2607 | 2737 |
|
2608 | 2738 | #[cfg(test)]
|
2609 | 2739 | mod tests {
|
2610 |
| - use ethereum_types::{H256, Address}; |
| 2740 | + use std::sync::Arc; |
| 2741 | + use std::sync::atomic::{AtomicBool, Ordering}; |
| 2742 | + use std::thread; |
| 2743 | + use std::time::Duration; |
| 2744 | + |
| 2745 | + use ethereum_types::{Address, H256}; |
| 2746 | + use hash::keccak; |
| 2747 | + use kvdb::DBTransaction; |
| 2748 | + |
| 2749 | + use blockchain::{ExtrasInsert, BlockProvider}; |
| 2750 | + use super::{BlockChainClient, ChainInfo}; |
| 2751 | + use ethkey::KeyPair; |
| 2752 | + use types::{ |
| 2753 | + encoded, |
| 2754 | + engines::ForkChoice, |
| 2755 | + ids::{BlockId, TransactionId}, |
| 2756 | + log_entry::{LocalizedLogEntry, LogEntry}, |
| 2757 | + receipt::{LocalizedReceipt, Receipt, TransactionOutcome}, |
| 2758 | + transaction::{Action, LocalizedTransaction, Transaction}, |
| 2759 | + }; |
| 2760 | + use test_helpers::{generate_dummy_client, generate_dummy_client_with_data, generate_dummy_client_with_spec_and_data, get_good_dummy_block_hash}; |
| 2761 | + use super::transaction_receipt; |
2611 | 2762 |
|
2612 | 2763 | #[test]
|
2613 | 2764 | fn should_not_cache_details_before_commit() {
|
|
0 commit comments