Merge branch 'master' into rh-grandpa-dynamic2

This commit is contained in:
Robert Habermeier
2018-10-22 16:06:42 +02:00
87 changed files with 2757 additions and 993 deletions
+5 -5
View File
@@ -91,7 +91,7 @@ pub struct Fork<Block: BlockT, T> {
head: Entry<Block, T>,
}
/// Outcome of Fork::try_append_or_fork.
/// Outcome of Fork::try_append_or_fork.
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub enum ForkAppendResult<Block: BlockT> {
@@ -356,7 +356,7 @@ impl<Block: BlockT, T: CacheItemT, S: Storage<Block, T>> ListCache<Block, T, S>
// if there's an entry at this block:
// - remove reference from this entry to the previous entry
// - destroy fork starting with previous entry
// - destroy fork starting with previous entry
let current_entry = match self.storage.read_entry(&ancient_block)? {
Some(current_entry) => current_entry,
None => return Ok(()),
@@ -583,12 +583,12 @@ fn read_forks<Block: BlockT, T: CacheItemT, S: Storage<Block, T>>(
#[cfg(test)]
pub mod tests {
use runtime_primitives::testing::{Header, Block as RawBlock};
use runtime_primitives::testing::{Header, Block as RawBlock, ExtrinsicWrapper};
use runtime_primitives::traits::Header as HeaderT;
use cache::list_storage::tests::{DummyStorage, FaultyStorage, DummyTransaction};
use super::*;
type Block = RawBlock<u64>;
type Block = RawBlock<ExtrinsicWrapper<u64>>;
pub fn test_id(number: u64) -> ComplexBlockId<Block> {
ComplexBlockId::new(From::from(number), number)
@@ -834,7 +834,7 @@ pub mod tests {
// when trying to insert block @ finalized number
assert!(ListCache::new(DummyStorage::new(), 1024, test_id(100))
.on_block_insert(&mut DummyTransaction::new(), test_id(99), test_id(100), Some(100), false).unwrap().is_none());
// when trying to insert non-final block AND it appends to the best block of unfinalized fork
// AND new value is the same as in the fork' best block
let mut cache = ListCache::new(
+3 -3
View File
@@ -23,7 +23,7 @@ use kvdb::{KeyValueDB, DBTransaction};
use client::error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult};
use codec::{Encode, Decode};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, NumberFor};
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use utils::{self, db_err, meta_keys};
use cache::{CacheItemT, ComplexBlockId};
@@ -126,7 +126,8 @@ impl DbStorage {
impl<Block: BlockT, T: CacheItemT> Storage<Block, T> for DbStorage {
fn read_id(&self, at: NumberFor<Block>) -> ClientResult<Option<Block::Hash>> {
utils::read_id::<Block>(&*self.db, self.columns.hash_lookup, BlockId::Number(at))
utils::read_header::<Block>(&*self.db, self.columns.hash_lookup, self.columns.header, BlockId::Number(at))
.map(|maybe_header| maybe_header.map(|header| header.hash()))
}
fn read_header(&self, at: &Block::Hash) -> ClientResult<Option<Block::Header>> {
@@ -246,7 +247,6 @@ mod meta {
#[cfg(test)]
pub mod tests {
use std::collections::{HashMap, HashSet};
use runtime_primitives::traits::Header as HeaderT;
use super::*;
pub struct FaultyStorage;
+3 -2
View File
@@ -194,10 +194,11 @@ impl<Block: BlockT> BlockchainCache<Block> for DbCacheSync<Block> {
ComplexBlockId::new(hash, *header.number())
},
BlockId::Number(number) => {
let hash = utils::read_id::<Block>(
let hash = utils::read_header::<Block>(
&**db,
columns.hash_lookup,
BlockId::Number(number.clone())).ok()??;
columns.header,
BlockId::Number(number.clone())).ok()??.hash();
ComplexBlockId::new(hash, number)
},
};
+101 -42
View File
@@ -75,7 +75,7 @@ use runtime_primitives::BuildStorage;
use state_machine::backend::Backend as StateBackend;
use executor::RuntimeInfo;
use state_machine::{CodeExecutor, DBValue, ExecutionStrategy};
use utils::{Meta, db_err, meta_keys, open_database, read_db, read_id, read_meta};
use utils::{Meta, db_err, meta_keys, open_database, read_db, block_id_to_lookup_key, read_meta};
use client::LeafSet;
use state_db::StateDb;
pub use state_db::PruningMode;
@@ -118,6 +118,7 @@ mod columns {
pub const META: Option<u32> = ::utils::COLUMN_META;
pub const STATE: Option<u32> = Some(1);
pub const STATE_META: Option<u32> = Some(2);
/// maps hashes to lookup keys
pub const HASH_LOOKUP: Option<u32> = Some(3);
pub const HEADER: Option<u32> = Some(4);
pub const BODY: Option<u32> = Some(5);
@@ -219,15 +220,20 @@ impl<Block: BlockT> client::blockchain::HeaderBackend<Block> for BlockchainDb<Bl
}
}
fn number(&self, hash: Block::Hash) -> Result<Option<<Block::Header as HeaderT>::Number>, client::error::Error> {
self.header(BlockId::Hash(hash)).and_then(|key| match key {
Some(hdr) => Ok(Some(hdr.number().clone())),
None => Ok(None),
})
fn number(&self, hash: Block::Hash) -> Result<Option<NumberFor<Block>>, client::error::Error> {
if let Some(lookup_key) = block_id_to_lookup_key::<Block>(&*self.db, columns::HASH_LOOKUP, BlockId::Hash(hash))? {
let number = utils::lookup_key_to_number(&lookup_key)?;
Ok(Some(number))
} else {
Ok(None)
}
}
fn hash(&self, number: <Block::Header as HeaderT>::Number) -> Result<Option<Block::Hash>, client::error::Error> {
read_id::<Block>(&*self.db, columns::HASH_LOOKUP, BlockId::Number(number))
fn hash(&self, number: NumberFor<Block>) -> Result<Option<Block::Hash>, client::error::Error> {
self.header(BlockId::Number(number)).and_then(|maybe_header| match maybe_header {
Some(header) => Ok(Some(header.hash().clone())),
None => Ok(None),
})
}
}
@@ -495,12 +501,9 @@ impl<Block: BlockT> Backend<Block> {
let hash = if new_canonical == number_u64 {
hash
} else {
read_id::<Block>(
&*self.blockchain.db,
columns::HASH_LOOKUP,
BlockId::Number(As::sa(new_canonical))
)?.expect("existence of block with number `new_canonical` \
implies existence of blocks with all nubmers before it; qed")
::client::blockchain::HeaderBackend::hash(&self.blockchain, As::sa(new_canonical))?
.expect("existence of block with number `new_canonical` \
implies existence of blocks with all numbers before it; qed")
};
trace!(target: "db", "Canonicalize block #{} ({:?})", new_canonical, hash);
@@ -588,14 +591,6 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
let parent_hash = *pending_block.header.parent_hash();
let number = pending_block.header.number().clone();
transaction.put(columns::HEADER, hash.as_ref(), &pending_block.header.encode());
if let Some(body) = pending_block.body {
transaction.put(columns::BODY, hash.as_ref(), &body.encode());
}
if let Some(justification) = pending_block.justification {
transaction.put(columns::JUSTIFICATION, hash.as_ref(), &justification.encode());
}
if pending_block.leaf_state.is_best() {
let meta = self.blockchain.meta.read();
@@ -607,7 +602,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
BlockId::Hash(parent_hash),
)?;
// update block number to hash lookup entries.
// uncanonicalize
for retracted in tree_route.retracted() {
if retracted.hash == meta.finalized_hash {
warn!("Potential safety failure: reverting finalized block {:?}",
@@ -616,30 +611,94 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
return Err(::client::error::ErrorKind::NotInFinalizedChain.into());
}
transaction.delete(
columns::HASH_LOOKUP,
&::utils::number_to_lookup_key(retracted.number)
);
let prev_lookup_key = ::utils::number_to_lookup_key(retracted.number);
let new_lookup_key = ::utils::number_and_hash_to_lookup_key(retracted.number, retracted.hash);
// change mapping from `number -> header`
// to `number + hash -> header`
let retracted_header = if let Some(header) = ::client::blockchain::HeaderBackend::<Block>::header(&self.blockchain, BlockId::Number(retracted.number))? {
header
} else {
return Err(client::error::ErrorKind::UnknownBlock(format!("retracted {:?}", retracted)).into());
};
transaction.delete(columns::HEADER, &prev_lookup_key);
transaction.put(columns::HEADER, &new_lookup_key, &retracted_header.encode());
// if body is stored
// change mapping from `number -> body`
// to `number + hash -> body`
if let Some(retracted_body) = ::client::blockchain::Backend::<Block>::body(&self.blockchain, BlockId::Number(retracted.number))? {
transaction.delete(columns::BODY, &prev_lookup_key);
transaction.put(columns::BODY, &new_lookup_key, &retracted_body.encode());
}
// if justification is stored
// change mapping from `number -> justification`
// to `number + hash -> justification`
if let Some(retracted_justification) = ::client::blockchain::Backend::<Block>::justification(&self.blockchain, BlockId::Number(retracted.number))? {
transaction.delete(columns::JUSTIFICATION, &prev_lookup_key);
transaction.put(columns::JUSTIFICATION, &new_lookup_key, &retracted_justification.encode());
}
transaction.put(columns::HASH_LOOKUP, retracted.hash.as_ref(), &new_lookup_key);
}
// canonicalize
for enacted in tree_route.enacted() {
let hash: &Block::Hash = &enacted.hash;
transaction.put(
columns::HASH_LOOKUP,
&::utils::number_to_lookup_key(enacted.number),
hash.as_ref(),
)
let prev_lookup_key = ::utils::number_and_hash_to_lookup_key(enacted.number, enacted.hash);
let new_lookup_key = ::utils::number_to_lookup_key(enacted.number);
// change mapping from `number + hash -> header`
// to `number -> header`
let enacted_header = if let Some(header) = ::client::blockchain::HeaderBackend::<Block>::header(&self.blockchain, BlockId::Number(enacted.number))? {
header
} else {
return Err(client::error::ErrorKind::UnknownBlock(format!("enacted {:?}", enacted)).into());
};
transaction.delete(columns::HEADER, &prev_lookup_key);
transaction.put(columns::HEADER, &new_lookup_key, &enacted_header.encode());
// if body is stored
// change mapping from `number + hash -> body`
// to `number -> body`
if let Some(enacted_body) = ::client::blockchain::Backend::<Block>::body(&self.blockchain, BlockId::Number(enacted.number))? {
transaction.delete(columns::BODY, &prev_lookup_key);
transaction.put(columns::BODY, &new_lookup_key, &enacted_body.encode());
}
// if justification is stored
// change mapping from `number -> justification`
// to `number + hash -> justification`
if let Some(enacted_justification) = ::client::blockchain::Backend::<Block>::justification(&self.blockchain, BlockId::Number(enacted.number))? {
transaction.delete(columns::JUSTIFICATION, &prev_lookup_key);
transaction.put(columns::JUSTIFICATION, &new_lookup_key, &enacted_justification.encode());
}
transaction.put(columns::HASH_LOOKUP, enacted.hash.as_ref(), &new_lookup_key);
}
}
transaction.put(
columns::HASH_LOOKUP,
&::utils::number_to_lookup_key(number),
hash.as_ref()
);
transaction.put(columns::META, meta_keys::BEST_BLOCK, hash.as_ref());
}
// blocks in longest chain are keyed by number
let lookup_key = if pending_block.leaf_state.is_best() {
::utils::number_to_lookup_key(number).to_vec()
} else {
// other blocks are keyed by number + hash
::utils::number_and_hash_to_lookup_key(number, hash)
};
transaction.put(columns::HEADER, &lookup_key, &pending_block.header.encode());
if let Some(body) = pending_block.body {
transaction.put(columns::BODY, &lookup_key, &body.encode());
}
if let Some(justification) = pending_block.justification {
transaction.put(columns::JUSTIFICATION, &lookup_key, &justification.encode());
}
transaction.put(columns::HASH_LOOKUP, hash.as_ref(), &lookup_key);
if number == Zero::zero() {
transaction.put(columns::META, meta_keys::FINALIZED_BLOCK, hash.as_ref());
transaction.put(columns::META, meta_keys::GENESIS_HASH, hash.as_ref());
@@ -732,14 +791,14 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
match self.storage.state_db.revert_one() {
Some(commit) => {
apply_state_commit(&mut transaction, commit);
let removed = best.clone();
let _removed = best.clone();
best -= As::sa(1);
let header = self.blockchain.header(BlockId::Number(best))?.ok_or_else(
|| client::error::ErrorKind::UnknownBlock(
format!("Error reverting to {}. Block header not found.", best)))?;
transaction.put(columns::META, meta_keys::BEST_BLOCK, header.hash().as_ref());
transaction.delete(columns::HASH_LOOKUP, &::utils::number_to_lookup_key(removed));
transaction.delete(columns::HASH_LOOKUP, header.hash().as_ref());
self.storage.db.write(transaction).map_err(db_err)?;
self.blockchain.update_meta(header.hash().clone(), best.clone(), true, false);
self.blockchain.leaves.write().revert(header.hash().clone(), header.number().clone(), header.parent_hash().clone());
@@ -806,11 +865,11 @@ mod tests {
use client::backend::Backend as BTrait;
use client::backend::BlockImportOperation as Op;
use client::blockchain::HeaderBackend as BlockchainHeaderBackend;
use runtime_primitives::testing::{Header, Block as RawBlock};
use runtime_primitives::testing::{Header, Block as RawBlock, ExtrinsicWrapper};
use state_machine::{TrieMut, TrieDBMut, ChangesTrieRootsStorage, ChangesTrieStorage};
use test_client;
type Block = RawBlock<u64>;
type Block = RawBlock<ExtrinsicWrapper<u64>>;
fn prepare_changes(changes: Vec<(Vec<u8>, Vec<u8>)>) -> (H256, MemoryDB<Blake2Hasher>) {
let mut changes_root = H256::default();
+59 -27
View File
@@ -34,7 +34,7 @@ use runtime_primitives::traits::{Block as BlockT, Header as HeaderT,
Zero, One, As, NumberFor};
use cache::{DbCacheSync, DbCache, ComplexBlockId};
use utils::{meta_keys, Meta, db_err, number_to_lookup_key, open_database,
read_db, read_id, read_meta};
read_db, block_id_to_lookup_key, read_meta};
use DatabaseSettings;
pub(crate) mod columns {
@@ -168,14 +168,16 @@ impl<Block> BlockchainHeaderBackend<Block> for LightStorage<Block>
}
fn number(&self, hash: Block::Hash) -> ClientResult<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
self.header(BlockId::Hash(hash)).and_then(|key| match key {
Some(hdr) => Ok(Some(hdr.number().clone())),
None => Ok(None),
})
if let Some(lookup_key) = block_id_to_lookup_key::<Block>(&*self.db, columns::HASH_LOOKUP, BlockId::Hash(hash))? {
let number = ::utils::lookup_key_to_number(&lookup_key)?;
Ok(Some(number))
} else {
Ok(None)
}
}
fn hash(&self, number: <<Block as BlockT>::Header as HeaderT>::Number) -> ClientResult<Option<Block::Hash>> {
read_id::<Block>(&*self.db, columns::HASH_LOOKUP, BlockId::Number(number))
Ok(self.header(BlockId::Number(number))?.map(|header| header.hash().clone()))
}
}
@@ -212,13 +214,13 @@ impl<Block: BlockT> LightStorage<Block> {
trace!(target: "db", "Replacing blocks [{}..{}] with CHT#{}", new_cht_start, new_cht_end, new_cht_number);
while prune_block <= new_cht_end {
let id = read_id::<Block>(&*self.db, columns::HASH_LOOKUP, BlockId::Number(prune_block))?;
if let Some(hash) = id {
let lookup_key = number_to_lookup_key(prune_block);
transaction.delete(columns::HASH_LOOKUP, &lookup_key);
transaction.delete(columns::HEADER, hash.as_ref());
if let Some(hash) = self.hash(prune_block)? {
let lookup_key = block_id_to_lookup_key::<Block>(&*self.db, columns::HASH_LOOKUP, BlockId::Number(prune_block))?
.expect("retrieved hash for `prune_block` right above. therefore retrieving lookup key must succeed. q.e.d.");
transaction.delete(columns::HASH_LOOKUP, hash.as_ref());
transaction.delete(columns::HEADER, &lookup_key);
}
prune_block += <<Block as BlockT>::Header as HeaderT>::Number::one();
prune_block += NumberFor::<Block>::one();
}
}
}
@@ -242,8 +244,6 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
let number = *header.number();
let parent_hash = *header.parent_hash();
transaction.put(columns::HEADER, hash.as_ref(), &header.encode());
if leaf_state.is_best() {
// handle reorg.
{
@@ -263,27 +263,55 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
(&retracted.number, &retracted.hash));
}
transaction.delete(
columns::HASH_LOOKUP,
&::utils::number_to_lookup_key(retracted.number)
);
let prev_lookup_key = ::utils::number_to_lookup_key(retracted.number);
let new_lookup_key = ::utils::number_and_hash_to_lookup_key(retracted.number, retracted.hash);
// change mapping from `number -> header`
// to `number + hash -> header`
let retracted_header = if let Some(header) = self.header(BlockId::Number(retracted.number))? {
header
} else {
return Err(::client::error::ErrorKind::UnknownBlock(format!("retracted {:?}", retracted)).into());
};
transaction.delete(columns::HEADER, &prev_lookup_key);
transaction.put(columns::HEADER, &new_lookup_key, &retracted_header.encode());
transaction.put(columns::HASH_LOOKUP, retracted.hash.as_ref(), &new_lookup_key);
}
for enacted in tree_route.enacted() {
let hash: &Block::Hash = &enacted.hash;
transaction.put(
columns::HASH_LOOKUP,
&::utils::number_to_lookup_key(enacted.number),
hash.as_ref(),
)
let prev_lookup_key = ::utils::number_and_hash_to_lookup_key(enacted.number, enacted.hash);
let new_lookup_key = ::utils::number_to_lookup_key(enacted.number);
// change mapping from `number + hash -> header`
// to `number -> header`
let enacted_header = if let Some(header) = self.header(BlockId::Number(enacted.number))? {
header
} else {
return Err(::client::error::ErrorKind::UnknownBlock(format!("enacted {:?}", enacted)).into());
};
transaction.delete(columns::HEADER, &prev_lookup_key);
transaction.put(columns::HEADER, &new_lookup_key, &enacted_header.encode());
transaction.put(columns::HASH_LOOKUP, enacted.hash.as_ref(), &new_lookup_key);
}
}
}
transaction.put(columns::META, meta_keys::BEST_BLOCK, hash.as_ref());
transaction.put(columns::HASH_LOOKUP, &number_to_lookup_key(number), hash.as_ref());
}
// blocks in longest chain are keyed by number
let lookup_key = if leaf_state.is_best() {
::utils::number_to_lookup_key(number).to_vec()
} else {
// other blocks are keyed by number + hash
::utils::number_and_hash_to_lookup_key(number, hash)
};
transaction.put(columns::HEADER, &lookup_key, &header.encode());
transaction.put(columns::HASH_LOOKUP, hash.as_ref(), &lookup_key);
let finalized = match leaf_state {
NewBlockState::Final => true,
_ => false,
@@ -374,10 +402,10 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
#[cfg(test)]
pub(crate) mod tests {
use client::cht;
use runtime_primitives::testing::{H256 as Hash, Header, Block as RawBlock};
use runtime_primitives::testing::{H256 as Hash, Header, Block as RawBlock, ExtrinsicWrapper};
use super::*;
type Block = RawBlock<u32>;
type Block = RawBlock<ExtrinsicWrapper<u32>>;
fn prepare_header(parent: &Hash, number: u64, extrinsics_root: Hash) -> Header {
Header {
@@ -512,6 +540,7 @@ pub(crate) mod tests {
prev_hash = insert_block(&db, &prev_hash, 1 + number, None);
}
assert_eq!(db.db.iter(columns::HEADER).count(), (1 + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::HASH_LOOKUP).count(), (1 + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::CHT).count(), 0);
// insert next SIZE blocks && ensure that nothing is pruned
@@ -519,12 +548,14 @@ pub(crate) mod tests {
prev_hash = insert_block(&db, &prev_hash, 1 + cht::SIZE + number, None);
}
assert_eq!(db.db.iter(columns::HEADER).count(), (1 + cht::SIZE + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::HASH_LOOKUP).count(), (1 + cht::SIZE + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::CHT).count(), 0);
// insert block #{2 * cht::SIZE + 1} && check that new CHT is created + headers of this CHT are pruned
// nothing is yet finalized, so nothing is pruned.
prev_hash = insert_block(&db, &prev_hash, 1 + cht::SIZE + cht::SIZE, None);
assert_eq!(db.db.iter(columns::HEADER).count(), (2 + cht::SIZE + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::HASH_LOOKUP).count(), (2 + cht::SIZE + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::CHT).count(), 0);
// now finalize the block.
@@ -533,6 +564,7 @@ pub(crate) mod tests {
}
db.finalize_header(BlockId::Hash(prev_hash)).unwrap();
assert_eq!(db.db.iter(columns::HEADER).count(), (1 + cht::SIZE + 1) as usize);
assert_eq!(db.db.iter(columns::HASH_LOOKUP).count(), (1 + cht::SIZE + 1) as usize);
assert_eq!(db.db.iter(columns::CHT).count(), 1);
assert!((0..cht::SIZE).all(|i| db.db.get(columns::HEADER, &number_to_lookup_key(1 + i)).unwrap().is_none()));
}
+48 -25
View File
@@ -67,10 +67,11 @@ pub struct Meta<N, H> {
}
/// A block lookup key: used for canonical lookup from block number to hash
pub type BlockLookupKey = [u8; 4];
pub type ShortBlockLookupKey = [u8; 4];
/// Convert block number into lookup key (LE representation).
pub fn number_to_lookup_key<N>(n: N) -> BlockLookupKey where N: As<u64> {
/// Convert block number into short lookup key (LE representation) for
/// blocks that are in the canonical chain.
pub fn number_to_lookup_key<N>(n: N) -> ShortBlockLookupKey where N: As<u64> {
let n: u64 = n.as_();
assert!(n & 0xffffffff00000000 == 0);
@@ -82,6 +83,49 @@ pub fn number_to_lookup_key<N>(n: N) -> BlockLookupKey where N: As<u64> {
]
}
/// Convert number and hash into long lookup key for blocks that are
/// not in the canonical chain.
pub fn number_and_hash_to_lookup_key<N, H>(number: N, hash: H) -> Vec<u8> where
N: As<u64>,
H: AsRef<[u8]>
{
let mut lookup_key = number_to_lookup_key(number).to_vec();
lookup_key.extend_from_slice(hash.as_ref());
lookup_key
}
/// Convert block lookup key into block number.
/// all block lookup keys start with the block number.
pub fn lookup_key_to_number<N>(key: &[u8]) -> client::error::Result<N> where N: As<u64> {
if key.len() < 4 {
return Err(client::error::ErrorKind::Backend("Invalid block key".into()).into());
}
Ok((key[0] as u64) << 24
| (key[1] as u64) << 16
| (key[2] as u64) << 8
| (key[3] as u64)).map(As::sa)
}
/// Convert block id to block lookup key.
/// block lookup key is the DB-key header, block and justification are stored under.
/// looks up lookup key by hash from DB as necessary.
pub fn block_id_to_lookup_key<Block>(
db: &KeyValueDB,
hash_lookup_col: Option<u32>,
id: BlockId<Block>
) -> Result<Option<Vec<u8>>, client::error::Error> where
Block: BlockT,
{
match id {
// numbers are solely looked up in canonical chain
BlockId::Number(n) => Ok(Some(number_to_lookup_key(n).to_vec())),
BlockId::Hash(h) => db.get(hash_lookup_col, h.as_ref()).map(|v|
v.map(|v| { v.into_vec() })
).map_err(db_err),
}
}
/// Maps database error to client error
pub fn db_err(err: io::Error) -> client::error::Error {
use std::error::Error;
@@ -113,33 +157,12 @@ pub fn open_database(config: &DatabaseSettings, col_meta: Option<u32>, db_type:
Ok(Arc::new(db))
}
/// Convert block id to block key, looking up canonical hash by number from DB as necessary.
pub fn read_id<Block>(db: &KeyValueDB, col_index: Option<u32>, id: BlockId<Block>) -> Result<Option<Block::Hash>, client::error::Error>
where
Block: BlockT,
{
match id {
BlockId::Hash(h) => Ok(Some(h)),
BlockId::Number(n) => db.get(col_index, &number_to_lookup_key(n)).map(|v|
v.map(|v| {
let mut h = <Block::Hash>::default();
{
let h = h.as_mut();
let len = ::std::cmp::min(v.len(), h.len());
h.as_mut().copy_from_slice(&v[..len]);
}
h
})
).map_err(db_err),
}
}
/// Read database column entry for the given block.
pub fn read_db<Block>(db: &KeyValueDB, col_index: Option<u32>, col: Option<u32>, id: BlockId<Block>) -> client::error::Result<Option<DBValue>>
where
Block: BlockT,
{
read_id(db, col_index, id).and_then(|key| match key {
block_id_to_lookup_key(db, col_index, id).and_then(|key| match key {
Some(key) => db.get(col, key.as_ref()).map_err(db_err),
None => Ok(None),
})
+2 -2
View File
@@ -89,7 +89,7 @@ pub fn build_proof<Header, Hasher, I>(
{
let transaction = build_pairs::<Header, I>(cht_size, cht_num, hashes)?
.into_iter()
.map(|(k, v)| (k, Some(v)))
.map(|(k, v)| (None, k, Some(v)))
.collect::<Vec<_>>();
let storage = InMemoryState::<Hasher>::default().update(transaction);
let (value, proof) = prove_read(storage, &encode_cht_key(block_num)).ok()?;
@@ -205,7 +205,7 @@ pub fn decode_cht_value(value: &[u8]) -> Option<H256> {
32 => Some(H256::from_slice(&value[0..32])),
_ => None,
}
}
#[cfg(test)]
+3 -3
View File
@@ -574,7 +574,7 @@ impl<B, E, Block> Client<B, E, Block> where
for tx in extrinsics {
let tx = api::TaggedTransactionQueue::validate_transaction(self, &id, &tx)?;
match tx {
TransactionValidity::Valid(_, _, mut provides, ..) => {
TransactionValidity::Valid { mut provides, .. } => {
tags.append(&mut provides);
},
// silently ignore invalid extrinsics,
@@ -1128,12 +1128,12 @@ impl<B, E, Block> api::BlockBuilder<Block> for Client<B, E, Block> where
self.call_api_at(at, "inherent_extrinsics", &(inherent))
}
fn check_inherents<InherentData: Encode + Decode>(
fn check_inherents<InherentData: Encode + Decode, InherentError: Encode + Decode>(
&self,
at: &BlockId<Block>,
block: &Block,
data: &InherentData
) -> Result<Result<(), api::BlockBuilderError>, Self::Error> {
) -> Result<Result<(), InherentError>, Self::Error> {
self.call_api_at(at, "check_inherents", &(block, data))
}
+19 -2
View File
@@ -201,7 +201,7 @@ impl<Block, S, F, H> StateBackend<H> for OnDemandState<Block, S, F>
S: BlockchainStorage<Block>,
F: Fetcher<Block>,
H: Hasher,
{
type Error = ClientError;
type Transaction = ();
@@ -227,15 +227,32 @@ impl<Block, S, F, H> StateBackend<H> for OnDemandState<Block, S, F>
.into_future().wait()
}
fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> ClientResult<Option<Vec<u8>>> {
Err(ClientErrorKind::NotAvailableOnLightClient.into())
}
fn for_keys_with_prefix<A: FnMut(&[u8])>(&self, _prefix: &[u8], _action: A) {
// whole state is not available on light node
}
fn for_keys_in_child_storage<A: FnMut(&[u8])>(&self, _storage_key: &[u8], _action: A) {
// whole state is not available on light node
}
fn storage_root<I>(&self, _delta: I) -> (H::Out, Self::Transaction)
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)> {
where
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
{
(H::Out::default(), ())
}
fn child_storage_root<I>(&self, _key: &[u8], _delta: I) -> (Vec<u8>, Self::Transaction)
where
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
{
(H::Out::default().as_ref().to_vec(), ())
}
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
// whole state is not available on light node
Vec::new()
+2 -3
View File
@@ -179,11 +179,10 @@ impl<Block: BlockT> StorageNotifications<Block> {
#[cfg(test)]
mod tests {
use runtime_primitives::testing::{H256 as Hash, Block as RawBlock};
use runtime_primitives::testing::{H256 as Hash, Block as RawBlock, ExtrinsicWrapper};
use super::*;
use futures::Stream;
#[cfg(test)]
impl From<Vec<(StorageKey, Option<StorageData>)>> for StorageChangeSet {
fn from(changes: Vec<(StorageKey, Option<StorageData>)>) -> Self {
@@ -201,7 +200,7 @@ mod tests {
}
}
type Block = RawBlock<Hash>;
type Block = RawBlock<ExtrinsicWrapper<Hash>>;
#[test]
fn triggering_change_should_notify_wildcard_listeners() {