Skip to content

Commit

Permalink
Adds cli interface to allow reseting chain to a particular block (ope…
Browse files Browse the repository at this point in the history
…nethereum#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
  • Loading branch information
seunlanlege authored and HCastano committed Feb 12, 2019
1 parent 86edc20 commit cbaedad
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 8 deletions.
15 changes: 15 additions & 0 deletions ethcore/blockchain/src/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,21 @@ 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
2 changes: 1 addition & 1 deletion ethcore/blockchain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ pub use self::cache::CacheSize;
pub use self::config::Config;
pub use self::import_route::ImportRoute;
pub use self::update::ExtrasInsert;
pub use ethcore_db::keys::{BlockReceipts, BlockDetails, TransactionAddress};
pub use ethcore_db::keys::{BlockReceipts, BlockDetails, TransactionAddress, BlockNumberKey};
pub use common_types::tree_route::TreeRoute;
48 changes: 46 additions & 2 deletions ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 call_contract::{CallContract, RegistryInfo};
use ethcore_miner::pool::VerifiedTransaction;
Expand Down Expand Up @@ -52,7 +52,7 @@ use client::{
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,
Expand Down Expand Up @@ -80,12 +80,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");

Expand Down Expand Up @@ -1329,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())
Expand Down
7 changes: 4 additions & 3 deletions ethcore/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ pub use self::io_message::ClientIoMessage;
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, TransactionInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock,
StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, BadBlocks,
BlockChainReset
Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, TransactionInfo,
ScheduleInfo, ImportSealedBlock,BroadcastProposalBlock, ImportBlock,
StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter,
BadBlocks, BlockChainReset
};
pub use state::StateInfo;
pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient, IoClient};
Expand Down
6 changes: 6 additions & 0 deletions ethcore/src/client/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,3 +471,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>;
}
42 changes: 41 additions & 1 deletion parity/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ use ethereum_types::{U256, H256, Address};
use bytes::ToPretty;
use rlp::PayloadInfo;
use ethcore::account_provider::AccountProvider;
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock};
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, Nonce, Balance, BlockChainClient, BlockId, BlockInfo,
ImportBlock, BlockChainReset};
use ethcore::error::{ImportErrorKind, ErrorKind as EthcoreErrorKind, Error as EthcoreError};
use ethcore::miner::Miner;
use ethcore::verification::queue::VerifierSettings;
Expand All @@ -40,6 +41,7 @@ use dir::Directories;
use user_defaults::UserDefaults;
use ethcore_private_tx;
use db;
use ansi_term::Colour;

#[derive(Debug, PartialEq)]
pub enum DataFormat {
Expand Down Expand Up @@ -71,6 +73,21 @@ pub enum BlockchainCmd {
Import(ImportBlockchain),
Export(ExportBlockchain),
ExportState(ExportState),
Reset(ResetBlockchain)
}

#[derive(Debug, PartialEq)]
pub struct ResetBlockchain {
pub dirs: Directories,
pub spec: SpecType,
pub pruning: Pruning,
pub pruning_history: u64,
pub pruning_memory: usize,
pub tracing: Switch,
pub fat_db: Switch,
pub compaction: DatabaseCompactionProfile,
pub cache_config: CacheConfig,
pub num: u32,
}

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -153,6 +170,7 @@ pub fn execute(cmd: BlockchainCmd) -> Result<(), String> {
}
BlockchainCmd::Export(export_cmd) => execute_export(export_cmd),
BlockchainCmd::ExportState(export_cmd) => execute_export_state(export_cmd),
BlockchainCmd::Reset(reset_cmd) => execute_reset(reset_cmd),
}
}

Expand Down Expand Up @@ -709,6 +727,28 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> {
Ok(())
}

fn execute_reset(cmd: ResetBlockchain) -> Result<(), String> {
let service = start_client(
cmd.dirs,
cmd.spec,
cmd.pruning,
cmd.pruning_history,
cmd.pruning_memory,
cmd.tracing,
cmd.fat_db,
cmd.compaction,
cmd.cache_config,
false,
0,
)?;

let client = service.client();
client.reset(cmd.num)?;
info!("{}", Colour::Green.bold().paint("Successfully reset db!"));

Ok(())
}

pub fn kill_db(cmd: KillBlockchain) -> Result<(), String> {
let spec = cmd.spec.spec(&cmd.dirs.cache)?;
let genesis_hash = spec.genesis_header().hash();
Expand Down
11 changes: 11 additions & 0 deletions parity/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,15 @@ usage! {
CMD cmd_db_kill {
"Clean the database of the given --chain (default: mainnet)",
}

CMD cmd_db_reset {
"Removes NUM latests blocks from the db",

ARG arg_db_reset_num: (u32) = 10u32,
"<NUM>",
"Number of blocks to revert",
}

}

CMD cmd_export_hardcoded_sync
Expand Down Expand Up @@ -1612,6 +1621,7 @@ mod tests {
cmd_tools_hash: false,
cmd_db: false,
cmd_db_kill: false,
cmd_db_reset: false,
cmd_export_hardcoded_sync: false,

// Arguments
Expand All @@ -1631,6 +1641,7 @@ mod tests {
arg_dapp_path: None,
arg_account_import_path: None,
arg_wallet_import_path: None,
arg_db_reset_num: 10,

// -- Operating Options
arg_mode: "last".into(),
Expand Down
15 changes: 14 additions & 1 deletion parity/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use ethcore_private_tx::{ProviderConfig, EncryptorConfig};
use secretstore::{NodeSecretKey, Configuration as SecretStoreConfiguration, ContractAddress as SecretStoreContractAddress};
use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack};
use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat};
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat, ResetBlockchain};
use export_hardcoded_sync::ExportHsyncCmd;
use presale::ImportWallet;
use account::{AccountCmd, NewAccount, ListAccounts, ImportAccounts, ImportFromGethAccounts};
Expand Down Expand Up @@ -176,6 +176,19 @@ impl Configuration {
}
} else if self.args.cmd_tools && self.args.cmd_tools_hash {
Cmd::Hash(self.args.arg_tools_hash_file)
} else if self.args.cmd_db && self.args.cmd_db_reset {
Cmd::Blockchain(BlockchainCmd::Reset(ResetBlockchain {
dirs,
spec,
pruning,
pruning_history,
pruning_memory: self.args.arg_pruning_memory,
tracing,
fat_db,
compaction,
cache_config,
num: self.args.arg_db_reset_num,
}))
} else if self.args.cmd_db && self.args.cmd_db_kill {
Cmd::Blockchain(BlockchainCmd::Kill(KillBlockchain {
spec: spec,
Expand Down

0 comments on commit cbaedad

Please sign in to comment.