Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions lib/src/executor/runtime_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1355,8 +1355,6 @@ enum PendingStorageChangesTrieNode {

/// Writing and reading keys the main trie under this prefix obeys special rules.
const CHILD_STORAGE_SPECIAL_PREFIX: &[u8] = b":child_storage:";
/// Writing and reading keys the main trie under this prefix obeys special rules.
const DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX: &[u8] = b":child_storage:default:";

impl Inner {
/// Continues the execution.
Expand Down Expand Up @@ -1442,11 +1440,7 @@ impl Inner {
// If we've finished calculating a child trie, update its entry in the
// main trie.
if let Some(child_trie) = &trie {
let mut main_trie_key = Vec::with_capacity(
DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX.len() + child_trie.len(),
);
main_trie_key.extend_from_slice(DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX);
main_trie_key.extend_from_slice(child_trie);
let main_trie_key = trie::default_child_trie_root_key(child_trie);

if trie_root_hash != trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE {
self.pending_storage_changes
Expand Down
12 changes: 4 additions & 8 deletions lib/src/network/codec/state_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,10 @@ pub fn build_state_request(config: StateRequest) -> impl Iterator<Item = impl As
either::Left(protobuf::bytes_tag_encode(2, key).map(either::Left))
}
StateRequestStart::ChildTrieDefault { child_trie, key } => either::Right(
protobuf::bytes_tag_encode(2, {
let mut vec = b":child_storage:default:".to_vec();
vec.extend(child_trie);
vec
})
.map(either::Left)
.chain(protobuf::bytes_tag_encode(2, key).map(either::Right))
.map(either::Right),
protobuf::bytes_tag_encode(2, crate::trie::default_child_trie_root_key(&child_trie))
.map(either::Left)
.chain(protobuf::bytes_tag_encode(2, key).map(either::Right))
.map(either::Right),
),
};

Expand Down
11 changes: 9 additions & 2 deletions lib/src/network/codec/storage_call_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,23 @@ pub fn build_child_storage_proof_request<'a>(
impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + 'a,
>,
) -> impl Iterator<Item = impl AsRef<[u8]>> {
// The remote expects the child storage key in field 3 to be the full prefixed key
// (`:child_storage:default:<child_trie>`). It strips the prefix via
// `ChildType::from_prefixed_key` and rejects a bare child trie name with
// `InvalidChildStorageKey`. `ChildStorageProofRequestConfig::child_trie` is the bare name,
// so the prefix is prepended here.
let prefixed_child_trie = crate::trie::default_child_trie_root_key(config.child_trie.as_ref());

// Message format for RemoteReadChildRequest (tag 4 in Request oneof):
// - Field 2: block hash
// - Field 3: child storage key (child trie name)
// - Field 3: child storage key (prefixed child trie key)
// - Field 6: keys to fetch
protobuf::message_tag_encode(
4,
protobuf::bytes_tag_encode(2, config.block_hash)
.map(either::Left)
.chain(
protobuf::bytes_tag_encode(3, config.child_trie)
protobuf::bytes_tag_encode(3, prefixed_child_trie)
.map(either::Left)
.map(either::Right),
)
Expand Down
16 changes: 16 additions & 0 deletions lib/src/trie.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,22 @@ pub const EMPTY_KECCAK256_TRIE_MERKLE_VALUE: [u8; 32] = [
214, 101, 145, 255, 150, 169, 224, 100, 188, 201, 138,
];

/// Prefix that identifies a default child trie within the main trie's storage.
///
/// The root of a default child trie identified by `trie_id` is stored in the main trie under
/// the key `concat(`[`DEFAULT_CHILD_STORAGE_PREFIX`]`, trie_id)`. Use
/// [`default_child_trie_root_key`] to build that key.
pub const DEFAULT_CHILD_STORAGE_PREFIX: &[u8] = b":child_storage:default:";

/// Returns the main-trie storage key under which the root of the default child trie identified
/// by `trie_id` is stored: `concat(`[`DEFAULT_CHILD_STORAGE_PREFIX`]`, trie_id)`.
pub fn default_child_trie_root_key(trie_id: &[u8]) -> Vec<u8> {
let mut k = Vec::with_capacity(DEFAULT_CHILD_STORAGE_PREFIX.len() + trie_id.len());
k.extend_from_slice(DEFAULT_CHILD_STORAGE_PREFIX);
k.extend_from_slice(trie_id);
k
}

/// Returns the Merkle value of a trie containing the entries passed as parameter. The entries
/// passed as parameter are `(key, value)`.
///
Expand Down
54 changes: 35 additions & 19 deletions light-base/src/json_rpc_service/background.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2270,26 +2270,29 @@ pub(super) async fn run<TPlat: PlatformRef>(
}
};

if child_trie.is_some() {
// TODO: implement this
// Child-trie queries only support value and hash reads. The descendants
// and merkle-value variants resolve against a trie root that, for a child
// trie, isn't known until its proof arrives.
if child_trie.is_some()
&& items.iter().any(|item| {
!matches!(
item.ty,
methods::ChainHeadStorageType::Value
| methods::ChainHeadStorageType::Hash
)
})
{
let _ = me
.responses_tx
.send(parse::build_error_response(
request_id_json,
parse::ErrorResponse::ServerError(
-32000,
"Child key storage queries not supported yet",
"child-trie storage queries only support value and hash reads",
),
None,
))
.await;
log!(
&me.platform,
Warn,
&me.log_target,
"chainHead_v1_storage has been called with a non-null childTrie. \
This isn't supported by smoldot yet."
);
continue;
}

Expand Down Expand Up @@ -2341,15 +2344,28 @@ pub(super) async fn run<TPlat: PlatformRef>(
}

// Initialize the storage query operation.
let fetch_operation = me.sync_service.clone().storage_query(
block_number,
hash.0,
block_state_trie_root,
storage_operations.into_iter(),
3,
Duration::from_secs(20),
NonZero::<u32>::new(2).unwrap(),
);
let fetch_operation = if let Some(child_trie) = child_trie {
me.sync_service.clone().child_storage_query(
block_number,
hash.0,
block_state_trie_root,
child_trie.0,
storage_operations.into_iter(),
3,
Duration::from_secs(20),
NonZero::<u32>::new(2).unwrap(),
)
} else {
me.sync_service.clone().storage_query(
block_number,
hash.0,
block_state_trie_root,
storage_operations.into_iter(),
3,
Duration::from_secs(20),
NonZero::<u32>::new(2).unwrap(),
)
};

let operation_id = {
let mut operation_id = [0u8; 32];
Expand Down
10 changes: 2 additions & 8 deletions light-base/src/runtime_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3411,10 +3411,7 @@ async fn runtime_call_single_attempt<TPlat: PlatformRef>(
let proof_access_duration_before = platform.now();
let trie_root = if let Some(child_trie) = child_trie {
// TODO: allocation here, but probably not problematic
const PREFIX: &[u8] = b":child_storage:default:";
let mut key = Vec::with_capacity(PREFIX.len() + child_trie.len());
key.extend_from_slice(PREFIX);
key.extend_from_slice(child_trie.as_ref());
let key = smoldot::trie::default_child_trie_root_key(child_trie.as_ref());
match call_proof.storage_value(block_state_trie_root_hash, &key) {
Err(_) => {
return (
Expand Down Expand Up @@ -3755,10 +3752,7 @@ fn get_trie_root_for_child_or_main<'a>(
child_trie: Option<&[u8]>,
) -> Result<Option<&'a [u8; 32]>, ()> {
if let Some(child_trie) = child_trie {
const PREFIX: &[u8] = b":child_storage:default:";
let mut key = Vec::with_capacity(PREFIX.len() + child_trie.len());
key.extend_from_slice(PREFIX);
key.extend_from_slice(child_trie);
let key = smoldot::trie::default_child_trie_root_key(child_trie);
match proof.storage_value(block_state_trie_root_hash, &key) {
Err(_) => Err(()),
Ok(None) => Ok(None),
Expand Down
Loading
Loading