Remove requirement on Hash = H256, make Proposer return StorageChanges and Proof (#3860)

* Extend `Proposer` to optionally generate a proof of the proposal

* Something

* Refactor sr-api to not depend on client anymore

* Fix benches

* Apply suggestions from code review

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Apply suggestions from code review

* Introduce new `into_storage_changes` function

* Switch to runtime api for `execute_block` and don't require `H256`
anywhere in the code

* Put the `StorageChanges` into the `Proposal`

* Move the runtime api error to its own trait

* Adds `StorageTransactionCache` to the runtime api

This requires that we add `type NodeBlock = ` to the
`impl_runtime_apis!` macro to work around some bugs in rustc :(

* Remove `type NodeBlock` and switch to a "better" hack

* Start using the transaction cache from the runtime api

* Make it compile

* Move `InMemory` to its own file

* Make all tests work again

* Return block, storage_changes and proof from Blockbuilder::bake()

* Make sure that we use/set `storage_changes` when possible

* Add test

* Fix deadlock

* Remove accidentally added folders

* Introduce `RecordProof` as argument type to be more explicit

* Update client/src/client.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Update primitives/state-machine/src/ext.rs

Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Integrates review feedback

* Remove `unsafe` usage

* Update client/block-builder/src/lib.rs

Co-Authored-By: Benjamin Kampmann <ben@gnunicorn.org>

* Update client/src/call_executor.rs

* Bump versions

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: Benjamin Kampmann <ben.kampmann@googlemail.com>
This commit is contained in:
Bastian Köcher
2020-01-10 10:48:32 +01:00
committed by GitHub
parent 74d6e660c6
commit fd6b29dd2c
140 changed files with 4860 additions and 3339 deletions
+73 -84
View File
@@ -24,11 +24,13 @@ use sp_core::offchain::storage::{
InMemOffchainStorage as OffchainStorage
};
use sp_runtime::generic::{BlockId, DigestItem};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor, HasherFor};
use sp_runtime::{Justification, Storage};
use sp_state_machine::backend::{Backend as StateBackend, InMemory};
use sp_state_machine::{self, InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId, ChangesTrieTransaction};
use hash_db::{Hasher, Prefix};
use sp_state_machine::{
InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId, ChangesTrieTransaction,
InMemoryBackend, Backend as StateBackend,
};
use hash_db::Prefix;
use sp_trie::MemoryDB;
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};
@@ -459,25 +461,21 @@ impl<Block: BlockT> sc_client_api::light::Storage<Block> for Blockchain<Block>
}
/// In-memory operation.
pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
pub struct BlockImportOperation<Block: BlockT> {
pending_block: Option<PendingBlock<Block>>,
pending_cache: HashMap<CacheKeyId, Vec<u8>>,
old_state: InMemory<H>,
new_state: Option<InMemory<H>>,
changes_trie_update: Option<MemoryDB<H>>,
old_state: InMemoryBackend<HasherFor<Block>>,
new_state: Option<InMemoryBackend<HasherFor<Block>>>,
changes_trie_update: Option<MemoryDB<HasherFor<Block>>>,
aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
set_head: Option<BlockId<Block>>,
}
impl<Block, H> backend::BlockImportOperation<Block, H> for BlockImportOperation<Block, H>
where
Block: BlockT,
H: Hasher<Out=Block::Hash>,
H::Out: Ord,
impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block> where
Block::Hash: Ord,
{
type State = InMemory<H>;
type State = InMemoryBackend<HasherFor<Block>>;
fn state(&self) -> sp_blockchain::Result<Option<&Self::State>> {
Ok(Some(&self.old_state))
@@ -502,17 +500,23 @@ where
self.pending_cache = cache;
}
fn update_db_storage(&mut self, update: <InMemory<H> as StateBackend<H>>::Transaction) -> sp_blockchain::Result<()> {
fn update_db_storage(
&mut self,
update: <InMemoryBackend<HasherFor<Block>> as StateBackend<HasherFor<Block>>>::Transaction,
) -> sp_blockchain::Result<()> {
self.new_state = Some(self.old_state.update(update));
Ok(())
}
fn update_changes_trie(&mut self, update: ChangesTrieTransaction<H, NumberFor<Block>>) -> sp_blockchain::Result<()> {
fn update_changes_trie(
&mut self,
update: ChangesTrieTransaction<HasherFor<Block>, NumberFor<Block>>,
) -> sp_blockchain::Result<()> {
self.changes_trie_update = Some(update.0);
Ok(())
}
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<H::Out> {
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash> {
check_genesis_storage(&storage)?;
let child_delta = storage.children.into_iter()
@@ -524,7 +528,7 @@ where
child_delta
);
self.new_state = Some(InMemory::from(transaction));
self.new_state = Some(InMemoryBackend::from(transaction));
Ok(root)
}
@@ -543,7 +547,11 @@ where
Ok(())
}
fn mark_finalized(&mut self, block: BlockId<Block>, justification: Option<Justification>) -> sp_blockchain::Result<()> {
fn mark_finalized(
&mut self,
block: BlockId<Block>,
justification: Option<Justification>,
) -> sp_blockchain::Result<()> {
self.finalized_blocks.push((block, justification));
Ok(())
}
@@ -559,26 +567,16 @@ where
///
/// > **Warning**: Doesn't support all the features necessary for a proper database. Only use this
/// > struct for testing purposes. Do **NOT** use in production.
pub struct Backend<Block, H>
where
Block: BlockT,
H: Hasher<Out=Block::Hash>,
H::Out: Ord,
{
states: RwLock<HashMap<Block::Hash, InMemory<H>>>,
changes_trie_storage: ChangesTrieStorage<Block, H>,
pub struct Backend<Block: BlockT> where Block::Hash: Ord {
states: RwLock<HashMap<Block::Hash, InMemoryBackend<HasherFor<Block>>>>,
changes_trie_storage: ChangesTrieStorage<Block>,
blockchain: Blockchain<Block>,
import_lock: RwLock<()>,
}
impl<Block, H> Backend<Block, H>
where
Block: BlockT,
H: Hasher<Out=Block::Hash>,
H::Out: Ord,
{
impl<Block: BlockT> Backend<Block> where Block::Hash: Ord {
/// Create a new instance of in-mem backend.
pub fn new() -> Backend<Block, H> {
pub fn new() -> Self {
Backend {
states: RwLock::new(HashMap::new()),
changes_trie_storage: ChangesTrieStorage(InMemoryChangesTrieStorage::new()),
@@ -588,12 +586,7 @@ where
}
}
impl<Block, H> backend::AuxStore for Backend<Block, H>
where
Block: BlockT,
H: Hasher<Out=Block::Hash>,
H::Out: Ord,
{
impl<Block: BlockT> backend::AuxStore for Backend<Block> where Block::Hash: Ord {
fn insert_aux<
'a,
'b: 'a,
@@ -609,16 +602,11 @@ where
}
}
impl<Block, H> backend::Backend<Block, H> for Backend<Block, H>
where
Block: BlockT,
H: Hasher<Out=Block::Hash>,
H::Out: Ord,
{
type BlockImportOperation = BlockImportOperation<Block, H>;
impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash: Ord {
type BlockImportOperation = BlockImportOperation<Block>;
type Blockchain = Blockchain<Block>;
type State = InMemory<H>;
type ChangesTrieStorage = ChangesTrieStorage<Block, H>;
type State = InMemoryBackend<HasherFor<Block>>;
type ChangesTrieStorage = ChangesTrieStorage<Block>;
type OffchainStorage = OffchainStorage;
fn begin_operation(&self) -> sp_blockchain::Result<Self::BlockImportOperation> {
@@ -635,7 +623,11 @@ where
})
}
fn begin_state_operation(&self, operation: &mut Self::BlockImportOperation, block: BlockId<Block>) -> sp_blockchain::Result<()> {
fn begin_state_operation(
&self,
operation: &mut Self::BlockImportOperation,
block: BlockId<Block>,
) -> sp_blockchain::Result<()> {
operation.old_state = self.state_at(block)?;
Ok(())
}
@@ -680,7 +672,11 @@ where
Ok(())
}
fn finalize_block(&self, block: BlockId<Block>, justification: Option<Justification>) -> sp_blockchain::Result<()> {
fn finalize_block(
&self,
block: BlockId<Block>,
justification: Option<Justification>,
) -> sp_blockchain::Result<()> {
self.blockchain.finalize_header(block, justification)
}
@@ -727,19 +723,9 @@ where
}
}
impl<Block, H> backend::LocalBackend<Block, H> for Backend<Block, H>
where
Block: BlockT,
H: Hasher<Out=Block::Hash>,
H::Out: Ord,
{}
impl<Block: BlockT> backend::LocalBackend<Block> for Backend<Block> where Block::Hash: Ord {}
impl<Block, H> backend::RemoteBackend<Block, H> for Backend<Block, H>
where
Block: BlockT,
H: Hasher<Out=Block::Hash>,
H::Out: Ord,
{
impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block::Hash: Ord {
fn is_local_state_available(&self, block: &BlockId<Block>) -> bool {
self.blockchain.expect_block_number_from_id(block)
.map(|num| num.is_zero())
@@ -752,8 +738,11 @@ where
}
/// Prunable in-memory changes trie storage.
pub struct ChangesTrieStorage<Block: BlockT, H: Hasher>(InMemoryChangesTrieStorage<H, NumberFor<Block>>);
impl<Block: BlockT, H: Hasher> backend::PrunableStateChangesTrieStorage<Block, H> for ChangesTrieStorage<Block, H> {
pub struct ChangesTrieStorage<Block: BlockT>(
InMemoryChangesTrieStorage<HasherFor<Block>, NumberFor<Block>>
);
impl<Block: BlockT> backend::PrunableStateChangesTrieStorage<Block> for ChangesTrieStorage<Block> {
fn oldest_changes_trie_block(
&self,
_config: &ChangesTrieConfiguration,
@@ -763,45 +752,47 @@ impl<Block: BlockT, H: Hasher> backend::PrunableStateChangesTrieStorage<Block, H
}
}
impl<Block, H> sp_state_machine::ChangesTrieRootsStorage<H, NumberFor<Block>> for ChangesTrieStorage<Block, H>
where
Block: BlockT,
H: Hasher,
impl<Block: BlockT> sp_state_machine::ChangesTrieRootsStorage<HasherFor<Block>, NumberFor<Block>> for
ChangesTrieStorage<Block>
{
fn build_anchor(
&self,
_hash: H::Out,
) -> Result<sp_state_machine::ChangesTrieAnchorBlockId<H::Out, NumberFor<Block>>, String> {
_hash: Block::Hash,
) -> Result<sp_state_machine::ChangesTrieAnchorBlockId<Block::Hash, NumberFor<Block>>, String> {
Err("Dummy implementation".into())
}
fn root(
&self,
_anchor: &ChangesTrieAnchorBlockId<H::Out, NumberFor<Block>>,
_anchor: &ChangesTrieAnchorBlockId<Block::Hash, NumberFor<Block>>,
_block: NumberFor<Block>,
) -> Result<Option<H::Out>, String> {
) -> Result<Option<Block::Hash>, String> {
Err("Dummy implementation".into())
}
}
impl<Block, H> sp_state_machine::ChangesTrieStorage<H, NumberFor<Block>> for ChangesTrieStorage<Block, H>
where
Block: BlockT,
H: Hasher,
impl<Block: BlockT> sp_state_machine::ChangesTrieStorage<HasherFor<Block>, NumberFor<Block>> for
ChangesTrieStorage<Block>
{
fn as_roots_storage(&self) -> &dyn sp_state_machine::ChangesTrieRootsStorage<H, NumberFor<Block>> {
fn as_roots_storage(&self)
-> &dyn sp_state_machine::ChangesTrieRootsStorage<HasherFor<Block>, NumberFor<Block>>
{
self
}
fn with_cached_changed_keys(
&self,
_root: &H::Out,
_root: &Block::Hash,
_functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
) -> bool {
false
}
fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<sp_state_machine::DBValue>, String> {
fn get(
&self,
key: &Block::Hash,
prefix: Prefix,
) -> Result<Option<sp_state_machine::DBValue>, String> {
self.0.get(key, prefix)
}
}
@@ -823,10 +814,8 @@ pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
mod tests {
use sp_core::offchain::{OffchainStorage, storage::InMemOffchainStorage};
use std::sync::Arc;
use substrate_test_runtime_client;
use sp_core::Blake2Hasher;
type TestBackend = substrate_test_runtime_client::sc_client::in_mem::Backend<substrate_test_runtime_client::runtime::Block, Blake2Hasher>;
type TestBackend = substrate_test_runtime_client::sc_client::in_mem::Backend<substrate_test_runtime_client::runtime::Block>;
#[test]
fn test_leaves_with_complex_block_tree() {