Add standalone set head operations (#1600)

* Refactor head setting operation to a separate function

* Fix commit issue and implement set_head standalone in db

* Add standalone set head operations

* Address grumbles

* Change number_and_hash_to_lookup key in light mod to take reference

* Fix bug in set head commit

* Add a convenience fn

* Fix a deadlock

* Fix missing argument
This commit is contained in:
Wei Tang
2019-02-12 17:21:25 +01:00
committed by Gav Wood
parent 6122f7d6b6
commit 22048dba60
7 changed files with 321 additions and 175 deletions
+71 -43
View File
@@ -189,6 +189,61 @@ impl<Block: BlockT> LightStorage<Block> {
.cloned()))
}
/// Handle setting head within a transaction. `route_to` should be the last
/// block that existed in the database. `best_to` should be the best block
/// to be set.
///
/// In the case where the new best block is a block to be imported, `route_to`
/// should be the parent of `best_to`. In the case where we set an existing block
/// to be best, `route_to` should equal to `best_to`.
fn set_head_with_transaction(&self, transaction: &mut DBTransaction, route_to: Block::Hash, best_to: (NumberFor<Block>, Block::Hash)) -> Result<(), client::error::Error> {
let lookup_key = utils::number_and_hash_to_lookup_key(best_to.0, &best_to.1);
// handle reorg.
let meta = self.meta.read();
if meta.best_hash != Default::default() {
let tree_route = ::client::blockchain::tree_route(
self,
BlockId::Hash(meta.best_hash),
BlockId::Hash(route_to),
)?;
// update block number to hash lookup entries.
for retracted in tree_route.retracted() {
if retracted.hash == meta.finalized_hash {
// TODO: can we recover here?
warn!("Safety failure: reverting finalized block {:?}",
(&retracted.number, &retracted.hash));
}
utils::remove_number_to_key_mapping(
transaction,
columns::KEY_LOOKUP,
retracted.number
);
}
for enacted in tree_route.enacted() {
utils::insert_number_to_key_mapping(
transaction,
columns::KEY_LOOKUP,
enacted.number,
enacted.hash
);
}
}
transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
utils::insert_number_to_key_mapping(
transaction,
columns::KEY_LOOKUP,
best_to.0,
best_to.1,
);
Ok(())
}
// Note that a block is finalized. Only call with child of last finalized block.
fn note_finalized(
&self,
@@ -325,51 +380,10 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
}
// blocks are keyed by number + hash.
let lookup_key = utils::number_and_hash_to_lookup_key(number, hash);
let lookup_key = utils::number_and_hash_to_lookup_key(number, &hash);
if leaf_state.is_best() {
// handle reorg.
{
let meta = self.meta.read();
if meta.best_hash != Default::default() {
let tree_route = ::client::blockchain::tree_route(
self,
BlockId::Hash(meta.best_hash),
BlockId::Hash(parent_hash),
)?;
// update block number to hash lookup entries.
for retracted in tree_route.retracted() {
if retracted.hash == meta.finalized_hash {
warn!("Safety failure: reverting finalized block {:?}",
(&retracted.number, &retracted.hash));
}
utils::remove_number_to_key_mapping(
&mut transaction,
columns::KEY_LOOKUP,
retracted.number
);
}
for enacted in tree_route.enacted() {
utils::insert_number_to_key_mapping(
&mut transaction,
columns::KEY_LOOKUP,
enacted.number,
enacted.hash
);
}
}
}
transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
utils::insert_number_to_key_mapping(
&mut transaction,
columns::KEY_LOOKUP,
number,
hash,
);
self.set_head_with_transaction(&mut transaction, parent_hash, (number, hash))?;
}
utils::insert_hash_to_key_mapping(
@@ -426,6 +440,20 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
Ok(())
}
fn set_head(&self, id: BlockId<Block>) -> ClientResult<()> {
if let Some(header) = self.header(id)? {
let hash = header.hash();
let number = header.number();
let mut transaction = DBTransaction::new();
self.set_head_with_transaction(&mut transaction, hash.clone(), (number.clone(), hash.clone()))?;
self.db.write(transaction).map_err(db_err)?;
Ok(())
} else {
Err(ClientErrorKind::UnknownBlock(format!("Cannot set head {:?}", id)).into())
}
}
fn header_cht_root(&self, cht_size: u64, block: NumberFor<Block>) -> ClientResult<Block::Hash> {
self.read_cht_root(HEADER_CHT_PREFIX, cht_size, block)
}