diff --git a/substrate/core/client/src/cht.rs b/substrate/core/client/src/cht.rs index 54978b7932..fd8e07c3dd 100644 --- a/substrate/core/client/src/cht.rs +++ b/substrate/core/client/src/cht.rs @@ -89,7 +89,7 @@ pub fn build_proof( { let transaction = build_pairs::(cht_size, cht_num, hashes)? .into_iter() - .map(|(k, v)| (k, Some(v))) + .map(|(k, v)| (None, k, Some(v))) .collect::>(); let storage = InMemoryState::::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 { 32 => Some(H256::from_slice(&value[0..32])), _ => None, } - + } #[cfg(test)] diff --git a/substrate/core/client/src/light/backend.rs b/substrate/core/client/src/light/backend.rs index 9ee420140a..e83640aa6c 100644 --- a/substrate/core/client/src/light/backend.rs +++ b/substrate/core/client/src/light/backend.rs @@ -201,7 +201,7 @@ impl StateBackend for OnDemandState S: BlockchainStorage, F: Fetcher, H: Hasher, - + { type Error = ClientError; type Transaction = (); @@ -227,15 +227,32 @@ impl StateBackend for OnDemandState .into_future().wait() } + fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> ClientResult>> { + Err(ClientErrorKind::NotAvailableOnLightClient.into()) + } + fn for_keys_with_prefix(&self, _prefix: &[u8], _action: A) { // whole state is not available on light node } + fn for_keys_in_child_storage(&self, _storage_key: &[u8], _action: A) { + // whole state is not available on light node + } + fn storage_root(&self, _delta: I) -> (H::Out, Self::Transaction) - where I: IntoIterator, Option>)> { + where + I: IntoIterator, Option>)> + { (H::Out::default(), ()) } + fn child_storage_root(&self, _key: &[u8], _delta: I) -> (Vec, Self::Transaction) + where + I: IntoIterator, Option>)> + { + (H::Out::default().as_ref().to_vec(), ()) + } + fn pairs(&self) -> Vec<(Vec, Vec)> { // whole state is not available on light node Vec::new() diff --git a/substrate/core/executor/src/wasm_executor.rs b/substrate/core/executor/src/wasm_executor.rs index 2d626bf1cf..56624060e7 100644 --- a/substrate/core/executor/src/wasm_executor.rs +++ b/substrate/core/executor/src/wasm_executor.rs @@ -181,6 +181,46 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, this.ext.set_storage(key, value); Ok(()) }, + ext_set_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32) => { + let storage_key = this.memory.get(storage_key_data, storage_key_len as usize).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_set_child_storage"))?; + let key = this.memory.get(key_data, key_len as usize).map_err(|_| UserError("Invalid attempt to determine key in ext_set_child_storage"))?; + let value = this.memory.get(value_data, value_len as usize).map_err(|_| UserError("Invalid attempt to determine value in ext_set_child_storage"))?; + if let Some(_preimage) = this.hash_lookup.get(&key) { + debug_trace!( + target: "wasm-trace", "*** Setting child storage: {} -> %{} -> {} [k={}]", + ::primitives::hexdisplay::ascii_format(&storage_key), + ::primitives::hexdisplay::ascii_format(&_preimage), + HexDisplay::from(&value), + HexDisplay::from(&key) + ); + } else { + debug_trace!( + target: "wasm-trace", "*** Setting child storage: {} -> {} -> {} [k={}]", + ::primitives::hexdisplay::ascii_format(&storage_key), + ::primitives::hexdisplay::ascii_format(&key), + HexDisplay::from(&value), + HexDisplay::from(&key) + ); + } + this.ext.set_child_storage(storage_key, key, value); + Ok(()) + }, + ext_clear_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32) => { + let storage_key = this.memory.get( + storage_key_data, + storage_key_len as usize + ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_clear_child_storage"))?; + let key = this.memory.get(key_data, key_len as usize).map_err(|_| UserError("Invalid attempt to determine key in ext_clear_child_storage"))?; + debug_trace!(target: "wasm-trace", "*** Clearing child storage: {} -> {} [k={}]", + ::primitives::hexdisplay::ascii_format(&storage_key), + if let Some(_preimage) = this.hash_lookup.get(&key) { + format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) + } else { + format!(" {}", ::primitives::hexdisplay::ascii_format(&key)) + }, HexDisplay::from(&key)); + this.ext.clear_child_storage(&storage_key, &key); + Ok(()) + }, ext_clear_storage(key_data: *const u8, key_len: u32) => { let key = this.memory.get(key_data, key_len as usize).map_err(|_| UserError("Invalid attempt to determine key in ext_clear_storage"))?; debug_trace!(target: "wasm-trace", "*** Clearing storage: {} [k={}]", @@ -196,14 +236,33 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let key = this.memory.get(key_data, key_len as usize).map_err(|_| UserError("Invalid attempt to determine key in ext_exists_storage"))?; Ok(if this.ext.exists_storage(&key) { 1 } else { 0 }) }, + ext_exists_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32) -> u32 => { + let storage_key = this.memory.get( + storage_key_data, + storage_key_len as usize + ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_exists_child_storage"))?; + let key = this.memory.get(key_data, key_len as usize).map_err(|_| UserError("Invalid attempt to determine key in ext_exists_child_storage"))?; + Ok(if this.ext.exists_child_storage(&storage_key, &key) { 1 } else { 0 }) + }, ext_clear_prefix(prefix_data: *const u8, prefix_len: u32) => { let prefix = this.memory.get(prefix_data, prefix_len as usize).map_err(|_| UserError("Invalid attempt to determine prefix in ext_clear_prefix"))?; this.ext.clear_prefix(&prefix); Ok(()) }, + ext_kill_child_storage(storage_key_data: *const u8, storage_key_len: u32) => { + let storage_key = this.memory.get( + storage_key_data, + storage_key_len as usize + ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_kill_child_storage"))?; + this.ext.kill_child_storage(&storage_key); + Ok(()) + }, // return 0 and place u32::max_value() into written_out if no value exists for the key. ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8 => { - let key = this.memory.get(key_data, key_len as usize).map_err(|_| UserError("Invalid attempt to determine key in ext_get_allocated_storage"))?; + let key = this.memory.get( + key_data, + key_len as usize + ).map_err(|_| UserError("Invalid attempt to determine key in ext_get_allocated_storage"))?; let maybe_value = this.ext.storage(&key); debug_trace!(target: "wasm-trace", "*** Getting storage: {} == {} [k={}]", @@ -213,9 +272,9 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, format!(" {}", ::primitives::hexdisplay::ascii_format(&key)) }, if let Some(ref b) = maybe_value { - format!("{}", HexDisplay::from(b)) + &format!("{}", HexDisplay::from(b)) } else { - "".to_owned() + "" }, HexDisplay::from(&key) ); @@ -232,6 +291,45 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(0) } }, + // return 0 and place u32::max_value() into written_out if no value exists for the key. + ext_get_allocated_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8 => { + let storage_key = this.memory.get( + storage_key_data, + storage_key_len as usize + ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_get_allocated_child_storage"))?; + let key = this.memory.get( + key_data, + key_len as usize + ).map_err(|_| UserError("Invalid attempt to determine key in ext_get_allocated_child_storage"))?; + let maybe_value = this.ext.child_storage(&storage_key, &key); + + debug_trace!(target: "wasm-trace", "*** Getting child storage: {} -> {} == {} [k={}]", + ::primitives::hexdisplay::ascii_format(&storage_key), + if let Some(_preimage) = this.hash_lookup.get(&key) { + format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) + } else { + format!(" {}", ::primitives::hexdisplay::ascii_format(&key)) + }, + if let Some(ref b) = maybe_value { + &format!("{}", HexDisplay::from(b)) + } else { + "" + }, + HexDisplay::from(&key) + ); + + if let Some(value) = maybe_value { + let offset = this.heap.allocate(value.len() as u32) as u32; + this.memory.set(offset, &value).map_err(|_| UserError("Invalid attempt to set memory in ext_get_allocated_child_storage"))?; + this.memory.write_primitive(written_out, value.len() as u32) + .map_err(|_| UserError("Invalid attempt to write written_out in ext_get_allocated_child_storage"))?; + Ok(offset) + } else { + this.memory.write_primitive(written_out, u32::max_value()) + .map_err(|_| UserError("Invalid attempt to write failed written_out in ext_get_allocated_child_storage"))?; + Ok(0) + } + }, // return u32::max_value() if no value exists for the key. ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32 => { let key = this.memory.get(key_data, key_len as usize).map_err(|_| UserError("Invalid attempt to get key in ext_get_storage_into"))?; @@ -243,9 +341,9 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, format!(" {}", ::primitives::hexdisplay::ascii_format(&key)) }, if let Some(ref b) = maybe_value { - format!("{}", HexDisplay::from(b)) + &format!("{}", HexDisplay::from(b)) } else { - "".to_owned() + "" }, HexDisplay::from(&key) ); @@ -259,11 +357,61 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, Ok(u32::max_value()) } }, + // return u32::max_value() if no value exists for the key. + 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 => { + let storage_key = this.memory.get( + storage_key_data, + storage_key_len as usize + ).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_get_child_storage_into"))?; + let key = this.memory.get( + key_data, + key_len as usize + ).map_err(|_| UserError("Invalid attempt to get key in ext_get_child_storage_into"))?; + let maybe_value = this.ext.child_storage(&storage_key, &key); + debug_trace!(target: "wasm-trace", "*** Getting storage: {} -> {} == {} [k={}]", + ::primitives::hexdisplay::ascii_format(&storage_key), + if let Some(_preimage) = this.hash_lookup.get(&key) { + format!("%{}", ::primitives::hexdisplay::ascii_format(&_preimage)) + } else { + format!(" {}", ::primitives::hexdisplay::ascii_format(&key)) + }, + if let Some(ref b) = maybe_value { + &format!("{}", HexDisplay::from(b)) + } else { + "" + }, + HexDisplay::from(&key) + ); + + if let Some(value) = maybe_value { + let value = &value[value_offset as usize..]; + let written = ::std::cmp::min(value_len as usize, value.len()); + this.memory.set(value_data, &value[..written]).map_err(|_| UserError("Invalid attempt to set value in ext_get_child_storage_into"))?; + Ok(written as u32) + } else { + Ok(u32::max_value()) + } + }, ext_storage_root(result: *mut u8) => { let r = this.ext.storage_root(); this.memory.set(result, r.as_ref()).map_err(|_| UserError("Invalid attempt to set memory in ext_storage_root"))?; Ok(()) }, + ext_child_storage_root(storage_key_data: *const u8, storage_key_len: u32, written_out: *mut u32) -> *mut u8 => { + let storage_key = this.memory.get(storage_key_data, storage_key_len as usize).map_err(|_| UserError("Invalid attempt to determine storage_key in ext_child_storage_root"))?; + let r = this.ext.child_storage_root(&storage_key); + if let Some(value) = r { + let offset = this.heap.allocate(value.len() as u32) as u32; + this.memory.set(offset, &value).map_err(|_| UserError("Invalid attempt to set memory in ext_child_storage_root"))?; + this.memory.write_primitive(written_out, value.len() as u32) + .map_err(|_| UserError("Invalid attempt to write written_out in ext_child_storage_root"))?; + Ok(offset) + } else { + this.memory.write_primitive(written_out, u32::max_value()) + .map_err(|_| UserError("Invalid attempt to write failed written_out in ext_child_storage_root"))?; + Ok(0) + } + }, ext_storage_changes_root(block: u64, result: *mut u8) -> u32 => { let r = this.ext.storage_changes_root(block); if let Some(ref r) = r { @@ -300,9 +448,9 @@ impl_function_executor!(this: FunctionExecutor<'e, E>, let hashed_key = twox_128(&key); debug_trace!(target: "xxhash", "XXhash: {} -> {}", if let Ok(_skey) = ::std::str::from_utf8(&key) { - _skey.to_owned() + _skey } else { - format!("{}", HexDisplay::from(&key)) + &format!("{}", HexDisplay::from(&key)) }, HexDisplay::from(&hashed_key) ); diff --git a/substrate/core/network-libp2p/src/custom_proto.rs b/substrate/core/network-libp2p/src/custom_proto.rs index dcf5aaf4e1..a2680b056e 100644 --- a/substrate/core/network-libp2p/src/custom_proto.rs +++ b/substrate/core/network-libp2p/src/custom_proto.rs @@ -161,7 +161,7 @@ where TSubstream: AsyncRead + AsyncWrite, // Note that `inner` is wrapped in a `Fuse`, therefore we can poll it forever. loop { match self.inner.poll()? { - Async::Ready(Some(mut data)) => + Async::Ready(Some(data)) => return Ok(Async::Ready(Some(data.freeze()))), Async::Ready(None) => if !self.requires_poll_complete && self.send_queue.is_empty() { diff --git a/substrate/core/primitives/src/storage.rs b/substrate/core/primitives/src/storage.rs index 253713f738..f3b22294bd 100644 --- a/substrate/core/primitives/src/storage.rs +++ b/substrate/core/primitives/src/storage.rs @@ -72,4 +72,13 @@ pub mod well_known_keys { /// Changes trie configuration is stored under this key. pub const CHANGES_TRIE_CONFIG: &'static [u8] = b":changes_trie"; + + /// Prefix of child storage keys. + pub const CHILD_STORAGE_KEY_PREFIX: &'static [u8] = b":child_storage:"; + + /// Whether a key is a child storage key. + pub fn is_child_storage_key(key: &[u8]) -> bool { + key.starts_with(CHILD_STORAGE_KEY_PREFIX) + } + } diff --git a/substrate/core/sr-io/with_std.rs b/substrate/core/sr-io/with_std.rs index 0522dd23ac..ccadb89efc 100644 --- a/substrate/core/sr-io/with_std.rs +++ b/substrate/core/sr-io/with_std.rs @@ -47,6 +47,12 @@ pub fn storage(key: &[u8]) -> Option> { .expect("storage cannot be called outside of an Externalities-provided environment.") } +/// Get `key` from child storage and return a `Vec`, empty if there's a problem. +pub fn child_storage(storage_key: &[u8], key: &[u8]) -> Option> { + ext::with(|ext| ext.child_storage(storage_key, key).map(|s| s.to_vec())) + .expect("storage cannot be called outside of an Externalities-provided environment.") +} + /// Get `key` from storage, placing the value into `value_out` (as much of it as possible) and return /// the number of bytes that the entry in storage had beyond the offset or None if the storage entry /// doesn't exist at all. Note that if the buffer is smaller than the storage entry length, the returned @@ -55,7 +61,20 @@ pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> Op ext::with(|ext| ext.storage(key).map(|value| { let value = &value[value_offset..]; let written = ::std::cmp::min(value.len(), value_out.len()); - value_out[0..written].copy_from_slice(&value[0..written]); + value_out[..written].copy_from_slice(&value[..written]); + value.len() + })).expect("read_storage cannot be called outside of an Externalities-provided environment.") +} + +/// Get `key` from child storage, placing the value into `value_out` (as much of it as possible) and return +/// the number of bytes that the entry in storage had beyond the offset or None if the storage entry +/// doesn't exist at all. Note that if the buffer is smaller than the storage entry length, the returned +/// number of bytes is not equal to the number of bytes written to the `value_out`. +pub fn read_child_storage(storage_key: &[u8], key: &[u8], value_out: &mut [u8], value_offset: usize) -> Option { + ext::with(|ext| ext.child_storage(storage_key, key).map(|value| { + let value = &value[value_offset..]; + let written = ::std::cmp::min(value.len(), value_out.len()); + value_out[..written].copy_from_slice(&value[..written]); value.len() })).expect("read_storage cannot be called outside of an Externalities-provided environment.") } @@ -67,6 +86,13 @@ pub fn set_storage(key: &[u8], value: &[u8]) { ); } +/// Set the child storage of a key to some value. +pub fn set_child_storage(storage_key: &[u8], key: &[u8], value: &[u8]) { + ext::with(|ext| + ext.set_child_storage(storage_key.to_vec(), key.to_vec(), value.to_vec()) + ); +} + /// Clear the storage of a key. pub fn clear_storage(key: &[u8]) { ext::with(|ext| @@ -74,6 +100,13 @@ pub fn clear_storage(key: &[u8]) { ); } +/// Clear the storage of a key. +pub fn clear_child_storage(storage_key: &[u8], key: &[u8]) { + ext::with(|ext| + ext.clear_child_storage(storage_key, key) + ); +} + /// Check whether a given `key` exists in storage. pub fn exists_storage(key: &[u8]) -> bool { ext::with(|ext| @@ -81,6 +114,13 @@ pub fn exists_storage(key: &[u8]) -> bool { ).unwrap_or(false) } +/// Check whether a given `key` exists in storage. +pub fn exists_child_storage(storage_key: &[u8], key: &[u8]) -> bool { + ext::with(|ext| + ext.exists_child_storage(storage_key, key) + ).unwrap_or(false) +} + /// Clear the storage entries with a key that starts with the given prefix. pub fn clear_prefix(prefix: &[u8]) { ext::with(|ext| @@ -88,6 +128,13 @@ pub fn clear_prefix(prefix: &[u8]) { ); } +/// Clear an entire child storage. +pub fn kill_child_storage(storage_key: &[u8]) { + ext::with(|ext| + ext.kill_child_storage(storage_key) + ); +} + /// The current relay chain identifier. pub fn chain_id() -> u64 { ext::with(|ext| @@ -102,6 +149,13 @@ pub fn storage_root() -> H256 { ).unwrap_or(H256::new()) } +/// "Commit" all existing operations and compute the resultant child storage root. +pub fn child_storage_root(storage_key: &[u8]) -> Option> { + ext::with(|ext| + ext.child_storage_root(storage_key) + ).unwrap_or(None) +} + /// "Commit" all existing operations and get the resultant storage change root. pub fn storage_changes_root(block: u64) -> Option { ext::with(|ext| diff --git a/substrate/core/sr-io/without_std.rs b/substrate/core/sr-io/without_std.rs index db2a1d35d8..5b892ecffe 100644 --- a/substrate/core/sr-io/without_std.rs +++ b/substrate/core/sr-io/without_std.rs @@ -54,16 +54,24 @@ pub extern fn oom(_: ::core::alloc::Layout) -> ! { } extern "C" { + fn ext_free(addr: *mut u8); fn ext_print_utf8(utf8_data: *const u8, utf8_len: u32); fn ext_print_hex(data: *const u8, len: u32); fn ext_print_num(value: u64); fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32); + fn ext_set_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32); fn ext_clear_storage(key_data: *const u8, key_len: u32); + fn ext_clear_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32); fn ext_exists_storage(key_data: *const u8, key_len: u32) -> u32; + fn ext_exists_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32) -> u32; fn ext_clear_prefix(prefix_data: *const u8, prefix_len: u32); + fn ext_kill_child_storage(storage_key_data: *const u8, storage_key_len: u32); fn ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8; + fn ext_get_allocated_child_storage(storage_key_data: *const u8, storage_key_len: u32, key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8; fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32, value_offset: u32) -> u32; + 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_blake2_256_enumerated_trie_root(values_data: *const u8, lens_data: *const u32, lens_len: u32, result: *mut u8); fn ext_chain_id() -> u64; @@ -104,7 +112,24 @@ pub fn storage(key: &[u8]) -> Option> { if length == u32::max_value() { None } else { - Some(Vec::from_raw_parts(ptr, length as usize, length as usize)) + let ret = slice::from_raw_parts(ptr, length as usize).to_vec(); + ext_free(ptr); + Some(ret) + } + } +} + +/// Get `key` from child storage and return a `Vec`, empty if there's a problem. +pub fn child_storage(storage_key: &[u8], key: &[u8]) -> Option> { + let mut length: u32 = 0; + unsafe { + let ptr = ext_get_allocated_child_storage(storage_key.as_ptr(), storage_key.len() as u32, key.as_ptr(), key.len() as u32, &mut length); + if length == u32::max_value() { + None + } else { + let ret = slice::from_raw_parts(ptr, length as usize).to_vec(); + ext_free(ptr); + Some(ret) } } } @@ -119,6 +144,17 @@ pub fn set_storage(key: &[u8], value: &[u8]) { } } +/// Set the child storage of some particular key to Some value. +pub fn set_child_storage(storage_key: &[u8], key: &[u8], value: &[u8]) { + unsafe { + ext_set_child_storage( + storage_key.as_ptr(), key.len() as u32, + key.as_ptr(), key.len() as u32, + value.as_ptr(), value.len() as u32 + ); + } +} + /// Clear the storage of some particular key. pub fn clear_storage(key: &[u8]) { unsafe { @@ -128,6 +164,16 @@ pub fn clear_storage(key: &[u8]) { } } +/// Clear the storage of some particular key. +pub fn clear_child_storage(storage_key: &[u8], key: &[u8]) { + unsafe { + ext_clear_child_storage( + storage_key.as_ptr(), storage_key.len() as u32, + key.as_ptr(), key.len() as u32 + ); + } +} + /// Determine whether a particular key exists in storage. pub fn exists_storage(key: &[u8]) -> bool { unsafe { @@ -137,6 +183,16 @@ pub fn exists_storage(key: &[u8]) -> bool { } } +/// Determine whether a particular key exists in storage. +pub fn exists_child_storage(storage_key: &[u8], key: &[u8]) -> bool { + unsafe { + ext_exists_child_storage( + storage_key.as_ptr(), storage_key.len() as u32, + key.as_ptr(), key.len() as u32 + ) != 0 + } +} + /// Clear the storage entries key of which starts with the given prefix. pub fn clear_prefix(prefix: &[u8]) { unsafe { @@ -147,6 +203,16 @@ pub fn clear_prefix(prefix: &[u8]) { } } +/// Clear an entire child storage. +pub fn kill_child_storage(storage_key: &[u8]) { + unsafe { + ext_kill_child_storage( + storage_key.as_ptr(), + storage_key.len() as u32 + ); + } +} + /// Get `key` from storage, placing the value into `value_out` (as much as possible) and return /// the number of bytes that the key in storage was beyond the offset. pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> Option { @@ -162,6 +228,22 @@ pub fn read_storage(key: &[u8], value_out: &mut [u8], value_offset: usize) -> Op } } +/// Get `key` from child storage, placing the value into `value_out` (as much as possible) and return +/// the number of bytes that the key in storage was beyond the offset. +pub fn read_child_storage(storage_key: &[u8], key: &[u8], value_out: &mut [u8], value_offset: usize) -> Option { + unsafe { + match ext_get_child_storage_into( + storage_key.as_ptr(), storage_key.len() as u32, + key.as_ptr(), key.len() as u32, + value_out.as_mut_ptr(), value_out.len() as u32, + value_offset as u32 + ) { + none if none == u32::max_value() => None, + length => Some(length as usize), + } + } +} + /// The current storage's root. pub fn storage_root() -> [u8; 32] { let mut result: [u8; 32] = Default::default(); @@ -171,6 +253,21 @@ pub fn storage_root() -> [u8; 32] { result } +/// "Commit" all existing operations and compute the resultant child storage root. +pub fn child_storage_root(storage_key: &[u8]) -> Option> { + let mut length: u32 = 0; + unsafe { + let ptr = ext_child_storage_root(storage_key.as_ptr(), storage_key.len() as u32, &mut length); + if length == u32::max_value() { + None + } else { + let ret = slice::from_raw_parts(ptr, length as usize).to_vec(); + ext_free(ptr); + Some(ret) + } + } +} + /// The current storage' changes root. pub fn storage_changes_root(block: u64) -> Option<[u8; 32]> { let mut result: [u8; 32] = Default::default(); diff --git a/substrate/core/state-machine/src/backend.rs b/substrate/core/state-machine/src/backend.rs index 412fe53628..1df07a887d 100644 --- a/substrate/core/state-machine/src/backend.rs +++ b/substrate/core/state-machine/src/backend.rs @@ -23,7 +23,7 @@ use std::marker::PhantomData; use hash_db::Hasher; use trie_backend::TrieBackend; use trie_backend_essence::TrieBackendStorage; -use substrate_trie::{TrieDBMut, TrieMut, MemoryDB, trie_root}; +use substrate_trie::{TrieDBMut, TrieMut, MemoryDB, trie_root, child_trie_root}; use heapsize::HeapSizeOf; /// A state backend is used to read state data and can have changes committed @@ -35,7 +35,7 @@ pub trait Backend { type Error: super::Error; /// Storage changes to be applied if committing - type Transaction; + type Transaction: Consolidate + Default; /// Type of trie backend storage. type TrieBackendStorage: TrieBackendStorage; @@ -43,11 +43,22 @@ pub trait Backend { /// Get keyed storage associated with specific address, or None if there is nothing associated. fn storage(&self, key: &[u8]) -> Result>, Self::Error>; + /// Get keyed child storage associated with specific address, or None if there is nothing associated. + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result>, Self::Error>; + /// true if a key exists in storage. fn exists_storage(&self, key: &[u8]) -> Result { Ok(self.storage(key)?.is_some()) } + /// true if a key exists in child storage. + fn exists_child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result { + Ok(self.child_storage(storage_key, key)?.is_some()) + } + + /// Retrieve all entries keys of child storage and call `f` for each of those keys. + fn for_keys_in_child_storage(&self, storage_key: &[u8], f: F); + /// Retrieve all entries keys of which start with the given prefix and /// call `f` for each of those keys. fn for_keys_with_prefix(&self, prefix: &[u8], f: F); @@ -59,6 +70,13 @@ pub trait Backend { I: IntoIterator, Option>)>, H::Out: Ord; + /// Calculate the child storage root, with given delta over what is already stored in + /// the backend, and produce a "transaction" that can be used to commit. + fn child_storage_root(&self, storage_key: &[u8], delta: I) -> (Vec, Self::Transaction) + where + I: IntoIterator, Option>)>, + H::Out: Ord; + /// Get all key/value pairs into a Vec. fn pairs(&self) -> Vec<(Vec, Vec)>; @@ -66,6 +84,30 @@ pub trait Backend { fn try_into_trie_backend(self) -> Option>; } +/// Trait that allows consolidate two transactions together. +pub trait Consolidate { + /// Consolidate two transactions into one. + fn consolidate(&mut self, other: Self); +} + +impl Consolidate for () { + fn consolidate(&mut self, _: Self) { + () + } +} + +impl Consolidate for Vec<(Option>, Vec, Option>)> { + fn consolidate(&mut self, mut other: Self) { + self.append(&mut other); + } +} + +impl Consolidate for MemoryDB { + fn consolidate(&mut self, other: Self) { + MemoryDB::consolidate(self, other) + } +} + /// Error impossible. // TODO: use `!` type when stabilized. #[derive(Debug)] @@ -85,7 +127,7 @@ impl error::Error for Void { /// tests. #[derive(Eq)] pub struct InMemory { - inner: HashMap, Vec>, + inner: HashMap>, HashMap, Vec>>, _hasher: PhantomData, } @@ -117,10 +159,10 @@ impl InMemory where H::Out: HeapSizeOf { /// Copy the state, with applied updates pub fn update(&self, changes: >::Transaction) -> Self { let mut inner: HashMap<_, _> = self.inner.clone(); - for (key, val) in changes { + for (storage_key, key, val) in changes { match val { - Some(v) => { inner.insert(key, v); }, - None => { inner.remove(&key); }, + Some(v) => { inner.entry(storage_key).or_default().insert(key, v); }, + None => { inner.entry(storage_key).or_default().remove(&key); }, } } @@ -128,8 +170,8 @@ impl InMemory where H::Out: HeapSizeOf { } } -impl From, Vec>> for InMemory { - fn from(inner: HashMap, Vec>) -> Self { +impl From>, HashMap, Vec>>> for InMemory { + fn from(inner: HashMap>, HashMap, Vec>>) -> Self { InMemory { inner: inner, _hasher: PhantomData, @@ -137,23 +179,42 @@ impl From, Vec>> for InMemory { } } +impl From, Vec>> for InMemory { + fn from(inner: HashMap, Vec>) -> Self { + let mut expanded = HashMap::new(); + expanded.insert(None, inner); + InMemory { + inner: expanded, + _hasher: PhantomData, + } + } +} + impl super::Error for Void {} impl Backend for InMemory where H::Out: HeapSizeOf { type Error = Void; - type Transaction = Vec<(Vec, Option>)>; + type Transaction = Vec<(Option>, Vec, Option>)>; type TrieBackendStorage = MemoryDB; fn storage(&self, key: &[u8]) -> Result>, Self::Error> { - Ok(self.inner.get(key).map(Clone::clone)) + Ok(self.inner.get(&None).and_then(|map| map.get(key).map(Clone::clone))) + } + + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result>, Self::Error> { + Ok(self.inner.get(&Some(storage_key.to_vec())).and_then(|map| map.get(key).map(Clone::clone))) } fn exists_storage(&self, key: &[u8]) -> Result { - Ok(self.inner.get(key).is_some()) + Ok(self.inner.get(&None).map(|map| map.get(key).is_some()).unwrap_or(false)) } fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { - self.inner.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f); + self.inner.get(&None).map(|map| map.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f)); + } + + fn for_keys_in_child_storage(&self, storage_key: &[u8], mut f: F) { + self.inner.get(&Some(storage_key.to_vec())).map(|map| map.keys().for_each(|k| f(&k))); } fn storage_root(&self, delta: I) -> (H::Out, Self::Transaction) @@ -161,7 +222,7 @@ impl Backend for InMemory where H::Out: HeapSizeOf { I: IntoIterator, Option>)>, ::Out: Ord, { - let existing_pairs = self.inner.iter().map(|(k, v)| (k.clone(), Some(v.clone()))); + let existing_pairs = self.inner.get(&None).into_iter().flat_map(|map| map.iter().map(|(k, v)| (k.clone(), Some(v.clone())))); let transaction: Vec<_> = delta.into_iter().collect(); let root = trie_root::(existing_pairs.chain(transaction.iter().cloned()) @@ -170,16 +231,52 @@ impl Backend for InMemory where H::Out: HeapSizeOf { .filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val))) ); - (root, transaction) + let full_transaction = transaction.into_iter().map(|(k, v)| (None, k, v)).collect(); + + (root, full_transaction) + } + + fn child_storage_root(&self, storage_key: &[u8], delta: I) -> (Vec, Self::Transaction) + where + I: IntoIterator, Option>)>, + H::Out: Ord + { + let storage_key = storage_key.to_vec(); + + let existing_pairs = self.inner.get(&Some(storage_key.clone())).into_iter().flat_map(|map| map.iter().map(|(k, v)| (k.clone(), Some(v.clone())))); + + let transaction: Vec<_> = delta.into_iter().collect(); + let root = child_trie_root::( + &storage_key, + existing_pairs.chain(transaction.iter().cloned()) + .collect::>() + .into_iter() + .filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val))) + ); + + let full_transaction = transaction.into_iter().map(|(k, v)| (Some(storage_key.clone()), k, v)).collect(); + + (root, full_transaction) } fn pairs(&self) -> Vec<(Vec, Vec)> { - self.inner.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + self.inner.get(&None).into_iter().flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.clone()))).collect() } fn try_into_trie_backend(self) -> Option> { let mut mdb = MemoryDB::default(); // TODO: should be more correct and use ::new() - let root = insert_into_memory_db::(&mut mdb, self.inner.into_iter())?; + let mut root = None; + for (storage_key, map) in self.inner { + if storage_key != None { + let _ = insert_into_memory_db::(&mut mdb, map.into_iter())?; + } else { + root = Some(insert_into_memory_db::(&mut mdb, map.into_iter())?); + } + } + let root = match root { + Some(root) => root, + None => insert_into_memory_db::(&mut mdb, ::std::iter::empty())?, + }; Some(TrieBackend::new(mdb, root)) } } diff --git a/substrate/core/state-machine/src/changes_trie/build.rs b/substrate/core/state-machine/src/changes_trie/build.rs index 8c317d760e..991b395938 100644 --- a/substrate/core/state-machine/src/changes_trie/build.rs +++ b/substrate/core/state-machine/src/changes_trie/build.rs @@ -73,10 +73,10 @@ fn prepare_extrinsics_input( where B: Backend, H: Hasher, - + { let mut extrinsic_map = BTreeMap::, BTreeSet>::new(); - for (key, val) in changes.prospective.iter().chain(changes.committed.iter()) { + for (key, val) in changes.prospective.top.iter().chain(changes.committed.top.iter()) { let extrinsics = match val.extrinsics { Some(ref extrinsics) => extrinsics, None => continue, @@ -274,7 +274,7 @@ mod test { let (backend, storage, mut changes) = prepare_for_build(); // 110: missing from backend, set to None in overlay - changes.prospective.insert(vec![110], OverlayedValue { + changes.prospective.top.insert(vec![110], OverlayedValue { value: None, extrinsics: Some(vec![1].into_iter().collect()) }); diff --git a/substrate/core/state-machine/src/changes_trie/mod.rs b/substrate/core/state-machine/src/changes_trie/mod.rs index 80f3bd5598..fb16cb54d6 100644 --- a/substrate/core/state-machine/src/changes_trie/mod.rs +++ b/substrate/core/state-machine/src/changes_trie/mod.rs @@ -31,6 +31,9 @@ //! block }, containing entries for every storage key that has been changed in //! the last N*digest_level-1 blocks (except for genesis block), mapping these keys //! to the set of lower-level digest blocks. +//! +//! Changes trie only contains the top level storage changes. Sub-level changes +//! are propogated through its storage root on the top level storage. mod build; mod build_iterator; diff --git a/substrate/core/state-machine/src/ext.rs b/substrate/core/state-machine/src/ext.rs index b0fc7347d3..b052942e49 100644 --- a/substrate/core/state-machine/src/ext.rs +++ b/substrate/core/state-machine/src/ext.rs @@ -17,11 +17,12 @@ //! Conrete externalities implementation. use std::{error, fmt, cmp::Ord}; -use backend::Backend; +use backend::{Backend, Consolidate}; use changes_trie::{Storage as ChangesTrieStorage, compute_changes_trie_root}; use {Externalities, OverlayedChanges}; use hash_db::Hasher; -use substrate_trie::{MemoryDB, TrieDBMut, TrieMut}; +use primitives::storage::well_known_keys::is_child_storage_key; +use substrate_trie::{MemoryDB, TrieDBMut, TrieMut, default_child_trie_root, is_child_trie_key_valid}; use heapsize::HeapSizeOf; const EXT_NOT_ALLOWED_TO_FAIL: &'static str = "Externalities not allowed to fail within runtime"; @@ -122,6 +123,31 @@ where fn mark_dirty(&mut self) { self.storage_transaction = None; } + + /// Fetch child storage root together with its transaction. + fn child_storage_root_transaction(&mut self, storage_key: &[u8]) -> (Vec, B::Transaction) { + self.mark_dirty(); + + let (root, transaction) = { + let delta = self.overlay.committed.children.get(storage_key) + .into_iter() + .flat_map(|map| map.1.iter().map(|(k, v)| (k.clone(), v.clone()))) + .chain(self.overlay.prospective.children.get(storage_key) + .into_iter() + .flat_map(|map| map.1.iter().map(|(k, v)| (k.clone(), v.clone())))); + + self.backend.child_storage_root(storage_key, delta) + }; + + let root_val = if root == default_child_trie_root::(storage_key) { + None + } else { + Some(root.clone()) + }; + self.overlay.sync_child_storage_root(storage_key, root_val); + + (root, transaction) + } } #[cfg(test)] @@ -137,8 +163,8 @@ where self.backend.pairs().iter() .map(|&(ref k, ref v)| (k.to_vec(), Some(v.to_vec()))) - .chain(self.overlay.committed.clone().into_iter().map(|(k, v)| (k, v.value))) - .chain(self.overlay.prospective.clone().into_iter().map(|(k, v)| (k, v.value))) + .chain(self.overlay.committed.top.clone().into_iter().map(|(k, v)| (k, v.value))) + .chain(self.overlay.prospective.top.clone().into_iter().map(|(k, v)| (k, v.value))) .collect::>() .into_iter() .filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val))) @@ -158,6 +184,11 @@ where self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL)) } + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option> { + self.overlay.child_storage(storage_key, key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(|| + self.backend.child_storage(storage_key, key).expect(EXT_NOT_ALLOWED_TO_FAIL)) + } + fn exists_storage(&self, key: &[u8]) -> bool { match self.overlay.storage(key) { Some(x) => x.is_some(), @@ -165,12 +196,52 @@ where } } + fn exists_child_storage(&self, storage_key: &[u8], key: &[u8]) -> bool { + match self.overlay.child_storage(storage_key, key) { + Some(x) => x.is_some(), + _ => self.backend.exists_child_storage(storage_key, key).expect(EXT_NOT_ALLOWED_TO_FAIL), + } + } + fn place_storage(&mut self, key: Vec, value: Option>) { + if is_child_storage_key(&key) { + warn!(target: "trie", "Refuse to directly set child storage key"); + return; + } + self.mark_dirty(); self.overlay.set_storage(key, value); } + fn place_child_storage(&mut self, storage_key: Vec, key: Vec, value: Option>) -> bool { + if !is_child_storage_key(&storage_key) || !is_child_trie_key_valid::(&storage_key) { + return false; + } + + self.mark_dirty(); + self.overlay.set_child_storage(storage_key, key, value); + + true + } + + fn kill_child_storage(&mut self, storage_key: &[u8]) { + if !is_child_storage_key(storage_key) || !is_child_trie_key_valid::(storage_key) { + return; + } + + self.mark_dirty(); + self.overlay.clear_child_storage(storage_key); + self.backend.for_keys_in_child_storage(storage_key, |key| { + self.overlay.set_child_storage(storage_key.to_vec(), key.to_vec(), None); + }); + } + fn clear_prefix(&mut self, prefix: &[u8]) { + if is_child_storage_key(prefix) { + warn!(target: "trie", "Refuse to directly clear prefix that is part of child storage key"); + return; + } + self.mark_dirty(); self.overlay.clear_prefix(prefix); self.backend.for_keys_with_prefix(prefix, |key| { @@ -183,19 +254,40 @@ where } fn storage_root(&mut self) -> H::Out { - if let Some((_, ref root)) = self.storage_transaction { + if let Some((_, ref root)) = self.storage_transaction { return root.clone(); } - // compute and memoize - let delta = self.overlay.committed.iter().map(|(k, v)| (k.clone(), v.value.clone())) - .chain(self.overlay.prospective.iter().map(|(k, v)| (k.clone(), v.value.clone()))); + let mut transaction = B::Transaction::default(); + let child_storage_keys: Vec<_> = self.overlay.prospective.children.keys().cloned().collect(); - let (root, transaction) = self.backend.storage_root(delta); + for key in child_storage_keys { + let (_, t) = self.child_storage_root_transaction(&key); + transaction.consolidate(t); + } + + // compute and memoize + let delta = self.overlay.committed.top.iter().map(|(k, v)| (k.clone(), v.value.clone())) + .chain(self.overlay.prospective.top.iter().map(|(k, v)| (k.clone(), v.value.clone()))); + + let (root, t) = self.backend.storage_root(delta); + transaction.consolidate(t); self.storage_transaction = Some((transaction, root)); root } + fn child_storage_root(&mut self, storage_key: &[u8]) -> Option> { + if !is_child_storage_key(storage_key) || !is_child_trie_key_valid::(storage_key) { + return None; + } + + if self.storage_transaction.is_some() { + return Some(self.storage(storage_key).unwrap_or(default_child_trie_root::(storage_key))); + } + + Some(self.child_storage_root_transaction(storage_key).0) + } + fn storage_changes_root(&mut self, block: u64) -> Option { let root_and_tx = compute_changes_trie_root::<_, T, H>( self.backend, @@ -287,7 +379,7 @@ mod tests { #[test] fn storage_changes_root_is_some_when_extrinsic_changes_are_empty() { let mut overlay = prepare_overlay_with_changes(); - overlay.prospective.get_mut(&vec![1]).unwrap().value = None; + overlay.prospective.top.get_mut(&vec![1]).unwrap().value = None; let storage = TestChangesTrieStorage::new(); let backend = TestBackend::default(); let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage)); diff --git a/substrate/core/state-machine/src/lib.rs b/substrate/core/state-machine/src/lib.rs index 50a8a83e6f..4853b2afb5 100644 --- a/substrate/core/state-machine/src/lib.rs +++ b/substrate/core/state-machine/src/lib.rs @@ -97,33 +97,62 @@ pub trait Externalities { /// Read storage of current contract being called. fn storage(&self, key: &[u8]) -> Option>; + /// Read child storage of current contract being called. + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option>; + /// Set storage entry `key` of current contract being called (effective immediately). fn set_storage(&mut self, key: Vec, value: Vec) { self.place_storage(key, Some(value)); } + /// Set child storage entry `key` of current contract being called (effective immediately). + fn set_child_storage(&mut self, storage_key: Vec, key: Vec, value: Vec) -> bool { + self.place_child_storage(storage_key, key, Some(value)) + } + /// Clear a storage entry (`key`) of current contract being called (effective immediately). fn clear_storage(&mut self, key: &[u8]) { self.place_storage(key.to_vec(), None); } - /// Clear a storage entry (`key`) of current contract being called (effective immediately). + /// Clear a child storage entry (`key`) of current contract being called (effective immediately). + fn clear_child_storage(&mut self, storage_key: &[u8], key: &[u8]) -> bool { + self.place_child_storage(storage_key.to_vec(), key.to_vec(), None) + } + + /// Whether a storage entry exists. fn exists_storage(&self, key: &[u8]) -> bool { self.storage(key).is_some() } + /// Whether a child storage entry exists. + fn exists_child_storage(&self, storage_key: &[u8], key: &[u8]) -> bool { + self.child_storage(storage_key, key).is_some() + } + + /// Clear an entire child storage. + fn kill_child_storage(&mut self, storage_key: &[u8]); + /// Clear storage entries which keys are start with the given prefix. fn clear_prefix(&mut self, prefix: &[u8]); /// Set or clear a storage entry (`key`) of current contract being called (effective immediately). fn place_storage(&mut self, key: Vec, value: Option>); + /// Set or clear a child storage entry. Return whether the operation succeeds. + fn place_child_storage(&mut self, storage_key: Vec, key: Vec, value: Option>) -> bool; + /// Get the identity of the chain. fn chain_id(&self) -> u64; - /// Get the trie root of the current storage map. + /// Get the trie root of the current storage map. This will also update all child storage keys in the top-level storage map. fn storage_root(&mut self) -> H::Out where H::Out: Ord; + /// Get the trie root of a child storage map. This will also update the value of the child storage keys in the top-level storage map. If the storage root equals default hash as defined by trie, the key in top-level storage map will be removed. + /// + /// 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; } @@ -477,6 +506,7 @@ where mod tests { use std::collections::HashMap; use codec::Encode; + use overlayed_changes::OverlayedValue; use super::*; use super::backend::InMemory; use super::ext::Ext; @@ -600,12 +630,12 @@ mod tests { let backend = InMemory::::from(initial).try_into_trie_backend().unwrap(); let mut overlay = OverlayedChanges { committed: map![ - b"aba".to_vec() => Some(b"1312".to_vec()).into(), - b"bab".to_vec() => Some(b"228".to_vec()).into() + b"aba".to_vec() => OverlayedValue::from(Some(b"1312".to_vec())), + b"bab".to_vec() => OverlayedValue::from(Some(b"228".to_vec())) ], prospective: map![ - b"abd".to_vec() => Some(b"69".to_vec()).into(), - b"bbd".to_vec() => Some(b"42".to_vec()).into() + b"abd".to_vec() => OverlayedValue::from(Some(b"69".to_vec())), + b"bbd".to_vec() => OverlayedValue::from(Some(b"42".to_vec())) ], ..Default::default() }; @@ -631,6 +661,19 @@ mod tests { ); } + #[test] + fn set_child_storage_works() { + let backend = InMemory::::default().try_into_trie_backend().unwrap(); + let changes_trie_storage = InMemoryChangesTrieStorage::new(); + let mut overlay = OverlayedChanges::default(); + let mut ext = Ext::new(&mut overlay, &backend, Some(&changes_trie_storage)); + + assert!(ext.set_child_storage(b":child_storage:testchild".to_vec(), b"abc".to_vec(), b"def".to_vec())); + assert_eq!(ext.child_storage(b":child_storage:testchild", b"abc"), Some(b"def".to_vec())); + ext.kill_child_storage(b":child_storage:testchild"); + assert_eq!(ext.child_storage(b":child_storage:testchild", b"abc"), None); + } + #[test] fn prove_read_and_proof_check_works() { // fetch read proof from 'remote' full node diff --git a/substrate/core/state-machine/src/overlayed_changes.rs b/substrate/core/state-machine/src/overlayed_changes.rs index e3e8d18b36..15012ac66e 100644 --- a/substrate/core/state-machine/src/overlayed_changes.rs +++ b/substrate/core/state-machine/src/overlayed_changes.rs @@ -16,6 +16,7 @@ //! The overlayed changes to state. +#[cfg(test)] use std::iter::FromIterator; use std::collections::{HashMap, HashSet}; use codec::Decode; use changes_trie::{NO_EXTRINSIC_INDEX, Configuration as ChangesTrieConfig}; @@ -28,9 +29,9 @@ use primitives::storage::well_known_keys::EXTRINSIC_INDEX; #[derive(Debug, Default, Clone)] pub struct OverlayedChanges { /// Changes that are not yet committed. - pub(crate) prospective: HashMap, OverlayedValue>, + pub(crate) prospective: OverlayedChangeSet, /// Committed changes. - pub(crate) committed: HashMap, OverlayedValue>, + pub(crate) committed: OverlayedChangeSet, /// Changes trie configuration. None by default, but could be installed by the /// runtime if it supports change tries. pub(crate) changes_trie_config: Option, @@ -47,6 +48,39 @@ pub struct OverlayedValue { pub extrinsics: Option>, } +/// Prospective or committed overlayed change set. +#[derive(Debug, Default, Clone)] +#[cfg_attr(test, derive(PartialEq))] +pub struct OverlayedChangeSet { + /// Top level storage changes. + pub top: HashMap, OverlayedValue>, + /// Child storage changes. + pub children: HashMap, (Option>, HashMap, Option>>)>, +} + +#[cfg(test)] +impl FromIterator<(Vec, OverlayedValue)> for OverlayedChangeSet { + fn from_iter, OverlayedValue)>>(iter: T) -> Self { + Self { + top: iter.into_iter().collect(), + children: Default::default(), + } + } +} + +impl OverlayedChangeSet { + /// Whether the change set is empty. + pub fn is_empty(&self) -> bool { + self.top.is_empty() && self.children.is_empty() + } + + /// Clear the change set. + pub fn clear(&mut self) { + self.top.clear(); + self.children.clear(); + } +} + impl OverlayedChanges { /// Sets the changes trie configuration. /// @@ -68,17 +102,36 @@ impl OverlayedChanges { /// to the backend); Some(None) if the key has been deleted. Some(Some(...)) for a key whose /// value has been set. pub fn storage(&self, key: &[u8]) -> Option> { - self.prospective.get(key) - .or_else(|| self.committed.get(key)) + self.prospective.top.get(key) + .or_else(|| self.committed.top.get(key)) .map(|x| x.value.as_ref().map(AsRef::as_ref)) } + /// Returns a double-Option: None if the key is unknown (i.e. and the query should be refered + /// to the backend); Some(None) if the key has been deleted. Some(Some(...)) for a key whose + /// value has been set. + pub fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option> { + if let Some(map) = self.prospective.children.get(storage_key) { + if let Some(val) = map.1.get(key) { + return Some(val.as_ref().map(AsRef::as_ref)); + } + } + + if let Some(map) = self.committed.children.get(storage_key) { + if let Some(val) = map.1.get(key) { + return Some(val.as_ref().map(AsRef::as_ref)); + } + } + + None + } + /// Inserts the given key-value pair into the prospective change set. /// /// `None` can be used to delete a value specified by the given key. pub(crate) fn set_storage(&mut self, key: Vec, val: Option>) { let extrinsic_index = self.extrinsic_index(); - let entry = self.prospective.entry(key).or_default(); + let entry = self.prospective.top.entry(key).or_default(); entry.value = val; if let Some(extrinsic) = extrinsic_index { @@ -87,6 +140,57 @@ impl OverlayedChanges { } } + /// Inserts the given key-value pair into the prospective child change set. + /// + /// `None` can be used to delete a value specified by the given key. + pub(crate) fn set_child_storage(&mut self, storage_key: Vec, key: Vec, val: Option>) { + let extrinsic_index = self.extrinsic_index(); + let map_entry = self.prospective.children.entry(storage_key).or_default(); + map_entry.1.insert(key, val); + + if let Some(extrinsic) = extrinsic_index { + map_entry.0.get_or_insert_with(Default::default) + .insert(extrinsic); + } + } + + /// Sync the child storage root. + pub(crate) fn sync_child_storage_root(&mut self, storage_key: &[u8], root: Option>) { + let entry = self.prospective.top.entry(storage_key.to_vec()).or_default(); + entry.value = root; + + if let Some((Some(extrinsics), _)) = self.prospective.children.get(storage_key) { + for extrinsic in extrinsics { + entry.extrinsics.get_or_insert_with(Default::default) + .insert(*extrinsic); + } + } + } + + /// Clear child storage of given storage key. + /// + /// NOTE that this doesn't take place immediately but written into the prospective + /// change set, and still can be reverted by [`discard_prospective`]. + /// + /// [`discard_prospective`]: #method.discard_prospective + pub(crate) fn clear_child_storage(&mut self, storage_key: &[u8]) { + let extrinsic_index = self.extrinsic_index(); + let map_entry = self.prospective.children.entry(storage_key.to_vec()).or_default(); + + if let Some(extrinsic) = extrinsic_index { + map_entry.0.get_or_insert_with(Default::default) + .insert(extrinsic); + } + + map_entry.1.values_mut().for_each(|e| *e = None); + + if let Some((_, committed_map)) = self.committed.children.get(storage_key) { + for (key, _) in committed_map.iter() { + map_entry.1.insert(key.clone(), None); + } + } + } + /// Removes all key-value pairs which keys share the given prefix. /// /// NOTE that this doesn't take place immediately but written into the prospective @@ -98,7 +202,7 @@ impl OverlayedChanges { // Iterate over all prospective and mark all keys that share // the given prefix as removed (None). - for (key, entry) in self.prospective.iter_mut() { + for (key, entry) in self.prospective.top.iter_mut() { if key.starts_with(prefix) { entry.value = None; @@ -111,9 +215,9 @@ impl OverlayedChanges { // Then do the same with keys from commited changes. // NOTE that we are making changes in the prospective change set. - for key in self.committed.keys() { + for key in self.committed.top.keys() { if key.starts_with(prefix) { - let entry = self.prospective.entry(key.clone()).or_default(); + let entry = self.prospective.top.entry(key.clone()).or_default(); entry.value = None; if let Some(extrinsic) = extrinsic_index { @@ -134,8 +238,8 @@ impl OverlayedChanges { if self.committed.is_empty() { ::std::mem::swap(&mut self.prospective, &mut self.committed); } else { - for (key, val) in self.prospective.drain() { - let entry = self.committed.entry(key).or_default(); + for (key, val) in self.prospective.top.drain() { + let entry = self.committed.top.entry(key).or_default(); entry.value = val.value; if let Some(prospective_extrinsics) = val.extrinsics { @@ -143,16 +247,16 @@ impl OverlayedChanges { .extend(prospective_extrinsics); } } - } - } + for (storage_key, map) in self.prospective.children.drain() { + let entry = self.committed.children.entry(storage_key).or_default(); + entry.1.extend(map.1.iter().map(|(k, v)| (k.clone(), v.clone()))); - /// Drain committed changes to an iterator. - /// - /// Panics: - /// Will panic if there are any uncommitted prospective changes. - pub fn drain<'a>(&'a mut self) -> impl Iterator, OverlayedValue)> + 'a { - assert!(self.prospective.is_empty()); - self.committed.drain() + if let Some(prospective_extrinsics) = map.0 { + entry.0.get_or_insert_with(Default::default) + .extend(prospective_extrinsics); + } + } + } } /// Consume `OverlayedChanges` and take committed set. @@ -161,14 +265,14 @@ impl OverlayedChanges { /// Will panic if there are any uncommitted prospective changes. pub fn into_committed(self) -> impl Iterator, Option>)> { assert!(self.prospective.is_empty()); - self.committed.into_iter().map(|(k, v)| (k, v.value)) + self.committed.top.into_iter().map(|(k, v)| (k, v.value)) } /// Inserts storage entry responsible for current extrinsic index. #[cfg(test)] pub(crate) fn set_extrinsic_index(&mut self, extrinsic_index: u32) { use codec::Encode; - self.prospective.insert(EXTRINSIC_INDEX.to_vec(), OverlayedValue { + self.prospective.top.insert(EXTRINSIC_INDEX.to_vec(), OverlayedValue { value: Some(extrinsic_index.encode()), extrinsics: None, }); @@ -293,7 +397,7 @@ mod tests { digest_interval: 4, digest_levels: 1, }), true); assert_eq!( - strip_extrinsic_index(&overlay.prospective), + strip_extrinsic_index(&overlay.prospective.top), vec![ (vec![1], OverlayedValue { value: Some(vec![2]), extrinsics: Some(vec![0].into_iter().collect()) }), ].into_iter().collect(), @@ -329,7 +433,7 @@ mod tests { overlay.set_extrinsic_index(2); overlay.set_storage(vec![1], Some(vec![6])); - assert_eq!(strip_extrinsic_index(&overlay.prospective), + assert_eq!(strip_extrinsic_index(&overlay.prospective.top), vec![ (vec![1], OverlayedValue { value: Some(vec![6]), extrinsics: Some(vec![0, 2].into_iter().collect()) }), (vec![3], OverlayedValue { value: Some(vec![4]), extrinsics: Some(vec![1].into_iter().collect()) }), @@ -344,14 +448,14 @@ mod tests { overlay.set_extrinsic_index(4); overlay.set_storage(vec![1], Some(vec![8])); - assert_eq!(strip_extrinsic_index(&overlay.committed), + assert_eq!(strip_extrinsic_index(&overlay.committed.top), vec![ (vec![1], OverlayedValue { value: Some(vec![6]), extrinsics: Some(vec![0, 2].into_iter().collect()) }), (vec![3], OverlayedValue { value: Some(vec![4]), extrinsics: Some(vec![1].into_iter().collect()) }), (vec![100], OverlayedValue { value: Some(vec![101]), extrinsics: Some(vec![NO_EXTRINSIC_INDEX].into_iter().collect()) }), ].into_iter().collect()); - assert_eq!(strip_extrinsic_index(&overlay.prospective), + assert_eq!(strip_extrinsic_index(&overlay.prospective.top), vec![ (vec![1], OverlayedValue { value: Some(vec![8]), extrinsics: Some(vec![4].into_iter().collect()) }), (vec![3], OverlayedValue { value: Some(vec![7]), extrinsics: Some(vec![3].into_iter().collect()) }), @@ -359,7 +463,7 @@ mod tests { overlay.commit_prospective(); - assert_eq!(strip_extrinsic_index(&overlay.committed), + assert_eq!(strip_extrinsic_index(&overlay.committed.top), vec![ (vec![1], OverlayedValue { value: Some(vec![8]), extrinsics: Some(vec![0, 2, 4].into_iter().collect()) }), (vec![3], OverlayedValue { value: Some(vec![7]), extrinsics: Some(vec![1, 3].into_iter().collect()) }), diff --git a/substrate/core/state-machine/src/proving_backend.rs b/substrate/core/state-machine/src/proving_backend.rs index d17eed7bc8..d8c9ae4695 100644 --- a/substrate/core/state-machine/src/proving_backend.rs +++ b/substrate/core/state-machine/src/proving_backend.rs @@ -20,7 +20,7 @@ use std::cell::RefCell; use hash_db::Hasher; use heapsize::HeapSizeOf; use hash_db::HashDB; -use trie::{TrieDB, Trie, Recorder, MemoryDB, TrieError}; +use trie::{Recorder, MemoryDB, TrieError, default_child_trie_root, read_trie_value_with, read_child_trie_value_with, record_all_keys}; use trie_backend::TrieBackend; use trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage}; use {Error, ExecutionError, Backend}; @@ -47,10 +47,21 @@ impl<'a, S, H> ProvingBackendEssence<'a, S, H> let map_e = |e| format!("Trie lookup error: {}", e); - TrieDB::::new(&eph, self.backend.root()).map_err(map_e)? - .get_with(key, &mut *self.proof_recorder) - .map(|x| x.map(|val| val.to_vec())) - .map_err(map_e) + read_trie_value_with(&eph, self.backend.root(), key, &mut *self.proof_recorder).map_err(map_e) + } + + pub fn child_storage(&mut self, storage_key: &[u8], key: &[u8]) -> Result>, String> { + let root = self.storage(storage_key)?.unwrap_or(default_child_trie_root::(storage_key)); + + let mut read_overlay = MemoryDB::default(); + let eph = Ephemeral::new( + self.backend.backend_storage(), + &mut read_overlay, + ); + + let map_e = |e| format!("Trie lookup error: {}", e); + + read_child_trie_value_with(storage_key, &eph, &root, key, &mut *self.proof_recorder).map_err(map_e) } pub fn record_all_keys(&mut self) { @@ -62,20 +73,7 @@ impl<'a, S, H> ProvingBackendEssence<'a, S, H> let mut iter = move || -> Result<(), Box>> { let root = self.backend.root(); - let trie = TrieDB::::new(&eph, root)?; - let iter = trie.iter()?; - - for x in iter { - let (key, _) = x?; - - // there's currently no API like iter_with() - // => use iter to enumerate all keys AND lookup each - // key using get_with - trie.get_with(&key, &mut *self.proof_recorder) - .map(|x| x.map(|val| val.to_vec()))?; - } - - Ok(()) + record_all_keys::(&eph, root, &mut *self.proof_recorder) }; if let Err(e) = iter() { @@ -128,6 +126,18 @@ impl Backend for ProvingBackend }.storage(key) } + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result>, Self::Error> { + ProvingBackendEssence { + backend: self.backend.essence(), + proof_recorder: &mut *self.proof_recorder.try_borrow_mut() + .expect("only fails when already borrowed; child_storage() is non-reentrant; qed"), + }.child_storage(storage_key, key) + } + + fn for_keys_in_child_storage(&self, storage_key: &[u8], f: F) { + self.backend.for_keys_in_child_storage(storage_key, f) + } + fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { self.backend.for_keys_with_prefix(prefix, f) } @@ -142,6 +152,14 @@ impl Backend for ProvingBackend self.backend.storage_root(delta) } + fn child_storage_root(&self, storage_key: &[u8], delta: I) -> (Vec, Self::Transaction) + where + I: IntoIterator, Option>)>, + H::Out: Ord + { + self.backend.child_storage_root(storage_key, delta) + } + fn try_into_trie_backend(self) -> Option> { None } @@ -211,7 +229,7 @@ mod tests { #[test] fn proof_recorded_and_checked() { - let contents = (0..64).map(|i| (vec![i], Some(vec![i]))).collect::>(); + let contents = (0..64).map(|i| (None, vec![i], Some(vec![i]))).collect::>(); let in_memory = InMemory::::default(); let in_memory = in_memory.update(contents); let in_memory_root = in_memory.storage_root(::std::iter::empty()).0; diff --git a/substrate/core/state-machine/src/testing.rs b/substrate/core/state-machine/src/testing.rs index c26c31dda8..ea67773ed2 100644 --- a/substrate/core/state-machine/src/testing.rs +++ b/substrate/core/state-machine/src/testing.rs @@ -103,6 +103,10 @@ impl Externalities for TestExternalities where H::Out: Ord + He self.inner.get(key).map(|x| x.to_vec()) } + fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> Option> { + None + } + fn place_storage(&mut self, key: Vec, maybe_value: Option>) { self.changes.set_storage(key.clone(), maybe_value.clone()); match maybe_value { @@ -111,6 +115,12 @@ impl Externalities for TestExternalities where H::Out: Ord + He } } + fn place_child_storage(&mut self, _storage_key: Vec, _key: Vec, _value: Option>) -> bool { + false + } + + fn kill_child_storage(&mut self, _storage_key: &[u8]) { } + fn clear_prefix(&mut self, prefix: &[u8]) { self.changes.clear_prefix(prefix); self.inner.retain(|key, _| !key.starts_with(prefix)); @@ -122,6 +132,10 @@ impl Externalities for TestExternalities where H::Out: Ord + He trie_root::(self.inner.clone()) } + fn child_storage_root(&mut self, _storage_key: &[u8]) -> Option> { + None + } + fn storage_changes_root(&mut self, block: u64) -> Option { compute_changes_trie_root::<_, _, H>( &InMemory::default(), diff --git a/substrate/core/state-machine/src/trie_backend.rs b/substrate/core/state-machine/src/trie_backend.rs index 0a4c2bb3ba..6f720a0f09 100644 --- a/substrate/core/state-machine/src/trie_backend.rs +++ b/substrate/core/state-machine/src/trie_backend.rs @@ -18,7 +18,7 @@ use hash_db::Hasher; use heapsize::HeapSizeOf; -use trie::{TrieDB, TrieDBMut, TrieError, Trie, TrieMut, MemoryDB}; +use trie::{TrieDB, TrieError, Trie, MemoryDB, delta_trie_root, default_child_trie_root, child_delta_trie_root}; use trie_backend_essence::{TrieBackendEssence, TrieBackendStorage, Ephemeral}; use {Backend}; @@ -64,10 +64,18 @@ impl, H: Hasher> Backend for TrieBackend where self.essence.storage(key) } + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result>, Self::Error> { + self.essence.child_storage(storage_key, key) + } + fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { self.essence.for_keys_with_prefix(prefix, f) } + fn for_keys_in_child_storage(&self, storage_key: &[u8], f: F) { + self.essence.for_keys_in_child_storage(storage_key, f) + } + fn pairs(&self) -> Vec<(Vec, Vec)> { let mut read_overlay = MemoryDB::default(); // TODO: use new for correctness let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay); @@ -97,22 +105,45 @@ impl, H: Hasher> Backend for TrieBackend where { let mut write_overlay = MemoryDB::default(); let mut root = *self.essence.root(); + { let mut eph = Ephemeral::new( self.essence.backend_storage(), &mut write_overlay, ); - let mut trie = TrieDBMut::::from_existing(&mut eph, &mut root).expect("prior state root to exist"); // TODO: handle gracefully - for (key, change) in delta { - let result = match change { - Some(val) => trie.insert(&key, &val), - None => trie.remove(&key), // TODO: archive mode - }; + match delta_trie_root::(&mut eph, root, delta) { + Ok(ret) => root = ret, + Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), + } + } - if let Err(e) = result { - warn!(target: "trie", "Failed to write to trie: {}", e); - } + (root, write_overlay) + } + + fn child_storage_root(&self, storage_key: &[u8], delta: I) -> (Vec, Self::Transaction) + where + I: IntoIterator, Option>)>, + H::Out: Ord + { + let mut write_overlay = MemoryDB::default(); + let mut root = match self.storage(storage_key) { + Ok(value) => value.unwrap_or(default_child_trie_root::(storage_key)), + Err(e) => { + warn!(target: "trie", "Failed to read child storage root: {}", e); + default_child_trie_root::(storage_key) + }, + }; + + { + let mut eph = Ephemeral::new( + self.essence.backend_storage(), + &mut write_overlay, + ); + + match child_delta_trie_root::(storage_key, &mut eph, root.clone(), delta) { + Ok(ret) => root = ret, + Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), } } @@ -128,6 +159,7 @@ impl, H: Hasher> Backend for TrieBackend where pub mod tests { use std::collections::HashSet; use primitives::{Blake2Hasher, H256}; + use trie::{TrieMut, TrieDBMut}; use super::*; fn test_db() -> (MemoryDB, H256) { diff --git a/substrate/core/state-machine/src/trie_backend_essence.rs b/substrate/core/state-machine/src/trie_backend_essence.rs index 335b325cec..56424ae022 100644 --- a/substrate/core/state-machine/src/trie_backend_essence.rs +++ b/substrate/core/state-machine/src/trie_backend_essence.rs @@ -22,7 +22,7 @@ use std::ops::Deref; use std::sync::Arc; use hash_db::{self, Hasher}; use heapsize::HeapSizeOf; -use trie::{TrieDB, Trie, MemoryDB, DBValue, TrieError}; +use trie::{TrieDB, Trie, MemoryDB, DBValue, TrieError, default_child_trie_root, read_trie_value, read_child_trie_value, for_keys_in_child_trie}; use changes_trie::Storage as ChangesTrieStorage; /// Patricia trie-based storage trait. @@ -66,8 +66,43 @@ impl, H: Hasher> TrieBackendEssence where H::Out: let map_e = |e| format!("Trie lookup error: {}", e); - TrieDB::::new(&eph, &self.root).map_err(map_e)? - .get(key).map(|x| x.map(|val| val.to_vec())).map_err(map_e) + read_trie_value(&eph, &self.root, key).map_err(map_e) + } + + /// Get the value of child storage at given key. + pub fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result>, String> { + let root = self.storage(storage_key)?.unwrap_or(default_child_trie_root::(storage_key)); + + let mut read_overlay = MemoryDB::default(); + let eph = Ephemeral { + storage: &self.storage, + overlay: &mut read_overlay, + }; + + let map_e = |e| format!("Trie lookup error: {}", e); + + read_child_trie_value(storage_key, &eph, &root, key).map_err(map_e) + } + + /// Retrieve all entries keys of child storage and call `f` for each of those keys. + pub fn for_keys_in_child_storage(&self, storage_key: &[u8], f: F) { + let root = match self.storage(storage_key) { + Ok(v) => v.unwrap_or(default_child_trie_root::(storage_key)), + Err(e) => { + debug!(target: "trie", "Error while iterating child storage: {}", e); + return; + } + }; + + let mut read_overlay = MemoryDB::default(); + let eph = Ephemeral { + storage: &self.storage, + overlay: &mut read_overlay, + }; + + if let Err(e) = for_keys_in_child_trie::(storage_key, &eph, &root, f) { + debug!(target: "trie", "Error while iterating child storage: {}", e); + } } /// Execute given closure for all keys starting with prefix. diff --git a/substrate/core/trie/src/lib.rs b/substrate/core/trie/src/lib.rs index 754c6ae16c..87d955a357 100644 --- a/substrate/core/trie/src/lib.rs +++ b/substrate/core/trie/src/lib.rs @@ -45,7 +45,7 @@ pub use trie_stream::TrieStream; /// The Substrate format implementation of `NodeCodec`. pub use node_codec::NodeCodec; /// Various re-exports from the `trie-db` crate. -pub use trie_db::{Trie, TrieMut, DBValue, Recorder}; +pub use trie_db::{Trie, TrieMut, DBValue, Recorder, Query}; /// As in `trie_db`, but less generic, error type for the crate. pub type TrieError = trie_db::TrieError; @@ -53,7 +53,7 @@ pub type TrieError = trie_db::TrieError; pub trait AsHashDB: hash_db::AsHashDB {} impl> AsHashDB for T {} /// As in `hash_db`, but less generic, trait exposed. -pub type HashDB = hash_db::HashDB; +pub type HashDB<'a, H> = hash_db::HashDB + 'a; /// As in `memory_db`, but less generic, trait exposed. pub type MemoryDB = memory_db::MemoryDB; @@ -73,6 +73,36 @@ pub fn trie_root(input: I) -> H::Out where trie_root::trie_root::(input) } +/// Determine a trie root given a hash DB and delta values. +pub fn delta_trie_root(db: &mut HashDB, mut root: H::Out, delta: I) -> Result>> where + I: IntoIterator)>, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]>, +{ + { + let mut trie = TrieDBMut::::from_existing(db, &mut root)?; + + for (key, change) in delta { + match change { + Some(val) => trie.insert(key.as_ref(), val.as_ref())?, + None => trie.remove(key.as_ref())?, // TODO: archive mode + }; + } + } + + Ok(root) +} + +/// Read a value from the trie. +pub fn read_trie_value(db: &HashDB, root: &H::Out, key: &[u8]) -> Result>, Box>> { + Ok(TrieDB::::new(db, root)?.get(key).map(|x| x.map(|val| val.to_vec()))?) +} + +/// Read a value from the trie with given Query. +pub fn read_trie_value_with>(db: &HashDB, root: &H::Out, key: &[u8], query: Q) -> Result>, Box>> { + Ok(TrieDB::::new(db, root)?.get_with(key, query).map(|x| x.map(|val| val.to_vec()))?) +} + /// Determine a trie root node's data given its ordered contents, closed form. pub fn unhashed_trie(input: I) -> Vec where I: IntoIterator, @@ -95,6 +125,102 @@ where ) } +/// Determine whether a child trie key is valid. `child_trie_root` and `child_delta_trie_root` can panic if invalid value is provided to them. +pub fn is_child_trie_key_valid(_storage_key: &[u8]) -> bool { + true +} + +/// Determine the default child trie root. +pub fn default_child_trie_root(_storage_key: &[u8]) -> Vec { + let mut db = MemoryDB::default(); + let mut root = H::Out::default(); + let mut empty = TrieDBMut::::new(&mut db, &mut root); + empty.commit(); + empty.root().as_ref().to_vec() +} + +/// Determine a child trie root given its ordered contents, closed form. H is the default hasher, but a generic +/// implementation may ignore this type parameter and use other hashers. +pub fn child_trie_root(_storage_key: &[u8], input: I) -> Vec where + I: IntoIterator, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]>, +{ + trie_root::(input).as_ref().iter().cloned().collect() +} + +/// Determine a child trie root given a hash DB and delta values. H is the default hasher, but a generic implementation may ignore this type parameter and use other hashers. +pub fn child_delta_trie_root(_storage_key: &[u8], db: &mut HashDB, root_vec: Vec, delta: I) -> Result, Box>> where + I: IntoIterator)>, + A: AsRef<[u8]> + Ord, + B: AsRef<[u8]>, +{ + let mut root = H::Out::default(); + root.as_mut().copy_from_slice(&root_vec); // root is fetched from DB, not writable by runtime, so it's always valid. + + { + let mut trie = TrieDBMut::::from_existing(db, &mut root)?; + + for (key, change) in delta { + match change { + Some(val) => trie.insert(key.as_ref(), val.as_ref())?, + None => trie.remove(key.as_ref())?, // TODO: archive mode + }; + } + } + + Ok(root.as_ref().to_vec()) +} + +/// Call `f` for all keys in a child trie. +pub fn for_keys_in_child_trie(_storage_key: &[u8], db: &HashDB, root_slice: &[u8], mut f: F) -> Result<(), Box>> { + let mut root = H::Out::default(); + root.as_mut().copy_from_slice(root_slice); // root is fetched from DB, not writable by runtime, so it's always valid. + + let trie = TrieDB::::new(db, &root)?; + let iter = trie.iter()?; + + for x in iter { + let (key, _) = x?; + f(&key); + } + + Ok(()) +} + +/// Record all keys for a given root. +pub fn record_all_keys(db: &HashDB, root: &H::Out, recorder: &mut Recorder) -> Result<(), Box>> { + let trie = TrieDB::::new(db, root)?; + let iter = trie.iter()?; + + for x in iter { + let (key, _) = x?; + + // there's currently no API like iter_with() + // => use iter to enumerate all keys AND lookup each + // key using get_with + trie.get_with(&key, &mut *recorder)?; + } + + Ok(()) +} + +/// Read a value from the child trie. +pub fn read_child_trie_value(_storage_key: &[u8], db: &HashDB, root_slice: &[u8], key: &[u8]) -> Result>, Box>> { + let mut root = H::Out::default(); + root.as_mut().copy_from_slice(root_slice); // root is fetched from DB, not writable by runtime, so it's always valid. + + Ok(TrieDB::::new(db, &root)?.get(key).map(|x| x.map(|val| val.to_vec()))?) +} + +/// Read a value from the child trie with given query. +pub fn read_child_trie_value_with>(_storage_key: &[u8], db: &HashDB, root_slice: &[u8], key: &[u8], query: Q) -> Result>, Box>> { + let mut root = H::Out::default(); + root.as_mut().copy_from_slice(root_slice); // root is fetched from DB, not writable by runtime, so it's always valid. + + Ok(TrieDB::::new(db, &root)?.get_with(key, query).map(|x| x.map(|val| val.to_vec()))?) +} + // Utilities (not exported): const EMPTY_TRIE: u8 = 0; @@ -418,4 +544,4 @@ mod tests { assert_eq!(pairs, iter_pairs); } -} \ No newline at end of file +}