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

Commit

Permalink
Merge branch 'client-trait-ipc' into ipc
Browse files Browse the repository at this point in the history
  • Loading branch information
NikVolf committed Jul 18, 2016
2 parents e6c452a + 6c02cea commit 529ab3c
Show file tree
Hide file tree
Showing 18 changed files with 303 additions and 201 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ matrix:

env:
global:
- TRAVIS_NODE_VERSION="6"
- CXX="g++-4.8"
- CC="gcc-4.8"
- RUST_BACKTRACE="1"
Expand Down Expand Up @@ -51,7 +50,6 @@ addons:
- g++-4.8

install:
- rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION
- ([ "$RUN_COVERAGE" = "false" ]) || (test -x $KCOV_CMD) || (
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
tar xzf master.tar.gz &&
Expand Down
38 changes: 19 additions & 19 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ version = "0.8"
default-features = false

[features]
default = ["dapps", "ethcore-signer/ui"]
default = ["ui", "use-precompiled-js"]
ui = ["dapps", "ethcore-signer/ui"]
use-precompiled-js = ["ethcore-dapps/use-precompiled-js", "ethcore-signer/use-precompiled-js"]
dapps = ["ethcore-dapps"]
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"]
travis-beta = ["ethcore/json-tests"]
Expand Down
14 changes: 10 additions & 4 deletions dapps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ serde_json = "0.7.0"
serde_macros = { version = "0.7.0", optional = true }
ethcore-rpc = { path = "../rpc" }
ethcore-util = { path = "../util" }
parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "0.3" }
parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
# List of apps
parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "0.5.1" }
parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "0.5.2" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6.0", optional = true }
parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" }
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6", optional = true }
mime_guess = { version = "1.6.1" }
clippy = { version = "0.0.79", optional = true}

Expand All @@ -38,3 +38,9 @@ default = ["serde_codegen", "extra-dapps"]
extra-dapps = ["parity-dapps-wallet"]
nightly = ["serde_macros"]
dev = ["clippy", "ethcore-rpc/dev", "ethcore-util/dev"]

