Ancient target set. InvalidStateRoot bug (#69) (#149)

This commit is contained in:
rakita
2020-12-10 17:57:26 +01:00
committed by GitHub
parent ea3efd926e
commit 837e8b8725
5 changed files with 78 additions and 33 deletions

View File

@@ -531,6 +531,10 @@ impl Importer {
.unwrap_or_else(|e| panic!("Receipt bytes should be valid: {:?}", e));
let _import_lock = self.import_lock.lock();
if unverified.header.number() >= chain.best_block_header().number() {
panic!("Ancient block number is higher then best block number");
}
{
trace_time!("import_old_block");
// verify the block, passing the chain for updating the epoch verifier.
@@ -1201,15 +1205,27 @@ impl Client {
/// Get a copy of the best block's state.
pub fn latest_state_and_header(&self) -> (State<StateDB>, Header) {
let header = self.best_block_header();
let state = State::from_existing(
self.state_db.read().boxed_clone_canon(&header.hash()),
*header.state_root(),
self.engine.account_start_nonce(header.number()),
self.factories.clone(),
)
.expect("State root of best block header always valid.");
(state, header)
let mut nb_tries = 5;
// Here, we are taking latest block and then latest state. If in between those two calls `best` block got prunned app will panic.
// This is something that should not happend often and it is edge case.
// Locking read best_block lock would be more straighforward, but can introduce overlaping locks,
// because of this we are just taking 5 tries to get best state in most cases it will work on first try.
while nb_tries != 0 {
let header = self.best_block_header();
match State::from_existing(
self.state_db.read().boxed_clone_canon(&header.hash()),
*header.state_root(),
self.engine.account_start_nonce(header.number()),
self.factories.clone(),
) {
Ok(ret) => return (ret, header),
Err(_) => {
warn!("Couldn't fetch state of best block header: {:?}", header);
nb_tries -= 1;
}
}
}
panic!("Couldn't get latest state in 5 tries");
}
/// Attempt to get a copy of a specific block's final state.