Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish implementing state_version = 1 #230

Merged
merged 27 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
157897d
Implement ext_storage_root_version_2
tomaka Feb 24, 2023
1e67fa3
Add support for trie v1 in RuntimeHostVm
tomaka Feb 24, 2023
77f058e
Update chain_spec.rs after API changes
tomaka Feb 24, 2023
12ead00
Propagate changes to the various runtime state machines
tomaka Feb 24, 2023
c8b4004
Add a generic parameter to StorageDiff
tomaka Feb 24, 2023
5af960b
Fix template parameters on StorageDiff
tomaka Feb 24, 2023
0398dee
Add StorageDiff::merge_map
tomaka Feb 24, 2023
dafd235
Update optimistic.rs
tomaka Feb 24, 2023
187a428
Fix merge_map
tomaka Feb 24, 2023
1268526
Update all.rs
tomaka Feb 24, 2023
1f2c722
Give information about the trie node version in Merkle proofs
tomaka Feb 24, 2023
1043a6c
Only provide a node version when a value is set
tomaka Feb 24, 2023
ca30862
Update light-base
tomaka Feb 24, 2023
04f3446
Fix tests
tomaka Feb 24, 2023
47c78af
Add BlockFull::state_trie_version
tomaka Feb 24, 2023
90d851a
Store the trie entry version in the storage cache
tomaka Feb 24, 2023
ef029e4
Insert the trie entry version in the database
tomaka Feb 25, 2023
283d99a
WIP full node update
tomaka Feb 25, 2023
a6bee38
Make the database return the trie entry version
tomaka Feb 25, 2023
8371bf9
Finish update to full node
tomaka Feb 26, 2023
370370a
Fix invalid write to non_finalized_changes
tomaka Feb 26, 2023
fd9a914
Minor fixes
tomaka Feb 26, 2023
9429737
Also implement ext_default_child_storage_root_version_2
tomaka Feb 26, 2023
e13f394
Fix doctest
tomaka Feb 26, 2023
78239e1
Fix other doctest
tomaka Feb 26, 2023
7ff485b
Add comment about versions in trie.rs
tomaka Feb 26, 2023
f965a31
Spellcheck
tomaka Feb 26, 2023
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
30 changes: 24 additions & 6 deletions full-node/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use futures::{channel::oneshot, prelude::*};
use smoldot::{
chain, chain_spec,
database::full_sqlite,
header,
executor, header,
identity::keystore,
informant::HashDisplay,
libp2p::{
Expand Down Expand Up @@ -742,18 +742,36 @@ async fn open_database(

// The database doesn't exist or is empty.
full_sqlite::DatabaseOpen::Empty(empty) => {
let genesis_storage = chain_spec.genesis_storage().into_genesis_items().unwrap(); // TODO: return error instead

// In order to determine the state_version of the genesis block, we need to compile
// the runtime.
// TODO: return errors instead of panicking
let state_version = executor::host::HostVmPrototype::new(executor::host::Config {
module: genesis_storage.value(b":code").unwrap(),
heap_pages: executor::storage_heap_pages_to_value(
genesis_storage.value(b":heappages"),
)
.unwrap(),
exec_hint: executor::vm::ExecHint::Oneshot,
allow_unresolved_imports: true,
})
.unwrap()
.runtime_version()
.decode()
.state_version
.map(|v| u8::from(v))
.unwrap_or(0);

// The finalized block is the genesis block. As such, it has an empty body and
// no justification.
let database = empty
.initialize(
genesis_chain_information,
iter::empty(),
None,
chain_spec
.genesis_storage()
.into_genesis_items()
.unwrap() // TODO: return error instead
.iter(),
genesis_storage.iter(),
state_version,
)
.unwrap();
(database, false)
Expand Down
49 changes: 36 additions & 13 deletions full-node/src/run/consensus_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use smoldot::{
informant::HashDisplay,
libp2p,
network::{self, protocol::BlockData},
sync::all,
sync::all::{self, TrieEntryVersion},
};
use std::{
collections::BTreeMap,
Expand Down Expand Up @@ -128,7 +128,14 @@ impl ConsensusService {
best_block_number,
finalized_block_storage,
finalized_chain_information,
): (_, _, _, _, BTreeMap<Vec<u8>, Vec<u8>>, _) = config
): (
_,
_,
_,
_,
BTreeMap<Vec<u8>, (Vec<u8>, TrieEntryVersion)>,
_,
) = config
.database
.with_database({
let block_number_bytes = config.block_number_bytes;
Expand All @@ -153,9 +160,17 @@ impl ConsensusService {
)
.unwrap()
.number;
let finalized_block_storage = database
let finalized_block_storage: Vec<(Vec<u8>, Vec<u8>, u8)> = database
.finalized_block_storage_top_trie(&finalized_block_hash)
.unwrap();
// TODO: we copy all entries; it could be more optimal to have a custom implementation of FromIterator that directly does the conversion?
let finalized_block_storage = finalized_block_storage
.into_iter()
.map(|(k, val, vers)| {
let vers = TrieEntryVersion::try_from(vers).unwrap(); // TODO: don't unwrap
(k, (val, vers))
})
.collect();
let finalized_chain_information = database
.to_chain_information(&finalized_block_hash)
.unwrap();
Expand Down Expand Up @@ -223,11 +238,11 @@ impl ConsensusService {
// Builds the runtime of the finalized block.
// Assumed to always be valid, otherwise the block wouldn't have been saved in the
// database, hence the large number of unwraps here.
let module = finalized_block_storage.get(&b":code"[..]).unwrap();
let (module, _) = finalized_block_storage.get(&b":code"[..]).unwrap();
let heap_pages = executor::storage_heap_pages_to_value(
finalized_block_storage
.get(&b":heappages"[..])
.map(|v| &v[..]),
.map(|(v, _)| &v[..]),
)
.unwrap();
executor::host::HostVmPrototype::new(executor::host::Config {
Expand Down Expand Up @@ -329,7 +344,7 @@ struct SyncBackground {
// While reading the storage from the database is an option, doing so considerably slows down
/// the verification, and also makes it impossible to insert blocks in the database in
/// parallel of this verification.
finalized_block_storage: BTreeMap<Vec<u8>, Vec<u8>>,
finalized_block_storage: BTreeMap<Vec<u8>, (Vec<u8>, TrieEntryVersion)>,

sync_state: Arc<Mutex<SyncState>>,

Expand Down Expand Up @@ -754,10 +769,11 @@ impl SyncBackground {
best_block_storage_access.get(key.as_ref(), || {
self.finalized_block_storage
.get(key.as_ref())
.map(|v| &v[..])
.map(|(val, vers)| (&val[..], *vers))
})
};
block_authoring = get.inject_value(value.map(iter::once));
block_authoring =
get.inject_value(value.map(|(val, vers)| (iter::once(val), vers)));
continue;
}
author::build::BuilderAuthoring::NextKey(_) => {
Expand Down Expand Up @@ -1137,7 +1153,7 @@ impl SyncBackground {
let value = self
.finalized_block_storage
.get(req.key().as_ref())
.map(|v| &v[..]);
.map(|(val, vers)| (&val[..], *vers));
verify = req.inject_value(value);
}
all::BlockVerification::FinalizedStorageNextKey(req) => {
Expand Down Expand Up @@ -1212,16 +1228,21 @@ impl SyncBackground {

// TODO: maybe write in a separate task? but then we can't access the finalized storage immediately after?
for block in &finalized_blocks {
for (key, value) in block
for (key, value, ()) in block
.full
.as_ref()
.unwrap()
.storage_top_trie_changes
.diff_iter_unordered()
{
if let Some(value) = value {
self.finalized_block_storage
.insert(key.to_owned(), value.to_owned());
self.finalized_block_storage.insert(
key.to_owned(),
(
value.to_owned(),
block.full.as_ref().unwrap().state_trie_version,
),
);
} else {
let _was_there = self.finalized_block_storage.remove(key);
// TODO: if a block inserts a new value, then removes it in the next block, the key will remain in `finalized_block_storage`; either solve this or document this
Expand Down Expand Up @@ -1327,7 +1348,9 @@ async fn database_blocks(
.as_ref()
.unwrap()
.storage_top_trie_changes
.diff_iter_unordered(),
.diff_iter_unordered()
.map(|(k, v, ())| (k, v)),
u8::from(block.full.as_ref().unwrap().state_trie_version),
);

match result {
Expand Down
4 changes: 3 additions & 1 deletion lib/src/author/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ use crate::{
use alloc::vec::Vec;
use core::{num::NonZeroU64, time::Duration};

pub use runtime::TrieEntryVersion;

/// Configuration for a block generation.
pub struct Config<'a, TLocAuth> {
/// Consensus-specific configuration.
Expand Down Expand Up @@ -310,7 +312,7 @@ impl StorageGet {
/// Injects the corresponding storage value.
pub fn inject_value(
self,
value: Option<impl Iterator<Item = impl AsRef<[u8]>>>,
value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>,
) -> BuilderAuthoring {
self.1.with_runtime_inner(self.0.inject_value(value))
}
Expand Down
11 changes: 10 additions & 1 deletion lib/src/author/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ use crate::{
use alloc::{borrow::ToOwned as _, string::String, vec::Vec};
use core::{iter, mem};

pub use runtime_host::TrieEntryVersion;

/// Configuration for a block generation.
pub struct Config<'a> {
/// Number of bytes used to encode block numbers in the header.
Expand Down Expand Up @@ -110,6 +112,9 @@ pub struct Success {
pub parent_runtime: host::HostVmPrototype,
/// List of changes to the storage top trie that the block performs.
pub storage_top_trie_changes: storage_diff::StorageDiff,
/// State trie version indicated by the runtime. All the storage changes indicated by
/// [`Success::storage_top_trie_changes`] should store this version alongside with them.
pub state_trie_version: TrieEntryVersion,
/// List of changes to the off-chain storage that this block performs.
pub offchain_storage_changes: storage_diff::StorageDiff,
/// Cache used for calculating the top trie root of the new block.
Expand Down Expand Up @@ -428,6 +433,7 @@ impl BlockBuild {
body: shared.block_body,
parent_runtime: success.virtual_machine.into_prototype(),
storage_top_trie_changes: success.storage_top_trie_changes,
state_trie_version: success.state_trie_version,
offchain_storage_changes: success.offchain_storage_changes,
top_trie_root_calculation_cache: success.top_trie_root_calculation_cache,
logs: shared.logs,
Expand Down Expand Up @@ -595,7 +601,10 @@ impl StorageGet {
}

/// Injects the corresponding storage value.
pub fn inject_value(self, value: Option<impl Iterator<Item = impl AsRef<[u8]>>>) -> BlockBuild {
pub fn inject_value(
self,
value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>,
) -> BlockBuild {
BlockBuild::from_inner(self.0.inject_value(value), self.1)
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/author/runtime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fn block_building_works() {
.iter()
.find(|(k, _)| *k == get.key().as_ref())
.map(|(_, v)| iter::once(v));
builder = get.inject_value(value);
builder = get.inject_value(value.map(|v| (v, super::TrieEntryVersion::V0)));
}
super::BlockBuild::NextKey(_) => unimplemented!(), // Not needed for this test.
super::BlockBuild::PrefixKeys(prefix) => {
Expand Down
9 changes: 8 additions & 1 deletion lib/src/chain/blocks_tree/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ use super::{
use alloc::boxed::Box;
use core::cmp::Ordering;

pub use verify::header_body::TrieEntryVersion;

impl<T> NonFinalizedTree<T> {
/// Verifies the given block.
///
Expand Down Expand Up @@ -600,6 +602,7 @@ impl<T> VerifyContext<T> {
parent_runtime: success.parent_runtime,
new_runtime: success.new_runtime,
storage_top_trie_changes: success.storage_top_trie_changes,
state_trie_version: success.state_trie_version,
offchain_storage_changes: success.offchain_storage_changes,
top_trie_root_calculation_cache: success.top_trie_root_calculation_cache,
insert: BodyInsert {
Expand Down Expand Up @@ -845,6 +848,10 @@ pub enum BodyVerifyStep2<T> {
new_runtime: Option<host::HostVmPrototype>,
/// List of changes to the storage top trie that the block performs.
storage_top_trie_changes: storage_diff::StorageDiff,
/// State trie version indicated by the runtime. All the storage changes indicated by
/// [`BodyVerifyStep2::Finished::storage_top_trie_changes`] should store this version
/// alongside with them.
state_trie_version: TrieEntryVersion,
/// List of changes to the off-chain storage that this block performs.
offchain_storage_changes: storage_diff::StorageDiff,
/// Cache of calculation for the storage trie of the best block.
Expand Down Expand Up @@ -940,7 +947,7 @@ impl<T> StorageGet<T> {
/// Injects the corresponding storage value.
pub fn inject_value(
self,
value: Option<impl Iterator<Item = impl AsRef<[u8]>>>,
value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>,
) -> BodyVerifyStep2<T> {
let inner = self.inner.inject_value(value);
self.context.with_body_verify(inner)
Expand Down
15 changes: 6 additions & 9 deletions lib/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,11 @@ impl ChainSpec {
let mut chain_information_build = build::ChainInformationBuild::new(build::Config {
finalized_block_header: build::ConfigFinalizedBlockHeader::Genesis {
state_trie_root_hash: {
let state_version = match vm_prototype.runtime_version().decode().state_version
{
Some(0) | None => trie::TrieEntryVersion::V0,
Some(1) => trie::TrieEntryVersion::V1,
Some(_) => return Err(FromGenesisStorageError::UnknownStateVersion),
};
let state_version = vm_prototype
.runtime_version()
.decode()
.state_version
.unwrap_or(trie::TrieEntryVersion::V0);

match self.genesis_storage() {
GenesisStorage::TrieRootHash(hash) => *hash,
Expand All @@ -144,7 +143,7 @@ impl ChainSpec {
) => {
let key: alloc::vec::Vec<u8> = val.key().collect();
let value = genesis_storage.value(&key[..]);
calculation = val.inject(state_version, value);
calculation = val.inject(value.map(move |v| (v, state_version)));
}
}
}
Expand Down Expand Up @@ -496,8 +495,6 @@ pub enum FromGenesisStorageError {
/// Error when initializing the virtual machine.
#[display(fmt = "Error when initializing the virtual machine: {}", _0)]
VmInitialization(executor::host::NewErr),
/// State version in runtime specification is not supported.
UnknownStateVersion,
/// Chain specification doesn't contain the list of storage items.
UnknownStorageItems,
}
Expand Down
Loading