Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit e569db0

Browse files
seunlanlegeniklasad1
authored andcommitted
Add new line after writing block to hex file. (#10984)
* add new line after writing block to hex file. * refactor for testability * correct import * better error reporting, code formatting * multiline imports * docs * better docs, move type to common types, merge ImportBlocks and ExportBlocks * tabs over spaces * correct test imports * Apply suggestions from code review Co-Authored-By: David <dvdplm@gmail.com> * correct typo * fixed test import
1 parent e512bf4 commit e569db0

File tree

9 files changed

+379
-153
lines changed

9 files changed

+379
-153
lines changed

ethcore/blockchain/src/blockchain.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ impl BlockChain {
592592
let best_block_rlp = bc.block(&best_block_hash)
593593
.expect("Best block is from a known block hash; qed");
594594

595-
// and write them
595+
// and write them to the cache.
596596
let mut best_block = bc.best_block.write();
597597
*best_block = BestBlock {
598598
total_difficulty: best_block_total_difficulty,
@@ -855,12 +855,31 @@ impl BlockChain {
855855
}
856856
}
857857

858-
/// clears all caches for testing purposes
858+
/// clears all caches, re-loads best block from disk for testing purposes
859859
pub fn clear_cache(&self) {
860860
self.block_bodies.write().clear();
861861
self.block_details.write().clear();
862862
self.block_hashes.write().clear();
863863
self.block_headers.write().clear();
864+
// Fetch best block details from disk
865+
let best_block_hash = self.db.key_value().get(db::COL_EXTRA, b"best")
866+
.expect("Low-level database error when fetching 'best' block. Some issue with disk?")
867+
.as_ref()
868+
.map(|r| H256::from_slice(r))
869+
.unwrap();
870+
let best_block_total_difficulty = self.block_details(&best_block_hash)
871+
.expect("Best block is from a known block hash; a known block hash always comes with a known block detail; qed")
872+
.total_difficulty;
873+
let best_block_rlp = self.block(&best_block_hash)
874+
.expect("Best block is from a known block hash; qed");
875+
876+
// and write them to the cache
877+
let mut best_block = self.best_block.write();
878+
*best_block = BestBlock {
879+
total_difficulty: best_block_total_difficulty,
880+
header: best_block_rlp.decode_header(),
881+
block: best_block_rlp,
882+
};
864883
}
865884

866885
/// Update the best ancient block to the given hash, after checking that

ethcore/src/client/client.rs

Lines changed: 184 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,78 +15,98 @@
1515
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
1616

1717
use std::cmp;
18-
use std::collections::{HashSet, BTreeMap, VecDeque};
18+
use std::collections::{BTreeMap, HashSet, VecDeque};
1919
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;
2122
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};
2325

24-
use blockchain::{BlockReceipts, BlockChain, BlockChainDB, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert, BlockNumberKey};
26+
use ansi_term::Colour;
2527
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};
3030
use hash::keccak;
31-
use io::IoChannel;
31+
use hash_db::EMPTY_PREFIX;
3232
use itertools::Itertools;
33-
use journaldb;
34-
use kvdb::{DBValue, KeyValueDB, DBTransaction};
33+
use kvdb::{DBTransaction, DBValue, KeyValueDB};
3534
use parking_lot::{Mutex, RwLock};
3635
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;
4954
use client::{
5055
Nonce, Balance, ChainInfo, BlockInfo, TransactionInfo,
5156
ReopenBlock, PrepareOpenBlock, ScheduleInfo, ImportSealedBlock,
5257
BroadcastProposalBlock, ImportBlock, StateOrBlock, StateInfo, StateClient, Call,
5358
AccountData, BlockChain as BlockChainTrait, BlockProducer, SealedBlockImporter,
54-
ClientIoMessage, BlockChainReset
59+
ClientIoMessage, BlockChainReset, ImportExportBlocks
5560
};
5661
use client::{
5762
BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient,
5863
TraceFilter, CallAnalytics, Mode,
5964
ChainNotify, NewBlocks, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType,
60-
IoClient, BadBlocks,
65+
IoClient, BadBlocks
6166
};
62-
use client::bad_blocks;
67+
use client::ancient_import::AncientVerifier;
68+
use db::{keys::BlockDetails, Readable, Writable};
6369
use engines::{MAX_UNCLE_AGE, Engine, EpochTransition, ForkChoice, EngineError, SealingState};
6470
use engines::epoch::PendingTransition;
6571
use error::{
6672
ImportError, ExecutionError, CallError, BlockError,
6773
QueueError, Error as EthcoreError, EthcoreResult,
6874
};
75+
use ethcore_miner::pool::VerifiedTransaction;
76+
use evm::Schedule;
6977
use executive::{Executive, Executed, TransactOptions, contract_address};
7078
use factory::{Factories, VmFactory};
79+
use io::IoChannel;
80+
use journaldb;
7181
use miner::{Miner, MinerService};
7282
use snapshot::{self, io as snapshot_io, SnapshotClient};
7383
use spec::Spec;
7484
use state::{self, State};
7585
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};
7787
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+
};
8199
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};
83104

