Adds cli interface to allow reseting chain to a particular block (#9782)

* added BlockChainReset trait, client impl, and cli interface

* show block hashes to be deleted and new best block, update best block in db, better cli interface

* delete BlockNumber from COL_EXTRA

* add TODO comment

* add BlockReciepts to imports

* refactor block_headers_from_best_block, better cli documentation

* exit gracefully if reset arg isn't supplied

* fix cli usage macro

* removed stray int literals

* use Vec::with_capacity

Co-Authored-By: seunlanlege <seunlanlege@gmail.com>

* cast n to usize

* correct imports

* make db reset arg required
This commit is contained in:
Seun LanLege
2019-01-16 19:37:26 +04:00
committed by Afri Schoedon
parent 1df6361753
commit cdba22a2cb
8 changed files with 137 additions and 6 deletions

View File

@@ -21,7 +21,7 @@ use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::sync::{Arc, Weak};
use std::time::{Instant, Duration};
use blockchain::{BlockReceipts, BlockChain, BlockChainDB, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert};
use blockchain::{BlockReceipts, BlockChain, BlockChainDB, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert, BlockNumberKey};
use bytes::Bytes;
use ethcore_miner::pool::VerifiedTransaction;
use ethereum_types::{H256, Address, U256};
@@ -50,7 +50,7 @@ use client::{
RegistryInfo, ReopenBlock, PrepareOpenBlock, ScheduleInfo, ImportSealedBlock,
BroadcastProposalBlock, ImportBlock, StateOrBlock, StateInfo, StateClient, Call,
AccountData, BlockChain as BlockChainTrait, BlockProducer, SealedBlockImporter,
ClientIoMessage,
ClientIoMessage, BlockChainReset
};
use client::{
BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient,
@@ -77,12 +77,14 @@ use verification::queue::kind::BlockLike;
use verification::queue::kind::blocks::Unverified;
use verification::{PreverifiedBlock, Verifier, BlockQueue};
use verification;
use ansi_term::Colour;
// re-export
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_contract!(registry, "res/contracts/registrar.json");
@@ -469,6 +471,7 @@ impl Importer {
// it is for reconstructing the state transition.
//
// The header passed is from the original block data and is sealed.
// TODO: should return an error if ImportRoute is none, issue #9910
fn commit_block<B>(&self, block: B, header: &Header, block_data: encoded::Block, client: &Client) -> ImportRoute where B: Drain {
let hash = &header.hash();
let number = header.number();
@@ -1328,6 +1331,48 @@ impl snapshot::DatabaseRestore for Client {
}
}
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())
}
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 db_transaction = DBTransaction::with_capacity((num + 1) as usize);
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());
Writable::delete::<H256, BlockNumberKey>
(&mut db_transaction, ::db::COL_EXTRA, &hash.number());
}
// update the new best block hash
db_transaction.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))
);
info!("New best block hash {}", Colour::Green.bold().paint(format!("{:?}", best_block_hash)));
Ok(())
}
}
impl Nonce for Client {
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
self.state_at(id).and_then(|s| s.nonce(address).ok())

View File

@@ -37,7 +37,8 @@ pub use self::test_client::{TestBlockChainClient, EachBlockWith};
pub use self::chain_notify::{ChainNotify, NewBlocks, ChainRoute, ChainRouteType, ChainMessageType};
pub use self::traits::{
Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock,
StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, BadBlocks,
StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter,
BadBlocks, BlockChainReset
};
pub use state::StateInfo;
pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient, IoClient};

View File

@@ -482,3 +482,9 @@ pub trait ProvingBlockChainClient: BlockChainClient {
/// Get an epoch change signal by block hash.
fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>>;
}
/// resets the blockchain
pub trait BlockChainReset {
/// reset to best_block - n
fn reset(&self, num: u32) -> Result<(), String>;
}