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

Commit

Permalink
Merge branch 'master' into dp/fix/move-step-service-into-clique
Browse files Browse the repository at this point in the history
* master:
  add_sync_notifier in EthPubSubClient holds on to a Client for too long (#10689)
  Don't panic if extra_data is longer than VANITY_LENGTH (#10682)
  docs: evmbin - Update Rust docs (#10658)
  Remove annoying compiler warnings (#10679)
  Reset blockchain properly (#10669)
  • Loading branch information
dvdplm committed May 23, 2019
2 parents 569c8fc + d250f34 commit 70b1e0c
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 43 deletions.
23 changes: 8 additions & 15 deletions ethcore/blockchain/src/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,21 +668,6 @@ impl BlockChain {
self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_details, parent).map_or(false, |d| d.children.contains(hash))
}

/// fetches the list of blocks from best block to n, and n's parent hash
/// where n > 0
pub fn block_headers_from_best_block(&self, n: u32) -> Option<(Vec<encoded::Header>, H256)> {
let mut blocks = Vec::with_capacity(n as usize);
let mut hash = self.best_block_hash();

for _ in 0..n {
let current_hash = self.block_header_data(&hash)?;
hash = current_hash.parent_hash();
blocks.push(current_hash);
}

Some((blocks, hash))
}

/// Returns a tree route between `from` and `to`, which is a tuple of:
///
/// - a vector of hashes of all blocks, ordered from `from` to `to`.
Expand Down Expand Up @@ -869,6 +854,14 @@ impl BlockChain {
}
}

/// clears all caches for testing purposes
pub fn clear_cache(&self) {
self.block_bodies.write().clear();
self.block_details.write().clear();
self.block_hashes.write().clear();
self.block_headers.write().clear();
}

/// Update the best ancient block to the given hash, after checking that
/// it's directly linked to the currently known best ancient block
pub fn update_best_ancient_block(&self, hash: &H256) {
Expand Down
67 changes: 45 additions & 22 deletions ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use blockchain::{BlockReceipts, BlockChain, BlockChainDB, BlockProvider, TreeRou
use bytes::Bytes;
use call_contract::{CallContract, RegistryInfo};
use ethcore_miner::pool::VerifiedTransaction;
use ethereum_types::{H256, Address, U256};
use ethereum_types::{H256, H264, Address, U256};
use evm::Schedule;
use hash::keccak;
use io::IoChannel;
Expand Down Expand Up @@ -86,7 +86,7 @@ pub use types::blockchain_info::BlockChainInfo;
pub use types::block_status::BlockStatus;
pub use blockchain::CacheSize as BlockChainCacheSize;
pub use verification::QueueInfo as BlockQueueInfo;
use db::Writable;
use db::{Writable, Readable, keys::BlockDetails};

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

Expand Down Expand Up @@ -1327,37 +1327,60 @@ impl BlockChainReset for Client {
fn reset(&self, num: u32) -> Result<(), String> {
if num as u64 > self.pruning_history() {
return Err("Attempting to reset to block with pruned state".into())
} else if num == 0 {
return Err("invalid number of blocks to reset".into())
}

let (blocks_to_delete, best_block_hash) = self.chain.read()
.block_headers_from_best_block(num)
.ok_or("Attempted to reset past genesis block")?;
let mut blocks_to_delete = Vec::with_capacity(num as usize);
let mut best_block_hash = self.chain.read().best_block_hash();
let mut batch = DBTransaction::with_capacity(blocks_to_delete.len());

let mut db_transaction = DBTransaction::with_capacity((num + 1) as usize);
for _ in 0..num {
let current_header = self.chain.read().block_header_data(&best_block_hash)
.expect("best_block_hash was fetched from db; block_header_data should exist in db; qed");
best_block_hash = current_header.parent_hash();

for hash in &blocks_to_delete {
db_transaction.delete(::db::COL_HEADERS, &hash.hash());
db_transaction.delete(::db::COL_BODIES, &hash.hash());
db_transaction.delete(::db::COL_EXTRA, &hash.hash());
let (number, hash) = (current_header.number(), current_header.hash());
batch.delete(::db::COL_HEADERS, &hash);
batch.delete(::db::COL_BODIES, &hash);
Writable::delete::<BlockDetails, H264>
(&mut batch, ::db::COL_EXTRA, &hash);
Writable::delete::<H256, BlockNumberKey>
(&mut db_transaction, ::db::COL_EXTRA, &hash.number());
(&mut batch, ::db::COL_EXTRA, &number);

blocks_to_delete.push((number, hash));
}

let hashes = blocks_to_delete.iter().map(|(_, hash)| hash).collect::<Vec<_>>();
info!("Deleting block hashes {}",
Colour::Red
.bold()
.paint(format!("{:#?}", hashes))
);

let mut best_block_details = Readable::read::<BlockDetails, H264>(
&**self.db.read().key_value(),
::db::COL_EXTRA,
&best_block_hash
).expect("block was previously imported; best_block_details should exist; qed");

let (_, last_hash) = blocks_to_delete.last()
.expect("num is > 0; blocks_to_delete can't be empty; qed");
// remove the last block as a child so that it can be re-imported
// ethcore/blockchain/src/blockchain.rs/Blockchain::is_known_child()
best_block_details.children.retain(|h| *h != *last_hash);
batch.write(
::db::COL_EXTRA,
&best_block_hash,
&best_block_details
);
// update the new best block hash
db_transaction.put(::db::COL_EXTRA, b"best", &*best_block_hash);
batch.put(::db::COL_EXTRA, b"best", &best_block_hash);

self.db.read()
.key_value()
.write(db_transaction)
.map_err(|err| format!("could not complete reset operation; io error occured: {}", err))?;

let hashes = blocks_to_delete.iter().map(|b| b.hash()).collect::<Vec<_>>();

info!("Deleting block hashes {}",
Colour::Red
.bold()
.paint(format!("{:#?}", hashes))
);
.write(batch)
.map_err(|err| format!("could not delete blocks; io error occurred: {}", err))?;

info!("New best block hash {}", Colour::Green.bold().paint(format!("{:?}", best_block_hash)));

Expand Down
22 changes: 21 additions & 1 deletion ethcore/src/tests/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use types::filter::Filter;
use types::view;
use types::views::BlockView;

use client::{BlockChainClient, Client, ClientConfig, BlockId, ChainInfo, BlockInfo, PrepareOpenBlock, ImportSealedBlock, ImportBlock};
use client::{BlockChainClient, BlockChainReset, Client, ClientConfig, BlockId, ChainInfo, BlockInfo, PrepareOpenBlock, ImportSealedBlock, ImportBlock};
use ethereum;
use executive::{Executive, TransactOptions};
use miner::{Miner, PendingOrdering, MinerService};
Expand Down Expand Up @@ -366,3 +366,23 @@ fn transaction_proof() {
assert_eq!(state.balance(&Address::default()).unwrap(), 5.into());
assert_eq!(state.balance(&address).unwrap(), 95.into());
}

#[test]
fn reset_blockchain() {
let client = get_test_client_with_blocks(get_good_dummy_block_seq(19));
// 19 + genesis block
assert!(client.block_header(BlockId::Number(20)).is_some());
assert_eq!(client.block_header(BlockId::Number(20)).unwrap().hash(), client.best_block_header().hash());

assert!(client.reset(5).is_ok());

client.chain().clear_cache();

assert!(client.block_header(BlockId::Number(20)).is_none());
assert!(client.block_header(BlockId::Number(19)).is_none());
assert!(client.block_header(BlockId::Number(18)).is_none());
assert!(client.block_header(BlockId::Number(17)).is_none());
assert!(client.block_header(BlockId::Number(16)).is_none());

assert!(client.block_header(BlockId::Number(15)).is_some());
}
2 changes: 1 addition & 1 deletion evmbin/benches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! benchmarking for EVM
//! should be started with:
//! ```bash
//! multirust run nightly cargo bench
//! rustup run nightly cargo bench
//! ```

#![feature(test)]
Expand Down
22 changes: 21 additions & 1 deletion evmbin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,23 @@
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.

//! Parity EVM interpreter binary.
//! Parity EVM Interpreter Binary.
//!
//! ## Overview
//!
//! The Parity EVM interpreter binary is a tool in the Parity
//! Ethereum toolchain. It is an EVM implementation for Parity Ethereum that
//! is used to run a standalone version of the EVM interpreter.
//!
//! ## Usage
//!
//! The evmbin tool is not distributed with regular Parity Ethereum releases
//! so you need to build it from source and run it like so:
//!
//! ```bash
//! cargo build -p evmbin --release
//! ./target/release/parity-evm --help
//! ```

#![warn(missing_docs)]

Expand Down Expand Up @@ -268,13 +284,17 @@ struct Args {
}

impl Args {
/// Set the gas limit. Defaults to max value to allow code to run for whatever time is required.
pub fn gas(&self) -> Result<U256, String> {
match self.flag_gas {
Some(ref gas) => gas.parse().map_err(to_string),
None => Ok(U256::from(u64::max_value())),
}
}

/// Set the gas price. Defaults to zero to allow the code to run even if an account with no balance
/// is used, otherwise such accounts would not have sufficient funds to pay the transaction fee.
/// Defaulting to zero also makes testing easier since it is not necessary to specify a special configuration file.
pub fn gas_price(&self) -> Result<U256, String> {
match self.flag_gas_price {
Some(ref gas_price) => gas_price.parse().map_err(to_string),
Expand Down
8 changes: 5 additions & 3 deletions rpc/src/v1/impls/eth_pubsub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ impl<C> EthPubSubClient<C>
where
F: 'static + Fn(SyncState) -> Option<pubsub::PubSubSyncStatus> + Send
{
let handler = self.handler.clone();
let weak_handler = Arc::downgrade(&self.handler);

self.handler.executor.spawn(
receiver.for_each(move |state| {
if let Some(status) = f(state) {
handler.notify_syncing(status);
return Ok(())
if let Some(handler) = weak_handler.upgrade() {
handler.notify_syncing(status);
return Ok(())
}
}
Err(())
})
Expand Down

0 comments on commit 70b1e0c

Please sign in to comment.