84105
// re-export
85106
pub use types::blockchain_info::BlockChainInfo;
86107
pub use types::block_status::BlockStatus;
87108
pub use blockchain::CacheSize as BlockChainCacheSize;
88109
pub use verification::QueueInfo as BlockQueueInfo;
89-
use db::{Writable, Readable, keys::BlockDetails};
90110

91111
use_contract!(registry, "res/contracts/registrar.json");
92112

@@ -2560,6 +2580,116 @@ impl ProvingBlockChainClient for Client {
25602580

25612581
impl SnapshotClient for Client {}
25622582

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+
25632693
/// Returns `LocalizedReceipt` given `LocalizedTransaction`
25642694
/// and a vector of receipts from given block up to transaction index.
25652695
fn transaction_receipt(
@@ -2607,7 +2737,28 @@ fn transaction_receipt(
26072737

26082738
#[cfg(test)]
26092739
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;
26112762

26122763
#[test]
26132764
fn should_not_cache_details_before_commit() {

ethcore/src/client/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub use self::chain_notify::{ChainNotify, NewBlocks, ChainRoute, ChainRouteType,
3838
pub use self::traits::{
3939
Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, TransactionInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock,
4040
StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, BadBlocks,
41-
BlockChainReset
41+
BlockChainReset, ImportExportBlocks
4242
};
4343
pub use state::StateInfo;
4444
pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient, IoClient};

ethcore/src/client/traits.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use types::basic_account::BasicAccount;
3131
use types::block_status::BlockStatus;
3232
use types::blockchain_info::BlockChainInfo;
3333
use types::call_analytics::CallAnalytics;
34+
use types::data_format::DataFormat;
3435
use types::encoded;
3536
use types::filter::Filter;
3637
use types::header::Header;
@@ -474,3 +475,29 @@ pub trait BlockChainReset {
474475
/// reset to best_block - n
475476
fn reset(&self, num: u32) -> Result<(), String>;
476477
}
478+
479+
/// Provides a method for importing/exporting blocks
480+
pub trait ImportExportBlocks {
481+
/// Export blocks to destination, with the given from, to and format argument.
482+
/// destination could be a file or stdout.
483+
/// If the format is hex, each block is written on a new line.
484+
/// For binary exports, all block data is written to the same line.
485+
fn export_blocks<'a>(
486+
&self,
487+
destination: Box<dyn std::io::Write + 'a>,
488+
from: BlockId,
489+
to: BlockId,
490+
format: Option<DataFormat>
491+
) -> Result<(), String>;
492+
493+
/// Import blocks from destination, with the given format argument
494+
/// Source could be a file or stdout.
495+
/// For hex format imports, it attempts to read the blocks on a line by line basis.
496+
/// For binary format imports, reads the 8 byte RLP header in order to decode the block
497+
/// length to be read.
498+
fn import_blocks<'a>(
499+
&self,
500+
source: Box<dyn std::io::Read + 'a>,
501+
format: Option<DataFormat>
502+
) -> Result<(), String>;
503+
}

0 commit comments

Comments
 (0)