diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 60196e4a322bb..93a5352fd7b51 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -64,7 +64,7 @@ use hash_db::Hasher; use kvdb::{KeyValueDB, DBTransaction}; use trie::MemoryDB; use parking_lot::RwLock; -use primitives::{H256, AuthorityId, Blake2Hasher, ChangesTrieConfiguration}; +use primitives::{H256, AuthorityId, Blake2Hasher, ChangesTrieConfiguration, convert_hash}; use primitives::storage::well_known_keys; use runtime_primitives::{generic::BlockId, Justification, StorageMap, ChildrenStorageMap}; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor, Zero, Digest, DigestItem}; @@ -145,7 +145,7 @@ impl<'a> state_db::MetaDb for StateMetaDb<'a> { /// Block database pub struct BlockchainDb { db: Arc, - meta: RwLock, Block::Hash>>, + meta: Arc, Block::Hash>>>, leaves: RwLock>>, } @@ -156,7 +156,7 @@ impl BlockchainDb { Ok(BlockchainDb { db, leaves: RwLock::new(leaves), - meta: RwLock::new(meta), + meta: Arc::new(RwLock::new(meta)), }) } @@ -387,6 +387,7 @@ impl state_machine::Storage for DbGenesisStorage { pub struct DbChangesTrieStorage { db: Arc, + meta: Arc, Block::Hash>>>, min_blocks_to_keep: Option, _phantom: ::std::marker::PhantomData, } @@ -400,7 +401,7 @@ impl DbChangesTrieStorage { } /// Prune obsolete changes tries. - pub fn prune(&self, config: Option, tx: &mut DBTransaction, block: NumberFor) { + pub fn prune(&self, config: Option, tx: &mut DBTransaction, block_hash: Block::Hash, block_num: NumberFor) { // never prune on archive nodes let min_blocks_to_keep = match self.min_blocks_to_keep { Some(min_blocks_to_keep) => min_blocks_to_keep, @@ -418,23 +419,54 @@ impl DbChangesTrieStorage { &config, &*self, min_blocks_to_keep, - block.as_(), + &state_machine::ChangesTrieAnchorBlockId { + hash: convert_hash(&block_hash), + number: block_num.as_(), + }, |node| tx.delete(columns::CHANGES_TRIE, node.as_ref())); } } impl state_machine::ChangesTrieRootsStorage for DbChangesTrieStorage { - fn root(&self, block: u64) -> Result, String> { - Ok(read_db::(&*self.db, columns::HASH_LOOKUP, columns::HEADER, BlockId::Number(As::sa(block))) - .map_err(|err| format!("{}", err)) - .and_then(|header| match header { - Some(header) => Block::Header::decode(&mut &header[..]) - .ok_or_else(|| format!("Failed to parse header of block {}", block)) - .map(Some), - None => Ok(None) - })? - .and_then(|header| header.digest().log(DigestItem::as_changes_trie_root) - .map(|root| H256::from_slice(root.as_ref())))) + fn root(&self, anchor: &state_machine::ChangesTrieAnchorBlockId, block: u64) -> Result, String> { + // check API requirement + assert!(block <= anchor.number, "API requirement"); + + // we need to get hash of the block to resolve changes trie root + let block_id = if block <= self.meta.read().finalized_number.as_() { + // if block is finalized, we could just read canonical hash + BlockId::Number(As::sa(block)) + } else { + // the block is not finalized + let mut current_num = anchor.number; + let mut current_hash: Block::Hash = convert_hash(&anchor.hash); + let maybe_anchor_header: Block::Header = ::utils::require_header::( + &*self.db, columns::HASH_LOOKUP, columns::HEADER, BlockId::Number(As::sa(current_num)) + ).map_err(|e| e.to_string())?; + if maybe_anchor_header.hash() == current_hash { + // if anchor is canonicalized, then the block is also canonicalized + BlockId::Number(As::sa(block)) + } else { + // else (block is not finalized + anchor is not canonicalized): + // => we should find the required block hash by traversing + // back from the anchor to the block with given number + while current_num != block { + let current_header: Block::Header = ::utils::require_header::( + &*self.db, columns::HASH_LOOKUP, columns::HEADER, BlockId::Hash(current_hash) + ).map_err(|e| e.to_string())?; + + current_hash = *current_header.parent_hash(); + current_num = current_num - 1; + } + + BlockId::Hash(current_hash) + } + }; + + Ok(::utils::require_header::(&*self.db, columns::HASH_LOOKUP, columns::HEADER, block_id) + .map_err(|e| e.to_string())? + .digest().log(DigestItem::as_changes_trie_root) + .map(|root| H256::from_slice(root.as_ref()))) } } @@ -480,6 +512,7 @@ impl Backend { fn from_kvdb(db: Arc, pruning: PruningMode, canonicalization_delay: u64) -> Result { let is_archive_pruning = pruning.is_archive(); let blockchain = BlockchainDb::new(db.clone())?; + let meta = blockchain.meta.clone(); let map_e = |e: state_db::Error| ::client::error::Error::from(format!("State database error: {:?}", e)); let state_db: StateDb = StateDb::new(pruning, &StateMetaDb(&*db)).map_err(map_e)?; let storage_db = StorageDb { @@ -488,6 +521,7 @@ impl Backend { }; let changes_tries_storage = DbChangesTrieStorage { db, + meta, min_blocks_to_keep: if is_archive_pruning { None } else { Some(MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR) }, _phantom: Default::default(), }; @@ -567,7 +601,7 @@ impl Backend { let changes_trie_config: Option = self.state_at(BlockId::Hash(parent_hash))? .storage(well_known_keys::CHANGES_TRIE_CONFIG)? .and_then(|v| Decode::decode(&mut &*v)); - self.changes_tries_storage.prune(changes_trie_config, transaction, f_num); + self.changes_tries_storage.prune(changes_trie_config, transaction, f_hash, f_num); } Ok(()) @@ -1191,10 +1225,13 @@ mod tests { #[test] fn changes_trie_storage_works() { let backend = Backend::::new_test(1000, 100); + backend.changes_tries_storage.meta.write().finalized_number = 1000; + let check_changes = |backend: &Backend, block: u64, changes: Vec<(Vec, Vec)>| { let (changes_root, mut changes_trie_update) = prepare_changes(changes); - assert_eq!(backend.changes_tries_storage.root(block), Ok(Some(changes_root))); + let anchor = state_machine::ChangesTrieAnchorBlockId { hash: Default::default(), number: block }; + assert_eq!(backend.changes_tries_storage.root(&anchor, block), Ok(Some(changes_root))); for (key, (val, _)) in changes_trie_update.drain() { assert_eq!(backend.changes_trie_storage().unwrap().get(&key), Ok(Some(val))); @@ -1218,9 +1255,66 @@ mod tests { check_changes(&backend, 2, changes2); } + #[test] + fn changes_trie_storage_works_with_forks() { + let backend = Backend::::new_test(1000, 100); + + let changes0 = vec![(b"k0".to_vec(), b"v0".to_vec())]; + let changes1 = vec![(b"k1".to_vec(), b"v1".to_vec())]; + let changes2 = vec![(b"k2".to_vec(), b"v2".to_vec())]; + let block0 = insert_header(&backend, 0, Default::default(), changes0.clone(), Default::default()); + let block1 = insert_header(&backend, 1, block0, changes1.clone(), Default::default()); + let block2 = insert_header(&backend, 2, block1, changes2.clone(), Default::default()); + + let changes2_1_0 = vec![(b"k3".to_vec(), b"v3".to_vec())]; + let changes2_1_1 = vec![(b"k4".to_vec(), b"v4".to_vec())]; + let block2_1_0 = insert_header(&backend, 3, block2, changes2_1_0.clone(), Default::default()); + let block2_1_1 = insert_header(&backend, 4, block2_1_0, changes2_1_1.clone(), Default::default()); + + let changes2_2_0 = vec![(b"k5".to_vec(), b"v5".to_vec())]; + let changes2_2_1 = vec![(b"k6".to_vec(), b"v6".to_vec())]; + let block2_2_0 = insert_header(&backend, 3, block2, changes2_2_0.clone(), Default::default()); + let block2_2_1 = insert_header(&backend, 4, block2_2_0, changes2_2_1.clone(), Default::default()); + + // finalize block1 + backend.changes_tries_storage.meta.write().finalized_number = 1; + + // branch1: when asking for finalized block hash + let (changes1_root, _) = prepare_changes(changes1); + let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block2_1_1, number: 4 }; + assert_eq!(backend.changes_tries_storage.root(&anchor, 1), Ok(Some(changes1_root))); + + // branch2: when asking for finalized block hash + let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block2_2_1, number: 4 }; + assert_eq!(backend.changes_tries_storage.root(&anchor, 1), Ok(Some(changes1_root))); + + // branch1: when asking for non-finalized block hash (search by traversal) + let (changes2_1_0_root, _) = prepare_changes(changes2_1_0); + let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block2_1_1, number: 4 }; + assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_1_0_root))); + + // branch2: when asking for non-finalized block hash (search using canonicalized hint) + let (changes2_2_0_root, _) = prepare_changes(changes2_2_0); + let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block2_2_1, number: 4 }; + assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root))); + + // finalize first block of branch2 (block2_2_0) + backend.changes_tries_storage.meta.write().finalized_number = 3; + + // branch2: when asking for finalized block of this branch + assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root))); + + // branch1: when asking for finalized block of other branch + // => result is incorrect (returned for the block of branch1), but this is expected, + // because the other fork is abandoned (forked before finalized header) + let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block2_1_1, number: 4 }; + assert_eq!(backend.changes_tries_storage.root(&anchor, 3), Ok(Some(changes2_2_0_root))); + } + #[test] fn changes_tries_are_pruned_on_finalization() { let mut backend = Backend::::new_test(1000, 100); + backend.changes_tries_storage.meta.write().finalized_number = 1000; backend.changes_tries_storage.min_blocks_to_keep = Some(8); let config = ChangesTrieConfiguration { digest_interval: 2, @@ -1243,26 +1337,27 @@ mod tests { let _ = insert_header(&backend, 12, block11, vec![(b"key_at_12".to_vec(), b"val_at_12".to_vec())], Default::default()); // check that roots of all tries are in the columns::CHANGES_TRIE + let anchor = state_machine::ChangesTrieAnchorBlockId { hash: Default::default(), number: 100 }; fn read_changes_trie_root(backend: &Backend, num: u64) -> H256 { backend.blockchain().header(BlockId::Number(num)).unwrap().unwrap().digest().logs().iter() .find(|i| i.as_changes_trie_root().is_some()).unwrap().as_changes_trie_root().unwrap().clone() } - let root1 = read_changes_trie_root(&backend, 1); assert_eq!(backend.changes_tries_storage.root(1).unwrap(), Some(root1)); - let root2 = read_changes_trie_root(&backend, 2); assert_eq!(backend.changes_tries_storage.root(2).unwrap(), Some(root2)); - let root3 = read_changes_trie_root(&backend, 3); assert_eq!(backend.changes_tries_storage.root(3).unwrap(), Some(root3)); - let root4 = read_changes_trie_root(&backend, 4); assert_eq!(backend.changes_tries_storage.root(4).unwrap(), Some(root4)); - let root5 = read_changes_trie_root(&backend, 5); assert_eq!(backend.changes_tries_storage.root(5).unwrap(), Some(root5)); - let root6 = read_changes_trie_root(&backend, 6); assert_eq!(backend.changes_tries_storage.root(6).unwrap(), Some(root6)); - let root7 = read_changes_trie_root(&backend, 7); assert_eq!(backend.changes_tries_storage.root(7).unwrap(), Some(root7)); - let root8 = read_changes_trie_root(&backend, 8); assert_eq!(backend.changes_tries_storage.root(8).unwrap(), Some(root8)); - let root9 = read_changes_trie_root(&backend, 9); assert_eq!(backend.changes_tries_storage.root(9).unwrap(), Some(root9)); - let root10 = read_changes_trie_root(&backend, 10); assert_eq!(backend.changes_tries_storage.root(10).unwrap(), Some(root10)); - let root11 = read_changes_trie_root(&backend, 11); assert_eq!(backend.changes_tries_storage.root(11).unwrap(), Some(root11)); - let root12 = read_changes_trie_root(&backend, 12); assert_eq!(backend.changes_tries_storage.root(12).unwrap(), Some(root12)); + let root1 = read_changes_trie_root(&backend, 1); assert_eq!(backend.changes_tries_storage.root(&anchor, 1).unwrap(), Some(root1)); + let root2 = read_changes_trie_root(&backend, 2); assert_eq!(backend.changes_tries_storage.root(&anchor, 2).unwrap(), Some(root2)); + let root3 = read_changes_trie_root(&backend, 3); assert_eq!(backend.changes_tries_storage.root(&anchor, 3).unwrap(), Some(root3)); + let root4 = read_changes_trie_root(&backend, 4); assert_eq!(backend.changes_tries_storage.root(&anchor, 4).unwrap(), Some(root4)); + let root5 = read_changes_trie_root(&backend, 5); assert_eq!(backend.changes_tries_storage.root(&anchor, 5).unwrap(), Some(root5)); + let root6 = read_changes_trie_root(&backend, 6); assert_eq!(backend.changes_tries_storage.root(&anchor, 6).unwrap(), Some(root6)); + let root7 = read_changes_trie_root(&backend, 7); assert_eq!(backend.changes_tries_storage.root(&anchor, 7).unwrap(), Some(root7)); + let root8 = read_changes_trie_root(&backend, 8); assert_eq!(backend.changes_tries_storage.root(&anchor, 8).unwrap(), Some(root8)); + let root9 = read_changes_trie_root(&backend, 9); assert_eq!(backend.changes_tries_storage.root(&anchor, 9).unwrap(), Some(root9)); + let root10 = read_changes_trie_root(&backend, 10); assert_eq!(backend.changes_tries_storage.root(&anchor, 10).unwrap(), Some(root10)); + let root11 = read_changes_trie_root(&backend, 11); assert_eq!(backend.changes_tries_storage.root(&anchor, 11).unwrap(), Some(root11)); + let root12 = read_changes_trie_root(&backend, 12); assert_eq!(backend.changes_tries_storage.root(&anchor, 12).unwrap(), Some(root12)); // now simulate finalization of block#12, causing prune of tries at #1..#4 let mut tx = DBTransaction::new(); - backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, 12); + backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, Default::default(), 12); backend.storage.db.write(tx).unwrap(); assert!(backend.changes_tries_storage.get(&root1).unwrap().is_none()); assert!(backend.changes_tries_storage.get(&root2).unwrap().is_none()); @@ -1275,7 +1370,7 @@ mod tests { // now simulate finalization of block#16, causing prune of tries at #5..#8 let mut tx = DBTransaction::new(); - backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, 16); + backend.changes_tries_storage.prune(Some(config.clone()), &mut tx, Default::default(), 16); backend.storage.db.write(tx).unwrap(); assert!(backend.changes_tries_storage.get(&root5).unwrap().is_none()); assert!(backend.changes_tries_storage.get(&root6).unwrap().is_none()); @@ -1286,7 +1381,7 @@ mod tests { // => no changes tries are pruned, because we never prune in archive mode backend.changes_tries_storage.min_blocks_to_keep = None; let mut tx = DBTransaction::new(); - backend.changes_tries_storage.prune(Some(config), &mut tx, 20); + backend.changes_tries_storage.prune(Some(config), &mut tx, Default::default(), 20); backend.storage.db.write(tx).unwrap(); assert!(backend.changes_tries_storage.get(&root9).unwrap().is_some()); assert!(backend.changes_tries_storage.get(&root10).unwrap().is_some()); diff --git a/core/client/db/src/utils.rs b/core/client/db/src/utils.rs index f7b81845e8e7c..5caebd7e72ec5 100644 --- a/core/client/db/src/utils.rs +++ b/core/client/db/src/utils.rs @@ -187,6 +187,17 @@ pub fn read_header( } } +/// Required header from the database. +pub fn require_header( + db: &KeyValueDB, + col_index: Option, + col: Option, + id: BlockId, +) -> client::error::Result { + read_header(db, col_index, col, id) + .and_then(|header| header.ok_or_else(|| client::error::ErrorKind::UnknownBlock(format!("{}", id)).into())) +} + /// Read meta from the database. pub fn read_meta(db: &KeyValueDB, col_meta: Option, col_header: Option) -> Result< Meta<<::Header as HeaderT>::Number, Block::Hash>, diff --git a/core/client/src/cht.rs b/core/client/src/cht.rs index fd8e07c3dd4bc..39e1aaa95bd25 100644 --- a/core/client/src/cht.rs +++ b/core/client/src/cht.rs @@ -27,7 +27,7 @@ use hash_db; use heapsize::HeapSizeOf; use trie; -use primitives::H256; +use primitives::{H256, convert_hash}; use runtime_primitives::traits::{As, Header as HeaderT, SimpleArithmetic, One}; use state_machine::backend::InMemory as InMemoryState; use state_machine::{prove_read, read_proof_check}; @@ -113,8 +113,7 @@ pub fn check_proof( Hasher: hash_db::Hasher, Hasher::Out: Ord + HeapSizeOf, { - let mut root: Hasher::Out = Default::default(); - root.as_mut().copy_from_slice(local_root.as_ref()); + let root: Hasher::Out = convert_hash(&local_root); let local_cht_key = encode_cht_key(local_number); let local_cht_value = read_proof_check::(root, remote_proof, &local_cht_key).map_err(|e| ClientError::from(e))?; diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 1279bc486a314..f1d1549185cd1 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -30,14 +30,14 @@ use consensus::{ImportBlock, ImportResult, BlockOrigin}; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash}; use runtime_primitives::{ApplyResult, BuildStorage}; use runtime_api as api; -use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration}; +use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash}; use primitives::storage::{StorageKey, StorageData}; use primitives::storage::well_known_keys; use codec::{Encode, Decode}; use state_machine::{ Backend as StateBackend, CodeExecutor, - ExecutionStrategy, ExecutionManager, prove_read, - key_changes, key_changes_proof, OverlayedChanges + ExecutionStrategy, ExecutionManager, ChangesTrieAnchorBlockId, + prove_read, key_changes, key_changes_proof, OverlayedChanges }; use backend::{self, BlockImportOperation}; @@ -355,7 +355,10 @@ impl Client where config, storage, self.require_block_number_from_id(&BlockId::Hash(first))?.as_(), - self.require_block_number_from_id(&BlockId::Hash(last))?.as_(), + &ChangesTrieAnchorBlockId { + hash: convert_hash(&last), + number: self.require_block_number_from_id(&BlockId::Hash(last))?.as_(), + }, self.backend.blockchain().info()?.best_number.as_(), key) .map_err(|err| error::ErrorKind::ChangesTrieAccessFailed(err).into()) @@ -388,7 +391,10 @@ impl Client where config, storage, self.require_block_number_from_id(&BlockId::Hash(first))?.as_(), - self.require_block_number_from_id(&BlockId::Hash(last))?.as_(), + &ChangesTrieAnchorBlockId { + hash: convert_hash(&last), + number: self.require_block_number_from_id(&BlockId::Hash(last))?.as_(), + }, max_number.as_(), key) .map_err(|err| error::ErrorKind::ChangesTrieAccessFailed(err).into()) diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index d52883db64f01..732b783b73adc 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -21,6 +21,7 @@ use std::marker::PhantomData; use std::sync::Arc; use futures::{IntoFuture, Future}; +use primitives::convert_hash; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; use state_machine::{Backend as StateBackend, CodeExecutor, OverlayedChanges, @@ -136,8 +137,7 @@ pub fn check_execution_proof( { let local_state_root = request.header.state_root(); - let mut root: H::Out = Default::default(); - root.as_mut().copy_from_slice(local_state_root.as_ref()); + let root: H::Out = convert_hash(&local_state_root); let mut changes = OverlayedChanges::default(); let local_result = execution_proof_check::( diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index 95e02b91f9f65..b75b74a0a976e 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -21,10 +21,10 @@ use futures::IntoFuture; use hash_db::Hasher; use heapsize::HeapSizeOf; -use primitives::ChangesTrieConfiguration; +use primitives::{ChangesTrieConfiguration, convert_hash}; use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT, NumberFor}; -use state_machine::{CodeExecutor, ChangesTrieRootsStorage, read_proof_check, - key_changes_proof_check}; +use state_machine::{CodeExecutor, ChangesTrieRootsStorage, ChangesTrieAnchorBlockId, + read_proof_check, key_changes_proof_check}; use call_executor::CallResult; use cht; @@ -192,9 +192,8 @@ impl FetchChecker for LightDataChecker request: &RemoteReadRequest, remote_proof: Vec> ) -> ClientResult>> { - let mut root: H::Out = Default::default(); - root.as_mut().copy_from_slice(request.header.state_root().as_ref()); - read_proof_check::(root, remote_proof, &request.key).map_err(Into::into) + read_proof_check::(convert_hash(request.header.state_root()), remote_proof, &request.key) + .map_err(Into::into) } fn check_execution_proof( @@ -229,7 +228,10 @@ impl FetchChecker for LightDataChecker }, remote_proof, first_number, - request.last_block.0.as_(), + &ChangesTrieAnchorBlockId { + hash: convert_hash(&request.last_block.1), + number: request.last_block.0.as_(), + }, remote_max.as_(), &request.key) .map(|pairs| pairs.into_iter().map(|(b, x)| (As::sa(b), x)).collect()) @@ -248,15 +250,12 @@ impl<'a, H, Hash> ChangesTrieRootsStorage for RootsStorage<'a, Hash> H: Hasher, Hash: 'a + Send + Sync + Clone + AsRef<[u8]>, { - fn root(&self, block: u64) -> Result, String> { + fn root(&self, _anchor: &ChangesTrieAnchorBlockId, block: u64) -> Result, String> { + // we can't ask for roots from parallel forks here => ignore anchor Ok(block.checked_sub(self.first) .and_then(|index| self.roots.get(index as usize)) .cloned() - .map(|root| { - let mut hasher_root: H::Out = Default::default(); - hasher_root.as_mut().copy_from_slice(root.as_ref()); - hasher_root - })) + .map(|root| convert_hash(&root))) } } diff --git a/core/executor/src/wasm_executor.rs b/core/executor/src/wasm_executor.rs index 90d6db600151a..7480b6195014a 100644 --- a/core/executor/src/wasm_executor.rs +++ b/core/executor/src/wasm_executor.rs @@ -29,7 +29,7 @@ use wasm_utils::UserError; use primitives::{blake2_256, twox_128, twox_256, ed25519}; use primitives::hexdisplay::HexDisplay; use primitives::sandbox as sandbox_primitives; -use primitives::Blake2Hasher; +use primitives::{H256, Blake2Hasher}; use trie::ordered_trie_root; use sandbox; @@ -412,8 +412,15 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(0) } }, - ext_storage_changes_root(block: u64, result: *mut u8) -> u32 => { - let r = this.ext.storage_changes_root(block); + ext_storage_changes_root(parent_hash_data: *const u8, parent_hash_len: u32, parent_number: u64, result: *mut u8) -> u32 => { + let mut parent_hash = H256::default(); + if parent_hash_len != parent_hash.as_ref().len() as u32 { + return Err(UserError("Invalid parent_hash_len in ext_storage_changes_root").into()); + } + let raw_parent_hash = this.memory.get(parent_hash_data, parent_hash_len as usize) + .map_err(|_| UserError("Invalid attempt to get parent_hash in ext_storage_changes_root"))?; + parent_hash.as_mut().copy_from_slice(&raw_parent_hash[..]); + let r = this.ext.storage_changes_root(parent_hash, parent_number); if let Some(ref r) = r { this.memory.set(result, &r[..]).map_err(|_| UserError("Invalid attempt to set memory in ext_storage_changes_root"))?; } diff --git a/core/primitives/src/hash.rs b/core/primitives/src/hash.rs index 5733a738c9b93..8d04df26844db 100644 --- a/core/primitives/src/hash.rs +++ b/core/primitives/src/hash.rs @@ -76,6 +76,16 @@ impl_rest!(H160, 20); impl_rest!(H256, 32); impl_rest!(H512, 64); +/// Hash conversion. Used to convert between unbound associated hash types in traits, +/// implemented by the same hash type. +/// Panics if used to convert between different hash types. +pub fn convert_hash, H2: AsRef<[u8]>>(src: &H2) -> H1 { + let mut dest = H1::default(); + assert_eq!(dest.as_mut().len(), src.as_ref().len()); + dest.as_mut().copy_from_slice(src.as_ref()); + dest +} + #[cfg(test)] mod tests { use super::*; diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index c5ddcb130dbc8..20f044a872725 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -107,7 +107,7 @@ mod changes_trie; #[cfg(test)] mod tests; -pub use self::hash::{H160, H256, H512}; +pub use self::hash::{H160, H256, H512, convert_hash}; pub use self::uint::U256; pub use authority_id::AuthorityId; pub use changes_trie::ChangesTrieConfiguration; diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 72fa107469853..a608a632fe136 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -157,9 +157,9 @@ pub fn child_storage_root(storage_key: &[u8]) -> Option> { } /// "Commit" all existing operations and get the resultant storage change root. -pub fn storage_changes_root(block: u64) -> Option { +pub fn storage_changes_root(parent_hash: [u8; 32], parent_num: u64) -> Option { ext::with(|ext| - ext.storage_changes_root(block) + ext.storage_changes_root(parent_hash.into(), parent_num) ).unwrap_or(None) } diff --git a/core/sr-io/without_std.rs b/core/sr-io/without_std.rs index 5b892ecffe6bb..d0f112b76e8bf 100644 --- a/core/sr-io/without_std.rs +++ b/core/sr-io/without_std.rs @@ -72,7 +72,7 @@ extern "C" { fn ext_get_child_storage_into(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32; fn ext_storage_root(result: *mut u8); fn ext_child_storage_root(storage_key_data: *const u8, storage_key_len: u32, written_out: *mut u32) -> *mut u8; - fn ext_storage_changes_root(block: u64, result: *mut u8) -> u32; + fn ext_storage_changes_root(parent_hash_data: *const u8, parent_hash_len: u32, parent_num: u64, result: *mut u8) -> u32; fn ext_blake2_256_enumerated_trie_root(values_data: *const u8, lens_data: *const u32, lens_len: u32, result: *mut u8); fn ext_chain_id() -> u64; fn ext_blake2_256(data: *const u8, len: u32, out: *mut u8); @@ -269,10 +269,10 @@ pub fn child_storage_root(storage_key: &[u8]) -> Option> { } /// The current storage' changes root. -pub fn storage_changes_root(block: u64) -> Option<[u8; 32]> { +pub fn storage_changes_root(parent_hash: [u8; 32], parent_num: u64) -> Option<[u8; 32]> { let mut result: [u8; 32] = Default::default(); let is_set = unsafe { - ext_storage_changes_root(block, result.as_mut_ptr()) + ext_storage_changes_root(parent_hash.as_ptr(), parent_hash.len() as u32, parent_num, result.as_mut_ptr()) }; if is_set != 0 { diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 809c617218f7e..28c7997a0f04f 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -276,7 +276,7 @@ pub trait Hash: 'static + MaybeSerializeDebug + Clone + Eq + PartialEq { // Stup fn storage_root() -> Self::Output; /// Acquire the global storage changes root. - fn storage_changes_root(block: u64) -> Option; + fn storage_changes_root(parent_hash: Self::Output, parent_number: u64) -> Option; } /// Blake2-256 Hash implementation. @@ -308,8 +308,8 @@ impl Hash for BlakeTwo256 { fn storage_root() -> Self::Output { runtime_io::storage_root().into() } - fn storage_changes_root(block: u64) -> Option { - runtime_io::storage_changes_root(block).map(Into::into) + fn storage_changes_root(parent_hash: Self::Output, parent_number: u64) -> Option { + runtime_io::storage_changes_root(parent_hash.into(), parent_number).map(Into::into) } } diff --git a/core/state-machine/src/changes_trie/build.rs b/core/state-machine/src/changes_trie/build.rs index 991b39593838a..c183f2b3cce23 100644 --- a/core/state-machine/src/changes_trie/build.rs +++ b/core/state-machine/src/changes_trie/build.rs @@ -25,7 +25,7 @@ use overlayed_changes::OverlayedChanges; use trie_backend_essence::{TrieBackendStorage, TrieBackendEssence}; use changes_trie::build_iterator::digest_build_iterator; use changes_trie::input::{InputKey, InputPair, DigestIndex, ExtrinsicIndex}; -use changes_trie::{Configuration, Storage}; +use changes_trie::{AnchorBlockId, Configuration, Storage}; /// Prepare input pairs for building a changes trie of given block. /// @@ -37,7 +37,7 @@ pub fn prepare_input<'a, B, S, H>( backend: &B, storage: Option<&'a S>, changes: &OverlayedChanges, - block: u64, + parent: &'a AnchorBlockId, ) -> Result>, String> where B: Backend, @@ -54,10 +54,10 @@ pub fn prepare_input<'a, B, S, H>( let mut input = Vec::new(); input.extend(prepare_extrinsics_input( backend, - block, + parent.number + 1, changes)?); input.extend(prepare_digest_input::<_, H>( - block, + parent, config, storage)?); @@ -73,7 +73,6 @@ fn prepare_extrinsics_input( where B: Backend, H: Hasher, - { let mut extrinsic_map = BTreeMap::, BTreeSet>::new(); for (key, val) in changes.prospective.top.iter().chain(changes.committed.top.iter()) { @@ -103,19 +102,19 @@ fn prepare_extrinsics_input( /// Prepare DigestIndex input pairs. fn prepare_digest_input<'a, S, H>( - block: u64, + parent: &'a AnchorBlockId, config: &Configuration, storage: &'a S -) -> Result, String> +) -> Result + 'a, String> where S: Storage, &'a S: TrieBackendStorage, H: Hasher, - H::Out: HeapSizeOf, + H::Out: 'a + HeapSizeOf, { let mut digest_map = BTreeMap::, BTreeSet>::new(); - for digest_build_block in digest_build_iterator(config, block) { - let trie_root = storage.root(digest_build_block)?; + for digest_build_block in digest_build_iterator(config, parent.number + 1) { + let trie_root = storage.root(parent, digest_build_block)?; let trie_root = trie_root.ok_or_else(|| format!("No changes trie root for block {}", digest_build_block))?; let trie_storage = TrieBackendEssence::<_, H>::new(storage, trie_root); @@ -136,7 +135,7 @@ fn prepare_digest_input<'a, S, H>( Ok(digest_map.into_iter() .map(move |(key, set)| InputPair::DigestIndex(DigestIndex { - block, + block: parent.number + 1, key }, set.into_iter().collect()))) } @@ -228,7 +227,7 @@ mod test { #[test] fn build_changes_trie_nodes_on_non_digest_block() { let (backend, storage, changes) = prepare_for_build(); - let changes_trie_nodes = prepare_input(&backend, Some(&storage), &changes, 5).unwrap(); + let changes_trie_nodes = prepare_input(&backend, Some(&storage), &changes, &AnchorBlockId { hash: Default::default(), number: 4 }).unwrap(); assert_eq!(changes_trie_nodes, Some(vec![ InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 5, key: vec![100] }, vec![0, 2, 3]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 5, key: vec![101] }, vec![1]), @@ -239,7 +238,7 @@ mod test { #[test] fn build_changes_trie_nodes_on_digest_block_l1() { let (backend, storage, changes) = prepare_for_build(); - let changes_trie_nodes = prepare_input(&backend, Some(&storage), &changes, 4).unwrap(); + let changes_trie_nodes = prepare_input(&backend, Some(&storage), &changes, &AnchorBlockId { hash: Default::default(), number: 3 }).unwrap(); assert_eq!(changes_trie_nodes, Some(vec![ InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![100] }, vec![0, 2, 3]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![101] }, vec![1]), @@ -255,7 +254,7 @@ mod test { #[test] fn build_changes_trie_nodes_on_digest_block_l2() { let (backend, storage, changes) = prepare_for_build(); - let changes_trie_nodes = prepare_input(&backend, Some(&storage), &changes, 16).unwrap(); + let changes_trie_nodes = prepare_input(&backend, Some(&storage), &changes, &AnchorBlockId { hash: Default::default(), number: 15 }).unwrap(); assert_eq!(changes_trie_nodes, Some(vec![ InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![100] }, vec![0, 2, 3]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![101] }, vec![1]), @@ -279,7 +278,7 @@ mod test { extrinsics: Some(vec![1].into_iter().collect()) }); - let changes_trie_nodes = prepare_input(&backend, Some(&storage), &changes, 4).unwrap(); + let changes_trie_nodes = prepare_input(&backend, Some(&storage), &changes, &AnchorBlockId { hash: Default::default(), number: 3 }).unwrap(); assert_eq!(changes_trie_nodes, Some(vec![ InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![100] }, vec![0, 2, 3]), InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 4, key: vec![101] }, vec![1]), diff --git a/core/state-machine/src/changes_trie/changes_iterator.rs b/core/state-machine/src/changes_trie/changes_iterator.rs index 8b4d2bd54070b..e8bd1e7db6b1a 100644 --- a/core/state-machine/src/changes_trie/changes_iterator.rs +++ b/core/state-machine/src/changes_trie/changes_iterator.rs @@ -23,7 +23,7 @@ use codec::{Decode, Encode}; use hash_db::{HashDB, Hasher}; use heapsize::HeapSizeOf; use substrate_trie::{Recorder, MemoryDB}; -use changes_trie::{Configuration, RootsStorage, Storage}; +use changes_trie::{AnchorBlockId, Configuration, RootsStorage, Storage}; use changes_trie::input::{DigestIndex, ExtrinsicIndex, DigestIndexValue, ExtrinsicIndexValue}; use changes_trie::storage::{TrieBackendAdapter, InMemoryStorage}; use proving_backend::ProvingBackendEssence; @@ -35,7 +35,7 @@ pub fn key_changes, H: Hasher>( config: &Configuration, storage: &S, begin: u64, - end: u64, + end: &AnchorBlockId, max: u64, key: &[u8], ) -> Result, String> where H::Out: HeapSizeOf { @@ -46,7 +46,7 @@ pub fn key_changes, H: Hasher>( storage, begin, end, - surface: surface_iterator(config, max, begin, end)?, + surface: surface_iterator(config, max, begin, end.number)?, extrinsics: Default::default(), blocks: Default::default(), @@ -62,7 +62,7 @@ pub fn key_changes_proof, H: Hasher>( config: &Configuration, storage: &S, begin: u64, - end: u64, + end: &AnchorBlockId, max: u64, key: &[u8], ) -> Result>, String> where H::Out: HeapSizeOf { @@ -73,7 +73,7 @@ pub fn key_changes_proof, H: Hasher>( storage, begin, end, - surface: surface_iterator(config, max, begin, end)?, + surface: surface_iterator(config, max, begin, end.number)?, extrinsics: Default::default(), blocks: Default::default(), @@ -98,7 +98,7 @@ pub fn key_changes_proof_check, H: Hasher>( roots_storage: &S, proof: Vec>, begin: u64, - end: u64, + end: &AnchorBlockId, max: u64, key: &[u8] ) -> Result, String> where H::Out: HeapSizeOf { @@ -115,7 +115,7 @@ pub fn key_changes_proof_check, H: Hasher>( storage: &proof_db, begin, end, - surface: surface_iterator(config, max, begin, end)?, + surface: surface_iterator(config, max, begin, end.number)?, extrinsics: Default::default(), blocks: Default::default(), @@ -174,12 +174,12 @@ impl<'a> Iterator for SurfaceIterator<'a> { /// Drilldown iterator - receives 'digest points' from surface iterator and explores /// every point until extrinsic is found. -pub struct DrilldownIteratorEssence<'a, RS: 'a + RootsStorage, S: 'a + Storage, H: Hasher> { +pub struct DrilldownIteratorEssence<'a, RS: 'a + RootsStorage, S: 'a + Storage, H: Hasher> where H::Out: 'a { key: &'a [u8], roots_storage: &'a RS, storage: &'a S, begin: u64, - end: u64, + end: &'a AnchorBlockId, surface: SurfaceIterator<'a>, extrinsics: VecDeque<(u64, u32)>, @@ -213,14 +213,14 @@ impl<'a, RS: 'a + RootsStorage, S: Storage, H: Hasher> DrilldownIteratorEs // not having a changes trie root is an error because: // we never query roots for future blocks // AND trie roots for old blocks are known (both on full + light node) - let trie_root = self.roots_storage.root(block)? + let trie_root = self.roots_storage.root(&self.end, block)? .ok_or_else(|| format!("Changes trie root for block {} is not found", block))?; // only return extrinsics for blocks before self.max // most of blocks will be filtered out beore pushing to `self.blocks` // here we just throwing away changes at digest blocks we're processing debug_assert!(block >= self.begin, "We shall not touch digests earlier than a range' begin"); - if block <= self.end { + if block <= self.end.number { let extrinsics_key = ExtrinsicIndex { block, key: self.key.to_vec() }.encode(); let extrinsics = trie_reader(&self.storage, trie_root, &extrinsics_key); if let Some(extrinsics) = extrinsics? { @@ -239,7 +239,7 @@ impl<'a, RS: 'a + RootsStorage, S: Storage, H: Hasher> DrilldownIteratorEs // filter level0 blocks here because we tend to use digest blocks, // AND digest block changes could also include changes for out-of-range blocks let begin = self.begin; - let end = self.end; + let end = self.end.number; self.blocks.extend(blocks.into_iter() .rev() .filter(|b| level > 1 || (*b >= begin && *b <= end)) @@ -261,7 +261,7 @@ impl<'a, RS: 'a + RootsStorage, S: Storage, H: Hasher> DrilldownIteratorEs } /// Exploring drilldown operator. -struct DrilldownIterator<'a, RS: 'a + RootsStorage, S: 'a + Storage, H: Hasher> { +struct DrilldownIterator<'a, RS: 'a + RootsStorage, S: 'a + Storage, H: Hasher> where H::Out: 'a { essence: DrilldownIteratorEssence<'a, RS, S, H>, } @@ -278,7 +278,7 @@ impl<'a, RS: 'a + RootsStorage, S: Storage, H: Hasher> Iterator } /// Proving drilldown iterator. -struct ProvingDrilldownIterator<'a, RS: 'a + RootsStorage, S: 'a + Storage, H: Hasher> { +struct ProvingDrilldownIterator<'a, RS: 'a + RootsStorage, S: 'a + Storage, H: Hasher> where H::Out: 'a { essence: DrilldownIteratorEssence<'a, RS, S, H>, proof_recorder: RefCell>, } @@ -427,23 +427,23 @@ mod tests { fn drilldown_iterator_works() { let (config, storage) = prepare_for_drilldown(); let drilldown_result = key_changes::, Blake2Hasher>( - &config, &storage, 0, 16, 16, &[42]); + &config, &storage, 0, &AnchorBlockId { hash: Default::default(), number: 16 }, 16, &[42]); assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)])); let drilldown_result = key_changes::, Blake2Hasher>( - &config, &storage, 0, 2, 4, &[42]); + &config, &storage, 0, &AnchorBlockId { hash: Default::default(), number: 2 }, 4, &[42]); assert_eq!(drilldown_result, Ok(vec![])); let drilldown_result = key_changes::, Blake2Hasher>( - &config, &storage, 0, 3, 4, &[42]); + &config, &storage, 0, &AnchorBlockId { hash: Default::default(), number: 3 }, 4, &[42]); assert_eq!(drilldown_result, Ok(vec![(3, 0)])); let drilldown_result = key_changes::, Blake2Hasher>( - &config, &storage, 7, 8, 8, &[42]); + &config, &storage, 7, &AnchorBlockId { hash: Default::default(), number: 8 }, 8, &[42]); assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1)])); let drilldown_result = key_changes::, Blake2Hasher>( - &config, &storage, 5, 7, 8, &[42]); + &config, &storage, 5, &AnchorBlockId { hash: Default::default(), number: 7 }, 8, &[42]); assert_eq!(drilldown_result, Ok(vec![(6, 3)])); } @@ -453,16 +453,16 @@ mod tests { storage.clear_storage(); assert!(key_changes::, Blake2Hasher>( - &config, &storage, 0, 100, 1000, &[42]).is_err()); + &config, &storage, 0, &AnchorBlockId { hash: Default::default(), number: 100 }, 1000, &[42]).is_err()); } #[test] fn drilldown_iterator_fails_when_range_is_invalid() { let (config, storage) = prepare_for_drilldown(); assert!(key_changes::, Blake2Hasher>( - &config, &storage, 0, 100, 50, &[42]).is_err()); + &config, &storage, 0, &AnchorBlockId { hash: Default::default(), number: 100 }, 50, &[42]).is_err()); assert!(key_changes::, Blake2Hasher>( - &config, &storage, 20, 10, 100, &[42]).is_err()); + &config, &storage, 20, &AnchorBlockId { hash: Default::default(), number: 10 }, 100, &[42]).is_err()); } @@ -474,7 +474,7 @@ mod tests { let (remote_config, remote_storage) = prepare_for_drilldown(); let remote_proof = key_changes_proof::, Blake2Hasher>( &remote_config, &remote_storage, - 0, 16, 16, &[42]).unwrap(); + 0, &AnchorBlockId { hash: Default::default(), number: 16 }, 16, &[42]).unwrap(); // happens on local light node: @@ -483,7 +483,7 @@ mod tests { local_storage.clear_storage(); let local_result = key_changes_proof_check::, Blake2Hasher>( &local_config, &local_storage, remote_proof, - 0, 16, 16, &[42]); + 0, &AnchorBlockId { hash: Default::default(), number: 16 }, 16, &[42]); // check that drilldown result is the same as if it was happening at the full node assert_eq!(local_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)])); diff --git a/core/state-machine/src/changes_trie/mod.rs b/core/state-machine/src/changes_trie/mod.rs index fb16cb54d60c2..1d523854ee3e3 100644 --- a/core/state-machine/src/changes_trie/mod.rs +++ b/core/state-machine/src/changes_trie/mod.rs @@ -58,10 +58,20 @@ use trie::{DBValue, trie_root}; /// Changes that are made outside of extrinsics are marked with this index; pub const NO_EXTRINSIC_INDEX: u32 = 0xffffffff; +/// Block identifier that could be used to determine fork of this block. +#[derive(Debug)] +pub struct AnchorBlockId { + /// Hash of this block. + pub hash: Hash, + /// Number of this block. + pub number: u64, +} + /// Changes trie storage. Provides access to trie roots and trie nodes. pub trait RootsStorage: Send + Sync { - /// Get changes trie root for given block. - fn root(&self, block: u64) -> Result, String>; + /// Get changes trie root for the block with given number which is an ancestor (or the block + /// itself) of the anchor_block (i.e. anchor_block.number >= block). + fn root(&self, anchor: &AnchorBlockId, block: u64) -> Result, String>; } /// Changes trie storage. Provides access to trie roots and trie nodes. @@ -79,13 +89,13 @@ pub fn compute_changes_trie_root<'a, B: Backend, S: Storage, H: Hasher>( backend: &B, storage: Option<&'a S>, changes: &OverlayedChanges, - block: u64, + parent: &'a AnchorBlockId, ) -> Option<(H::Out, Vec<(Vec, Vec)>)> where &'a S: TrieBackendStorage, H::Out: Ord + HeapSizeOf, { - let input_pairs = prepare_input::(backend, storage, changes, block) + let input_pairs = prepare_input::(backend, storage, changes, parent) .expect("storage is not allowed to fail within runtime")?; let transaction = input_pairs.into_iter() .map(Into::into) diff --git a/core/state-machine/src/changes_trie/prune.rs b/core/state-machine/src/changes_trie/prune.rs index 8168a0771d315..70bae77b0273f 100644 --- a/core/state-machine/src/changes_trie/prune.rs +++ b/core/state-machine/src/changes_trie/prune.rs @@ -21,7 +21,7 @@ use heapsize::HeapSizeOf; use substrate_trie::Recorder; use proving_backend::ProvingBackendEssence; use trie_backend_essence::TrieBackendEssence; -use changes_trie::{Configuration, Storage}; +use changes_trie::{AnchorBlockId, Configuration, Storage}; use changes_trie::storage::TrieBackendAdapter; /// Prune obslete changes tries. Puning happens at the same block, where highest @@ -33,21 +33,21 @@ pub fn prune, H: Hasher, F: FnMut(H::Out)>( config: &Configuration, storage: &S, min_blocks_to_keep: u64, - current_block: u64, + current_block: &AnchorBlockId, mut remove_trie_node: F, ) where H::Out: HeapSizeOf, { // we only CAN prune at block where max-level-digest is created - let digest_interval = match config.digest_level_at_block(current_block) { + let digest_interval = match config.digest_level_at_block(current_block.number) { Some((digest_level, digest_interval, _)) if digest_level == config.digest_levels => digest_interval, _ => return, }; // select range for pruning - let (first, last) = match pruning_range(min_blocks_to_keep, current_block, digest_interval) { + let (first, last) = match pruning_range(min_blocks_to_keep, current_block.number, digest_interval) { Some((first, last)) => (first, last), None => return, }; @@ -55,7 +55,7 @@ pub fn prune, H: Hasher, F: FnMut(H::Out)>( // delete changes trie for every block in range // TODO: limit `max_digest_interval` so that this cycle won't involve huge ranges for block in first..last+1 { - let root = match storage.root(block) { + let root = match storage.root(current_block, block) { Ok(Some(root)) => root, Ok(None) => continue, Err(error) => { @@ -139,7 +139,7 @@ mod tests { H::Out: HeapSizeOf, { let mut pruned_trie_nodes = HashSet::new(); - prune(config, storage, min_blocks_to_keep, current_block, + prune(config, storage, min_blocks_to_keep, &AnchorBlockId { hash: Default::default(), number: current_block }, |node| { pruned_trie_nodes.insert(node); }); pruned_trie_nodes } diff --git a/core/state-machine/src/changes_trie/storage.rs b/core/state-machine/src/changes_trie/storage.rs index 1cdd03841e1cf..088b605e9cc16 100644 --- a/core/state-machine/src/changes_trie/storage.rs +++ b/core/state-machine/src/changes_trie/storage.rs @@ -22,7 +22,7 @@ use trie::DBValue; use heapsize::HeapSizeOf; use trie::MemoryDB; use parking_lot::RwLock; -use changes_trie::{RootsStorage, Storage}; +use changes_trie::{AnchorBlockId, RootsStorage, Storage}; use trie_backend_essence::TrieBackendStorage; #[cfg(test)] @@ -110,7 +110,7 @@ impl InMemoryStorage where H::Out: HeapSizeOf { } impl RootsStorage for InMemoryStorage where H::Out: HeapSizeOf { - fn root(&self, block: u64) -> Result, String> { + fn root(&self, _anchor_block: &AnchorBlockId, block: u64) -> Result, String> { Ok(self.data.read().roots.get(&block).cloned()) } } diff --git a/core/state-machine/src/ext.rs b/core/state-machine/src/ext.rs index b03ed28250608..1bcb3fb732b1f 100644 --- a/core/state-machine/src/ext.rs +++ b/core/state-machine/src/ext.rs @@ -18,7 +18,7 @@ use std::{error, fmt, cmp::Ord}; use backend::{Backend, Consolidate}; -use changes_trie::{Storage as ChangesTrieStorage, compute_changes_trie_root}; +use changes_trie::{AnchorBlockId, Storage as ChangesTrieStorage, compute_changes_trie_root}; use {Externalities, OverlayedChanges}; use hash_db::Hasher; use primitives::storage::well_known_keys::is_child_storage_key; @@ -288,12 +288,12 @@ where Some(self.child_storage_root_transaction(storage_key).0) } - fn storage_changes_root(&mut self, block: u64) -> Option { + fn storage_changes_root(&mut self, parent: H::Out, parent_num: u64) -> Option { let root_and_tx = compute_changes_trie_root::<_, T, H>( self.backend, self.changes_trie_storage.clone(), self.overlay, - block, + &AnchorBlockId { hash: parent, number: parent_num }, ); let root_and_tx = root_and_tx.map(|(root, changes)| { let mut calculated_root = Default::default(); @@ -305,7 +305,7 @@ where } } - (block, mdb, root) + (parent_num + 1, mdb, root) }); let root = root_and_tx.as_ref().map(|(_, _, root)| root.clone()); self.changes_trie_transaction = root_and_tx; @@ -353,7 +353,7 @@ mod tests { let mut overlay = prepare_overlay_with_changes(); let backend = TestBackend::default(); let mut ext = TestExt::new(&mut overlay, &backend, None); - assert_eq!(ext.storage_changes_root(100), None); + assert_eq!(ext.storage_changes_root(Default::default(), 100), None); } #[test] @@ -363,7 +363,7 @@ mod tests { let storage = TestChangesTrieStorage::new(); let backend = TestBackend::default(); let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage)); - assert_eq!(ext.storage_changes_root(100), None); + assert_eq!(ext.storage_changes_root(Default::default(), 100), None); } #[test] @@ -372,7 +372,7 @@ mod tests { let storage = TestChangesTrieStorage::new(); let backend = TestBackend::default(); let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage)); - assert_eq!(ext.storage_changes_root(100), + assert_eq!(ext.storage_changes_root(Default::default(), 99), Some(hex!("5b829920b9c8d554a19ee2a1ba593c4f2ee6fc32822d083e04236d693e8358d5").into())); } @@ -383,7 +383,7 @@ mod tests { let storage = TestChangesTrieStorage::new(); let backend = TestBackend::default(); let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage)); - assert_eq!(ext.storage_changes_root(100), + assert_eq!(ext.storage_changes_root(Default::default(), 99), Some(hex!("bcf494e41e29a15c9ae5caa053fe3cb8b446ee3e02a254efbdec7a19235b76e4").into())); } } diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 7b0f3690d8d49..e88b3f370a773 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -53,7 +53,9 @@ pub use trie::{TrieMut, TrieDBMut, DBValue, MemoryDB}; pub use testing::TestExternalities; pub use ext::Ext; pub use backend::Backend; -pub use changes_trie::{Storage as ChangesTrieStorage, +pub use changes_trie::{ + AnchorBlockId as ChangesTrieAnchorBlockId, + Storage as ChangesTrieStorage, RootsStorage as ChangesTrieRootsStorage, InMemoryStorage as InMemoryChangesTrieStorage, key_changes, key_changes_proof, key_changes_proof_check, @@ -154,8 +156,8 @@ pub trait Externalities { /// Returns None if key provided is not a storage key. This can due to not being started with CHILD_STORAGE_KEY_PREFIX, or the trie implementation regards the key as invalid. fn child_storage_root(&mut self, storage_key: &[u8]) -> Option>; - /// Get the change trie root of the current storage overlay at given block. - fn storage_changes_root(&mut self, block: u64) -> Option where H::Out: Ord; + /// Get the change trie root of the current storage overlay at a block wth given parent. + fn storage_changes_root(&mut self, parent: H::Out, parent_num: u64) -> Option where H::Out: Ord; } /// Code execution engine. diff --git a/core/state-machine/src/testing.rs b/core/state-machine/src/testing.rs index 75ad342b6bbc2..876a190a966a9 100644 --- a/core/state-machine/src/testing.rs +++ b/core/state-machine/src/testing.rs @@ -22,7 +22,7 @@ use hash_db::Hasher; use heapsize::HeapSizeOf; use trie::trie_root; use backend::InMemory; -use changes_trie::{compute_changes_trie_root, InMemoryStorage as ChangesTrieInMemoryStorage}; +use changes_trie::{compute_changes_trie_root, InMemoryStorage as ChangesTrieInMemoryStorage, AnchorBlockId}; use primitives::storage::well_known_keys::CHANGES_TRIE_CONFIG; use super::{Externalities, OverlayedChanges}; @@ -136,12 +136,12 @@ impl Externalities for TestExternalities where H::Out: Ord + He None } - fn storage_changes_root(&mut self, block: u64) -> Option { + fn storage_changes_root(&mut self, parent: H::Out, parent_num: u64) -> Option { compute_changes_trie_root::<_, _, H>( &InMemory::default(), Some(&self.changes_trie_storage), &self.changes, - block, + &AnchorBlockId { hash: parent, number: parent_num }, ).map(|(root, _)| root.clone()) } } diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index a3041647d43f2..3703fb553e685 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -93,7 +93,7 @@ pub fn execute_block(block: Block) { // check digest let mut digest = Digest::default(); - if let Some(storage_changes_root) = storage_changes_root(header.number) { + if let Some(storage_changes_root) = storage_changes_root(header.parent_hash.into(), header.number - 1) { digest.push(generic::DigestItem::ChangesTrieRoot::(storage_changes_root.into())); } assert!(digest == header.digest, "Header digest items must match that calculated."); @@ -160,7 +160,7 @@ pub fn finalise_block() -> Header { let number = ::take(); let parent_hash = ::take(); let storage_root = BlakeTwo256::storage_root(); - let storage_changes_root = BlakeTwo256::storage_changes_root(number); + let storage_changes_root = BlakeTwo256::storage_changes_root(parent_hash, number - 1); let mut digest = Digest::default(); if let Some(storage_changes_root) = storage_changes_root { diff --git a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index bbac245c7b462..c526eacd1f6de 100644 Binary files a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index fe491c7cfdbaf..704f2d342f276 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -734,7 +734,7 @@ mod tests { let mut t = new_test_ext(true); Executor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1(true).0, true).0.unwrap(); - assert!(t.storage_changes_root(1).is_some()); + assert!(t.storage_changes_root(Default::default(), 0).is_some()); } #[test] @@ -742,6 +742,6 @@ mod tests { let mut t = new_test_ext(true); WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "execute_block", &block1(true).0).unwrap(); - assert!(t.storage_changes_root(1).is_some()); + assert!(t.storage_changes_root(Default::default(), 0).is_some()); } } diff --git a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index aee72d47e77ac..aafdeedceb1d9 100644 Binary files a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index eccd99a98c7cd..c3cffda04f0f0 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -284,7 +284,7 @@ impl Module { let mut digest = >::take(); let extrinsics_root = >::take(); let storage_root = T::Hashing::storage_root(); - let storage_changes_root = T::Hashing::storage_changes_root(number.as_()); + let storage_changes_root = T::Hashing::storage_changes_root(parent_hash, number.as_() - 1); // we can't compute changes trie root earlier && put it to the Digest // because it will include all currently existing temporaries