use-precompiled-js = [
"parity-dapps-status/use-precompiled-js",
"parity-dapps-home/use-precompiled-js",
"parity-dapps-wallet/use-precompiled-js"
]
107 changes: 81 additions & 26 deletions ethcore/src/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,32 +296,20 @@ impl BlockChain {
// load best block
let best_block_hash = match bc.extras_db.get(b"best").unwrap() {
Some(best) => {
let best = H256::from_slice(&best);
let mut b = best.clone();
let mut removed = 0;
let mut best_num = 0;
while !bc.blocks_db.get(&b).unwrap().is_some() {
// track back to the best block we have in the blocks database
let extras: BlockDetails = bc.extras_db.read(&b).unwrap();
type DetailsKey = Key<BlockDetails, Target=H264>;
bc.extras_db.delete(&(DetailsKey::key(&b))).unwrap();
b = extras.parent;
best_num = extras.number;
removed += 1;
}
if b != best {
let batch = DBTransaction::new();
let range = (best_num + 1) as bc::Number .. (best_num + removed) as bc::Number;
let chain = bc::group::BloomGroupChain::new(bc.blooms_config, &bc);
let changes = chain.replace(&range, vec![]);
for (k, v) in changes.into_iter() {
batch.write(&LogGroupPosition::from(k), &BloomGroup::from(v));
let mut new_best = H256::from_slice(&best);
while !bc.blocks_db.get(&new_best).unwrap().is_some() {
match bc.rewind() {
Some(h) => {
new_best = h;
}
None => {
warn!("Can't rewind blockchain");
break;
}
}
batch.put(b"best", &b).unwrap();
bc.extras_db.write(batch).unwrap();
info!("Restored mismatched best block. Was: {}, new: {}", best.hex(), b.hex());
info!("Restored mismatched best block. Was: {}, new: {}", H256::from_slice(&best).hex(), new_best.hex());
}
b
new_best
}
None => {
// best block does not exist
Expand Down Expand Up @@ -365,6 +353,46 @@ impl BlockChain {
self.extras_db.read_with_cache(&self.block_details, parent).map_or(false, |d| d.children.contains(hash))
}

/// Rewind to a previous block
pub fn rewind(&self) -> Option<H256> {
let batch = DBTransaction::new();
// track back to the best block we have in the blocks database
if let Some(best_block_hash) = self.extras_db.get(b"best").unwrap() {
let best_block_hash = H256::from_slice(&best_block_hash);
if best_block_hash == self.genesis_hash() {
return None;
}
if let Some(extras) = self.extras_db.read(&best_block_hash) as Option<BlockDetails> {
type DetailsKey = Key<BlockDetails, Target=H264>;
batch.delete(&(DetailsKey::key(&best_block_hash))).unwrap();
let hash = extras.parent;
let range = extras.number as bc::Number .. extras.number as bc::Number;
let chain = bc::group::BloomGroupChain::new(self.blooms_config, self);
let changes = chain.replace(&range, vec![]);
for (k, v) in changes.into_iter() {
batch.write(&LogGroupPosition::from(k), &BloomGroup::from(v));
}
batch.put(b"best", &hash).unwrap();
let mut best_block = self.best_block.write();
best_block.number = extras.number - 1;
best_block.total_difficulty = self.block_details(&hash).unwrap().total_difficulty;
best_block.hash = hash;
// update parent extras
if let Some(mut details) = self.extras_db.read(&hash) as Option<BlockDetails> {
details.children.clear();
batch.write(&hash, &details);
}
self.extras_db.write(batch).unwrap();
self.block_details.write().clear();
self.block_hashes.write().clear();
self.blocks.write().clear();
self.block_receipts.write().clear();
return Some(hash);
}
}
return None;
}

/// Set the cache configuration.
pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) {
self.pref_cache_size.store(pref_cache_size, AtomicOrder::Relaxed);
Expand Down Expand Up @@ -514,14 +542,15 @@ impl BlockChain {
batch.extend_with_cache(&mut *write_blocks_blooms, update.blocks_blooms, CacheUpdatePolicy::Remove);
}

// These cached values must be updated last and togeterh
// These cached values must be updated last with all three locks taken to avoid
// cache decoherence
{
let mut best_block = self.best_block.write();
// update best block
match update.info.location {
BlockLocation::Branch => (),
_ => {
batch.put(b"best", &update.info.hash).unwrap();
let mut best_block = self.best_block.write();
*best_block = BestBlock {
hash: update.info.hash,
number: update.info.number,
Expand Down Expand Up @@ -1222,4 +1251,30 @@ mod tests {
let bc = BlockChain::new(Config::default(), &genesis, temp.as_path());
assert_eq!(bc.best_block_number(), 5);
}

#[test]
fn test_rewind() {
let mut canon_chain = ChainGenerator::default();
let mut finalizer = BlockFinalizer::default();
let genesis = canon_chain.generate(&mut finalizer).unwrap();
let first = canon_chain.generate(&mut finalizer).unwrap();
let second = canon_chain.generate(&mut finalizer).unwrap();
let genesis_hash = BlockView::new(&genesis).header_view().sha3();
let first_hash = BlockView::new(&first).header_view().sha3();
let second_hash = BlockView::new(&second).header_view().sha3();

let temp = RandomTempPath::new();
let bc = BlockChain::new(Config::default(), &genesis, temp.as_path());

bc.insert_block(&first, vec![]);
bc.insert_block(&second, vec![]);

assert_eq!(bc.rewind(), Some(first_hash.clone()));
assert!(!bc.is_known(&second_hash));
assert_eq!(bc.best_block_number(), 1);
assert_eq!(bc.best_block_hash(), first_hash.clone());

assert_eq!(bc.rewind(), Some(genesis_hash.clone()));
assert_eq!(bc.rewind(), None);
}
}
52 changes: 43 additions & 9 deletions ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,18 @@ use std::sync::{Arc, Weak};
use std::path::{Path, PathBuf};
use std::fmt;
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::Instant;
use std::time::{Instant, Duration};
use time::precise_time_ns;

// util
use util::{journaldb, rlp, Bytes, Stream, View, PerfTimer, Itertools, Mutex, RwLock, Colour};
use util::journaldb::JournalDB;
use util::rlp::{RlpStream, Rlp, UntrustedRlp};
use util::numbers::*;
use util::panics::*;
use util::io::*;
use util::rlp;
use util::sha3::*;
use util::Bytes;
use util::rlp::{RlpStream, Rlp, UntrustedRlp};
use util::journaldb;
use util::journaldb::JournalDB;
use util::kvdb::*;
use util::{Stream, View, PerfTimer, Itertools};
use util::{Mutex, RwLock};

// other
use views::BlockView;
Expand Down Expand Up @@ -140,6 +137,8 @@ pub struct Client {
io_channel: IoChannel<ClientIoMessage>,
notify: RwLock<Option<Weak<ChainNotify>>>,
queue_transactions: AtomicUsize,
skipped: AtomicUsize,
last_import: Mutex<Instant>,
last_hashes: RwLock<VecDeque<H256>>,
}

Expand Down Expand Up @@ -201,6 +200,11 @@ impl Client {
state_db.commit(0, &spec.genesis_header().hash(), None).expect("Error commiting genesis state to state DB");
}

while !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.contains(h.state_root())) {
warn!("State root not found for block #{} ({}), recovering...", chain.best_block_number(), chain.best_block_hash().hex());
chain.rewind();
}

let engine = Arc::new(spec.engine);

let block_queue = BlockQueue::new(config.queue, engine.clone(), message_channel.clone());
Expand All @@ -227,6 +231,8 @@ impl Client {
io_channel: message_channel,
notify: RwLock::new(None),
queue_transactions: AtomicUsize::new(0),
skipped: AtomicUsize::new(0),
last_import: Mutex::new(Instant::now()),
last_hashes: RwLock::new(VecDeque::new()),
};
Ok(Arc::new(client))
Expand Down Expand Up @@ -361,24 +367,52 @@ impl Client {

for block in blocks {
let header = &block.header;
let start = precise_time_ns();

if invalid_blocks.contains(&header.parent_hash) {
invalid_blocks.insert(header.hash());
continue;
}
let tx_count = block.transactions.len();
let size = block.bytes.len();

let closed_block = self.check_and_close_block(&block);
if let Err(_) = closed_block {
invalid_blocks.insert(header.hash());
continue;
}

let closed_block = closed_block.unwrap();
imported_blocks.push(header.hash());

let route = self.commit_block(closed_block, &header.hash(), &block.bytes);
import_results.push(route);

self.report.write().accrue_block(&block);
trace!(target: "client", "Imported #{} ({})", header.number(), header.hash());

let duration_ns = precise_time_ns() - start;

let mut last_import = self.last_import.lock();
if Instant::now() > *last_import + Duration::from_secs(1) {
let queue_info = self.queue_info();
let importing = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3;
if !importing {
let skipped = self.skipped.load(AtomicOrdering::Relaxed);
info!(target: "import", "Imported {} {} ({} txs, {} Mgas, {} ms, {} KiB){}",
Colour::White.bold().paint(format!("#{}", header.number())),
Colour::White.bold().paint(format!("{}", header.hash())),
Colour::Yellow.bold().paint(format!("{}", tx_count)),
Colour::Yellow.bold().paint(format!("{:.2}", header.gas_used.low_u64() as f32 / 1000000f32)),
Colour::Purple.bold().paint(format!("{:.2}", duration_ns as f32 / 1000000f32)),
Colour::Blue.bold().paint(format!("{:.2}", size as f32 / 1024f32)),
if skipped > 0 { format!(" + another {} block(s)", Colour::Red.bold().paint(format!("{}", skipped))) } else { String::new() }
);
*last_import = Instant::now();
}
self.skipped.store(0, AtomicOrdering::Relaxed);
} else {
self.skipped.fetch_add(1, AtomicOrdering::Relaxed);
}
}

let imported = imported_blocks.len();
Expand Down
Loading

0 comments on commit 529ab3c

Please sign in to comment.