-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Conversation
core/state-machine/src/ext.rs
Outdated
/// Fetch child storage root together with its transaction. | ||
fn child_storage_root_transaction(&mut self, storage_key: &[u8]) -> (Vec<u8>, B::Transaction) { | ||
self.mark_dirty(); | ||
let storage_key = storage_key.to_vec(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you convert it to an Vec
at this position?
The Vec
is required in sync_child_storage_root
and this function clones the incoming value. So, we make one allocation that is not required at all. If you would call to_vec
in sync_child_storage_root
instead of clone()
. You could reduce the number of allocations to 1.
.insert(extrinsic); | ||
} | ||
|
||
for (_, entry) in map_entry.1.iter_mut() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick:
Could be changed to:
map_entry.1.values_mut().for_each(|e| e = None)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
core/state-machine/src/ext.rs
Outdated
.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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spaces -> tabs
core/executor/src/wasm_executor.rs
Outdated
if let Some(ref b) = maybe_value { | ||
format!("{}", HexDisplay::from(b)) | ||
} else { | ||
"<empty>".to_owned() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can remove the .to_owned()
when you change the first if branch to &format!("{}", HexDisplay::from(b))
.
So you don't need to allocate in the else branch :)
core/executor/src/wasm_executor.rs
Outdated
if let Some(ref b) = maybe_value { | ||
format!("{}", HexDisplay::from(b)) | ||
} else { | ||
"<empty>".to_owned() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as below.
core/executor/src/wasm_executor.rs
Outdated
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)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you maybe break these two debug_trace!
into multiple lines?
core/sr-io/with_std.rs
Outdated
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[0..written].copy_from_slice(&value[0..written]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: You can remove the leading 0
in [0..written]
.
/// Set storage entry `key` of current contract being called (effective immediately). | ||
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) { | ||
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<u8>, key: Vec<u8>, value: Vec<u8>) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe taking just a slice of u8
for each of these values would be better.
You have cases calling this function, where the data is not required to be an Vec<u8>
and so we could reduce the number allocations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only one I found where it may be redundant is kill_child_storage
, which I think would be fine because it doesn't mean to be a fast operation.
I would actually hope to keep this to use Vec<u8>
because it is a public interface. We also have set_storage
and many other interface here that use Vec<u8>
.
core/sr-io/without_std.rs
Outdated
if length == u32::max_value() { | ||
None | ||
} else { | ||
Some(Vec::from_raw_parts(ptr, length as usize, length as usize)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, as above.
core/state-machine/src/backend.rs
Outdated
} | ||
let root = match root { | ||
Some(root) => root, | ||
None => insert_into_memory_db::<H, _>(&mut mdb, HashMap::new().into_iter())?, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think HashMap::new().into_iter()
can be replaced by https://doc.rust-lang.org/std/iter/fn.empty.html
… sp-multi-trie2
core/executor/src/wasm_executor.rs
Outdated
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"))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this code is wider than 120 maximum. Can we wrap this code?
core/executor/src/wasm_executor.rs
Outdated
@@ -196,11 +221,21 @@ 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"))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this code is wider than 120 maximum. Can we wrap this code?
core/executor/src/wasm_executor.rs
Outdated
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"))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this code is wider than 120 maximum. Can we wrap this code?
core/executor/src/wasm_executor.rs
Outdated
@@ -232,6 +267,39 @@ 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"))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this code is wider than 120 maximum. Can we wrap this code?
core/executor/src/wasm_executor.rs
Outdated
@@ -259,11 +327,55 @@ 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"))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this code is wider than 120 maximum. Can we wrap this code?
core/sr-io/without_std.rs
Outdated
if length == u32::max_value() { | ||
None | ||
} else { | ||
Some(slice::from_raw_parts(ptr, length as usize).to_vec()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last time ^^
@pepyakin can't we call ext_free
here for freeing ptr
?
If that not works, I would at least propose to add TODO
over these lines that we do not forget these memory leaks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is the only possible way, as long as ext_*
make allocations with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me :)
rel #872
This adds support for multiple storage root. The basic idea is that we compute multiple tries (maybe of different types) for the same runtime, and in the end, merge the changeset to commit the results. This allows children trie to get its own storage root.
The top-level storage contains a
WELL_KNOWN_KEYS
prefix:child_storage:
, within which we store all child storage roots. A child storage root is updated wheneverExt::child_storage_root
is called, orExt::storage_root
is called.Ext::place_storage
and other mutation operations are forbidden to modify storage values under:child_storage:
.Currently it's a non-generic version, but it already works -- even for multiple trie types. (I'm hoping to get a generic version, together with generic tries, in a separate PR.) The trick is that one can specify
[patch]
forsubstrate-trie
to overwrite the default implementation, and then write a customizedchild_delta_trie_root
. The idea is that that function should dispatch and use different trie types to compute the transaction based on the child "storage key". A customized implementation can also useis_child_trie_key_valid
to make it so that only a subset of the:child_storage:
namespace is valid.For the default implementation right now in
substrate-trie
, it builds all child tries using the same trie type.