diff --git a/bin/full-node/src/run.rs b/bin/full-node/src/run.rs index 7f365e0e3c..0d6ebfc716 100644 --- a/bin/full-node/src/run.rs +++ b/bin/full-node/src/run.rs @@ -704,7 +704,7 @@ async fn open_database( // no justification. let database = empty .initialize( - genesis_chain_information, + (&genesis_chain_information.finalized_block_header).into(), iter::empty(), None, chain_spec diff --git a/src/database/full_sqlite.rs b/src/database/full_sqlite.rs index d037c735bc..6614c63444 100644 --- a/src/database/full_sqlite.rs +++ b/src/database/full_sqlite.rs @@ -70,9 +70,9 @@ #![cfg(feature = "database-sqlite")] #![cfg_attr(docsrs, doc(cfg(feature = "database-sqlite")))] -use crate::{chain::chain_information, header, util}; +use crate::{chain::chain_information, executor, header}; -use core::{fmt, iter, num::NonZeroU64}; +use core::{fmt, iter}; use parking_lot::Mutex; pub use open::{open, Config, ConfigTy, DatabaseEmpty, DatabaseOpen}; @@ -230,77 +230,88 @@ impl SqliteFullDatabase { block_header(&connection, finalized_block_hash, self.block_number_bytes)? .ok_or(AccessError::Corrupted(CorruptedError::MissingBlockHeader))?; - let finality = match ( - grandpa_authorities_set_id(&connection)?, - grandpa_finalized_triggered_authorities(&connection)?, - grandpa_finalized_scheduled_change(&connection)?, - ) { - ( - Some(after_finalized_block_authorities_set_id), - finalized_triggered_authorities, - finalized_scheduled_change, - ) => chain_information::ChainInformationFinality::Grandpa { - after_finalized_block_authorities_set_id, - finalized_triggered_authorities, - finalized_scheduled_change, - }, - (None, auth, None) if auth.is_empty() => { - chain_information::ChainInformationFinality::Outsourced - } - _ => { - return Err(FinalizedAccessError::Access(AccessError::Corrupted( - CorruptedError::ConsensusAlgorithmMix, - ))) - } + let runtime = { + let code = finalized_block_storage_top_trie(&connection, b":code")?.ok_or( + AccessError::Corrupted(CorruptedError::InvalidChainInformation( + InvalidChainInformationError::MissingRuntimeCode, + )), + )?; + let heap_pages = executor::storage_heap_pages_to_value( + finalized_block_storage_top_trie(&connection, b":heappages")? + .as_ref() + .map(|v| &v[..]), + ) + .map_err(|err| { + AccessError::Corrupted(CorruptedError::InvalidChainInformation( + InvalidChainInformationError::InvalidHeapPages(err), + )) + })?; + + executor::host::HostVmPrototype::new(executor::host::Config { + module: &code, + heap_pages, + exec_hint: executor::vm::ExecHint::Oneshot, + allow_unresolved_imports: false, + }) + .map_err(|err| { + AccessError::Corrupted(CorruptedError::InvalidChainInformation( + InvalidChainInformationError::InvalidRuntime(err), + )) + })? }; - let consensus = match ( - meta_get_number(&connection, "aura_slot_duration")?, - meta_get_number(&connection, "babe_slots_per_epoch")?, - meta_get_blob(&connection, "babe_finalized_next_epoch")?, - ) { - (None, Some(slots_per_epoch), Some(finalized_next_epoch)) => { - let slots_per_epoch = expect_nz_u64(slots_per_epoch)?; - let finalized_next_epoch_transition = - decode_babe_epoch_information(&finalized_next_epoch)?; - let finalized_block_epoch_information = - meta_get_blob(&connection, "babe_finalized_epoch")? - .map(|v| decode_babe_epoch_information(&v)) - .transpose()?; - chain_information::ChainInformationConsensus::Babe { - finalized_block_epoch_information, - finalized_next_epoch_transition, - slots_per_epoch, + let mut chain_info_builder = chain_information::build::ChainInformationBuild::new( + chain_information::build::Config { + runtime, + finalized_block_header: if finalized_block_header.number == 0 { + chain_information::build::ConfigFinalizedBlockHeader::Genesis { + state_trie_root_hash: finalized_block_header.state_root, + } + } else { + chain_information::build::ConfigFinalizedBlockHeader::NonGenesis { + header: finalized_block_header, + known_finality: None, + } + }, + }, + ); + + // TODO: consider returning the runtime + + let chain_info = loop { + match chain_info_builder { + chain_information::build::ChainInformationBuild::Finished { + result: Ok(info), + .. + } => { + break info; } - } - (Some(slot_duration), None, None) => { - let slot_duration = expect_nz_u64(slot_duration)?; - let finalized_authorities_list = aura_finalized_authorities(&connection)?; - chain_information::ChainInformationConsensus::Aura { - finalized_authorities_list, - slot_duration, + chain_information::build::ChainInformationBuild::Finished { + result: Err(error), + .. + } => { + return Err(FinalizedAccessError::Access(AccessError::Corrupted( + CorruptedError::InvalidChainInformation( + InvalidChainInformationError::Build(error), + ), + ))) + } + chain_information::build::ChainInformationBuild::InProgress( + chain_information::build::InProgress::StorageGet(get), + ) => { + let value = finalized_block_storage_top_trie(&connection, &get.key_as_vec())?; + chain_info_builder = get.inject_value(value.map(iter::once)); + } + chain_information::build::ChainInformationBuild::InProgress( + chain_information::build::InProgress::NextKey(_), + ) => { + // TODO: + todo!() } - } - (None, None, None) => chain_information::ChainInformationConsensus::Unknown, - _ => { - return Err(FinalizedAccessError::Access(AccessError::Corrupted( - CorruptedError::ConsensusAlgorithmMix, - ))) } }; - match chain_information::ValidChainInformation::try_from( - chain_information::ChainInformation { - finalized_block_header, - consensus, - finality, - }, - ) { - Ok(ci) => Ok(ci), - Err(err) => Err(FinalizedAccessError::Access(AccessError::Corrupted( - CorruptedError::InvalidChainInformation(err), - ))), - } + Ok(chain_info) } /// Insert a new block in the database. @@ -528,11 +539,6 @@ impl SqliteFullDatabase { ))? }; - let block_header = block_header(&connection, &block_hash, self.block_number_bytes)? - .ok_or(SetFinalizedError::Access(AccessError::Corrupted( - CorruptedError::MissingBlockHeader, - )))?; - let mut statement = connection .prepare( "DELETE FROM finalized_storage_top_trie @@ -564,95 +570,6 @@ impl SqliteFullDatabase { .bind(1, &block_hash[..]) .unwrap(); statement.next().unwrap(); - - // TODO: the code below is very verbose and redundant with other similar code in smoldot ; could be improved - - if let Some((new_epoch, next_config)) = block_header.digest.babe_epoch_information() { - let epoch = meta_get_blob(&connection, "babe_finalized_next_epoch")?.unwrap(); // TODO: don't unwrap - let decoded_epoch = decode_babe_epoch_information(&epoch)?; - connection.execute(r#"INSERT OR REPLACE INTO meta(key, value_blob) SELECT "babe_finalized_epoch", value_blob FROM meta WHERE key = "babe_finalized_next_epoch""#).unwrap(); - - let slot_number = block_header - .digest - .babe_pre_runtime() - .unwrap() - .slot_number(); - let slots_per_epoch = - expect_nz_u64(meta_get_number(&connection, "babe_slots_per_epoch")?.unwrap())?; // TODO: don't unwrap - - let new_epoch = if let Some(next_config) = next_config { - chain_information::BabeEpochInformation { - epoch_index: decoded_epoch.epoch_index.checked_add(1).unwrap(), - start_slot_number: Some( - decoded_epoch - .start_slot_number - .unwrap_or(slot_number) - .checked_add(slots_per_epoch.get()) - .unwrap(), - ), - authorities: new_epoch.authorities.map(Into::into).collect(), - randomness: *new_epoch.randomness, - c: next_config.c, - allowed_slots: next_config.allowed_slots, - } - } else { - chain_information::BabeEpochInformation { - epoch_index: decoded_epoch.epoch_index.checked_add(1).unwrap(), - start_slot_number: Some( - decoded_epoch - .start_slot_number - .unwrap_or(slot_number) - .checked_add(slots_per_epoch.get()) - .unwrap(), - ), - authorities: new_epoch.authorities.map(Into::into).collect(), - randomness: *new_epoch.randomness, - c: decoded_epoch.c, - allowed_slots: decoded_epoch.allowed_slots, - } - }; - - meta_set_blob( - &connection, - "babe_finalized_next_epoch", - &encode_babe_epoch_information(From::from(&new_epoch)), - )?; - } - - // TODO: implement Aura - - if grandpa_authorities_set_id(&connection)?.is_some() { - for grandpa_digest_item in block_header.digest.logs().filter_map(|d| match d { - header::DigestItemRef::GrandpaConsensus(gp) => Some(gp), - _ => None, - }) { - match grandpa_digest_item { - header::GrandpaConsensusLogRef::ScheduledChange(change) => { - assert_eq!(change.delay, 0); // TODO: not implemented if != 0 - - connection - .execute("DELETE FROM grandpa_triggered_authorities") - .unwrap(); - - let mut statement = connection.prepare("INSERT INTO grandpa_triggered_authorities(idx, public_key, weight) VALUES(?, ?, ?)").unwrap(); - for (index, item) in change.next_authorities.enumerate() { - statement = statement - .bind(1, i64::try_from(index).unwrap()) - .unwrap() - .bind(2, &item.public_key[..]) - .unwrap() - .bind(3, i64::from_ne_bytes(item.weight.get().to_ne_bytes())) - .unwrap(); - statement.next().unwrap(); - statement = statement.reset().unwrap(); - } - - connection.execute(r#"UPDATE meta SET value_number = value_number + 1 WHERE key = "grandpa_authorities_set_id""#).unwrap(); - } - _ => {} // TODO: unimplemented - } - } - } } // It is possible that the best block has been pruned. @@ -721,26 +638,7 @@ impl SqliteFullDatabase { return Err(FinalizedAccessError::Obsolete); } - let mut statement = connection - .prepare(r#"SELECT value FROM finalized_storage_top_trie WHERE key = ?"#) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted) - .map_err(FinalizedAccessError::Access)? - .bind(1, key) - .unwrap(); - - if !matches!(statement.next().unwrap(), sqlite::State::Row) { - return Ok(None); - } - - let value = statement - .read::>(0) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted) - .map_err(FinalizedAccessError::Access)?; - Ok(Some(value)) + finalized_block_storage_top_trie(&connection, key).map_err(FinalizedAccessError::Access) } /// Returns the key in the storage of the finalized block that immediately follows the key @@ -799,33 +697,8 @@ impl SqliteFullDatabase { return Err(FinalizedAccessError::Obsolete); } - let mut statement = connection - .prepare(r#"SELECT key FROM finalized_storage_top_trie WHERE key >= ?"#) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted) - .map_err(FinalizedAccessError::Access)? - .bind(1, prefix) - .unwrap(); - - let mut out = Vec::new(); - while matches!(statement.next().unwrap(), sqlite::State::Row) { - let key = statement - .read::>(0) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted) - .map_err(FinalizedAccessError::Access)?; - - // TODO: hack because I don't know how to ask sqlite to do that - if !(key.starts_with(prefix)) { - continue; - } - - out.push(key); - } - - Ok(out) + finalized_block_storage_top_trie_keys(&connection, prefix) + .map_err(FinalizedAccessError::Access) } } @@ -911,7 +784,7 @@ pub enum CorruptedError { InvalidBlockHashLen, /// Values in the database are all well-formatted, but are incoherent. #[display(fmt = "Invalid chain information: {}", _0)] - InvalidChainInformation(chain_information::ValidityError), + InvalidChainInformation(InvalidChainInformationError), /// The parent of a block in the database couldn't be found in that same database. BrokenChain, /// Missing a key in the `meta` table. @@ -930,6 +803,22 @@ pub enum CorruptedError { Internal(InternalError), } +/// Error in the content of the database. +#[derive(Debug, derive_more::Display)] +pub enum InvalidChainInformationError { + /// Runtime code is missing from the finalized block storage. + MissingRuntimeCode, + /// Heap pages is in an invalid format. + #[display(fmt = "Invalid heap pages format: {}", _0)] + InvalidHeapPages(executor::InvalidHeapPagesError), + /// Failed to build the runtime. + #[display(fmt = "Failed to build runtime: {}", _0)] + InvalidRuntime(executor::host::NewErr), + /// Error while building the chain information from the runtime. + #[display(fmt = "{}", _0)] + Build(chain_information::build::Error), +} + /// Low-level database error, such as an error while accessing the file system. #[derive(Debug, derive_more::Display)] pub struct InternalError(sqlite::Error); @@ -1125,224 +1014,77 @@ fn block_header( } } -fn flush(database: &sqlite::Connection) -> Result<(), AccessError> { - database.execute("COMMIT; BEGIN TRANSACTION;").unwrap(); - Ok(()) -} - -fn purge_block(database: &sqlite::Connection, hash: &[u8; 32]) -> Result<(), AccessError> { - let mut statement = database - .prepare( - "DELETE FROM non_finalized_changes WHERE hash = :hash; - DELETE FROM blocks_body WHERE hash = :hash; - DELETE FROM blocks WHERE hash = :hash;", - ) - .unwrap() - .bind_by_name(":hash", &hash[..]) - .unwrap(); - statement.next().unwrap(); - - Ok(()) -} - -fn grandpa_authorities_set_id(database: &sqlite::Connection) -> Result, AccessError> { - meta_get_number(database, "grandpa_authorities_set_id") -} - -fn grandpa_finalized_triggered_authorities( +fn finalized_block_storage_top_trie( database: &sqlite::Connection, -) -> Result, AccessError> { + key: &[u8], +) -> Result>, AccessError> { let mut statement = database - .prepare(r#"SELECT public_key, weight FROM grandpa_triggered_authorities ORDER BY idx ASC"#) + .prepare(r#"SELECT value FROM finalized_storage_top_trie WHERE key = ?"#) .map_err(InternalError) .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted)?; - - let mut out = Vec::new(); - while matches!(statement.next().unwrap(), sqlite::State::Row) { - let public_key = statement - .read::>(0) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted)?; - - let public_key = <[u8; 32]>::try_from(&public_key[..]) - .map_err(|_| CorruptedError::InvalidBlockHashLen) - .map_err(AccessError::Corrupted)?; - - let weight = statement - .read::(1) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted)?; - - let weight = NonZeroU64::new(u64::from_ne_bytes(weight.to_ne_bytes())) - .ok_or(CorruptedError::InvalidNumber) - .map_err(AccessError::Corrupted)?; - out.push(header::GrandpaAuthority { public_key, weight }); - } - - Ok(out) -} - -fn grandpa_finalized_scheduled_change( - database: &sqlite::Connection, -) -> Result)>, AccessError> { - if let Some(height) = meta_get_number(database, "grandpa_scheduled_target")? { - // TODO: duplicated from above except different table name - let mut statement = database - .prepare( - r#"SELECT public_key, weight FROM grandpa_scheduled_authorities ORDER BY idx ASC"#, - ) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted)?; - - let mut out = Vec::new(); - while matches!(statement.next().unwrap(), sqlite::State::Row) { - let public_key = statement - .read::>(0) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted)?; - - let public_key = <[u8; 32]>::try_from(&public_key[..]) - .map_err(|_| CorruptedError::InvalidBlockHashLen) - .map_err(AccessError::Corrupted)?; - - let weight = statement - .read::(1) - .map_err(InternalError) - .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted)?; - - let weight = NonZeroU64::new(u64::from_ne_bytes(weight.to_ne_bytes())) - .ok_or(CorruptedError::InvalidNumber) - .map_err(AccessError::Corrupted)?; - out.push(header::GrandpaAuthority { public_key, weight }); - } + .map_err(AccessError::Corrupted)? + .bind(1, key) + .unwrap(); - Ok(Some((height, out))) - } else { - Ok(None) + if !matches!(statement.next().unwrap(), sqlite::State::Row) { + return Ok(None); } -} -fn expect_nz_u64(value: u64) -> Result { - NonZeroU64::new(value) - .ok_or(CorruptedError::InvalidNumber) - .map_err(AccessError::Corrupted) + let value = statement + .read::>(0) + .map_err(InternalError) + .map_err(CorruptedError::Internal) + .map_err(AccessError::Corrupted)?; + Ok(Some(value)) } -fn aura_finalized_authorities( +fn finalized_block_storage_top_trie_keys( database: &sqlite::Connection, -) -> Result, AccessError> { + prefix: &[u8], +) -> Result>, AccessError> { let mut statement = database - .prepare(r#"SELECT public_key FROM aura_finalized_authorities ORDER BY idx ASC"#) + .prepare(r#"SELECT key FROM finalized_storage_top_trie WHERE key >= ?"#) .map_err(InternalError) .map_err(CorruptedError::Internal) - .map_err(AccessError::Corrupted)?; + .map_err(AccessError::Corrupted)? + .bind(1, prefix) + .unwrap(); let mut out = Vec::new(); while matches!(statement.next().unwrap(), sqlite::State::Row) { - let public_key = statement + let key = statement .read::>(0) .map_err(InternalError) .map_err(CorruptedError::Internal) .map_err(AccessError::Corrupted)?; - let public_key = <[u8; 32]>::try_from(&public_key[..]) - .map_err(|_| CorruptedError::InvalidBlockHashLen) - .map_err(AccessError::Corrupted)?; + // TODO: hack because I don't know how to ask sqlite to do that + if !(key.starts_with(prefix)) { + continue; + } - out.push(header::AuraAuthority { public_key }); + out.push(key); } Ok(out) } -fn encode_babe_epoch_information(info: chain_information::BabeEpochInformationRef) -> Vec { - let mut out = Vec::with_capacity(69 + info.authorities.len() * 40); - out.extend_from_slice(&info.epoch_index.to_le_bytes()); - if let Some(start_slot_number) = info.start_slot_number { - out.extend_from_slice(&[1]); - out.extend_from_slice(&start_slot_number.to_le_bytes()); - } else { - out.extend_from_slice(&[0]); - } - out.extend_from_slice(util::encode_scale_compact_usize(info.authorities.len()).as_ref()); - for authority in info.authorities { - out.extend_from_slice(authority.public_key); - out.extend_from_slice(&authority.weight.to_le_bytes()); - } - out.extend_from_slice(info.randomness); - out.extend_from_slice(&info.c.0.to_le_bytes()); - out.extend_from_slice(&info.c.1.to_le_bytes()); - out.extend_from_slice(match info.allowed_slots { - header::BabeAllowedSlots::PrimarySlots => &[0], - header::BabeAllowedSlots::PrimaryAndSecondaryPlainSlots => &[1], - header::BabeAllowedSlots::PrimaryAndSecondaryVrfSlots => &[2], - }); - out +fn flush(database: &sqlite::Connection) -> Result<(), AccessError> { + database.execute("COMMIT; BEGIN TRANSACTION;").unwrap(); + Ok(()) } -fn decode_babe_epoch_information( - value: &[u8], -) -> Result { - let result = nom::combinator::all_consuming(nom::combinator::map( - nom::sequence::tuple(( - nom::number::complete::le_u64, - util::nom_option_decode(nom::number::complete::le_u64), - nom::combinator::flat_map(crate::util::nom_scale_compact_usize, |num_elems| { - nom::multi::many_m_n( - num_elems, - num_elems, - nom::combinator::map( - nom::sequence::tuple(( - nom::bytes::complete::take(32u32), - nom::number::complete::le_u64, - )), - move |(public_key, weight)| header::BabeAuthority { - public_key: TryFrom::try_from(public_key).unwrap(), - weight, - }, - ), - ) - }), - nom::bytes::complete::take(32u32), - nom::sequence::tuple((nom::number::complete::le_u64, nom::number::complete::le_u64)), - nom::branch::alt(( - nom::combinator::map(nom::bytes::complete::tag(&[0]), |_| { - header::BabeAllowedSlots::PrimarySlots - }), - nom::combinator::map(nom::bytes::complete::tag(&[1]), |_| { - header::BabeAllowedSlots::PrimaryAndSecondaryPlainSlots - }), - nom::combinator::map(nom::bytes::complete::tag(&[2]), |_| { - header::BabeAllowedSlots::PrimaryAndSecondaryVrfSlots - }), - )), - )), - |(epoch_index, start_slot_number, authorities, randomness, c, allowed_slots)| { - chain_information::BabeEpochInformation { - epoch_index, - start_slot_number, - authorities, - randomness: TryFrom::try_from(randomness).unwrap(), - c, - allowed_slots, - } - }, - ))(value) - .map(|(_, v)| v) - .map_err(|_: nom::Err>| ()); - - let result = match result { - Ok(r) if r.validate().is_ok() => Ok(r), - Ok(_) | Err(()) => Err(()), - }; +fn purge_block(database: &sqlite::Connection, hash: &[u8; 32]) -> Result<(), AccessError> { + let mut statement = database + .prepare( + "DELETE FROM non_finalized_changes WHERE hash = :hash; + DELETE FROM blocks_body WHERE hash = :hash; + DELETE FROM blocks WHERE hash = :hash;", + ) + .unwrap() + .bind_by_name(":hash", &hash[..]) + .unwrap(); + statement.next().unwrap(); - result - .map_err(|()| CorruptedError::InvalidBabeEpochInformation) - .map_err(AccessError::Corrupted) + Ok(()) } diff --git a/src/database/full_sqlite/open.rs b/src/database/full_sqlite/open.rs index 99a5876db2..d61f1c8399 100644 --- a/src/database/full_sqlite/open.rs +++ b/src/database/full_sqlite/open.rs @@ -19,8 +19,8 @@ //! //! Contains everything related to the opening and initialization of the database. -use super::{encode_babe_epoch_information, AccessError, SqliteFullDatabase}; -use crate::chain::chain_information; +use super::{AccessError, SqliteFullDatabase}; +use crate::header; use std::{fs, path::Path}; @@ -74,31 +74,6 @@ Keys in that table: - `finalized` (number): Height of the finalized block, as a 64bits big endian number. - - `grandpa_authorities_set_id` (number): Id of the authorities set that must finalize the block - right after the finalized block. The value is 0 at the genesis block, and increased by 1 at every - authorities change. Missing if and only if the chain doesn't use Grandpa. - - - `grandpa_scheduled_target` (number): Height of the block where the authorities found in - `grandpa_scheduled_authorities` will be triggered. Blocks whose height is strictly higher than - this value must be finalized using the new set of authorities. This authority change must have - been scheduled in or before the finalized block. Missing if no change is scheduled or if the - chain doesn't use Grandpa. - - - `aura_slot_duration` (number): Duration of an Aura slot in milliseconds. Missing if and only if - the chain doesn't use Aura. - - - `babe_slots_per_epoch` (number): Number of slots per Babe epoch. Missing if and only if the - chain doesn't use Babe. - - - `babe_finalized_epoch` (blob): SCALE encoding of a structure that contains the information - about the Babe epoch used for the finalized block. Missing if and only if the finalized - block is block #0 or the chain doesn't use Babe. - - - `babe_finalized_next_epoch` (blob): SCALE encoding of a structure that contains the information - about the Babe epoch that follows the one described by `babe_finalized_epoch`. If the - finalized block is block #0, then this contains information about epoch #0. Missing if and - only if the chain doesn't use Babe. - */ CREATE TABLE IF NOT EXISTS meta( key STRING NOT NULL PRIMARY KEY, @@ -159,38 +134,6 @@ CREATE TABLE IF NOT EXISTS non_finalized_changes( CHECK(length(hash) == 32), FOREIGN KEY (hash) REFERENCES blocks(hash) ON UPDATE CASCADE ON DELETE CASCADE ); - -/* -List of public keys and weights of the GrandPa authorities that must finalize the children of the -finalized block. Empty if the chain doesn't use Grandpa. -*/ -CREATE TABLE IF NOT EXISTS grandpa_triggered_authorities( - idx INTEGER NOT NULL PRIMARY KEY, - public_key BLOB NOT NULL, - weight INTEGER NOT NULL, - CHECK(length(public_key) == 32) -); - -/* -List of public keys and weights of the GrandPa authorities that will be triggered at the block -found in `grandpa_scheduled_target` (see `meta`). Empty if the chain doesn't use Grandpa. -*/ -CREATE TABLE IF NOT EXISTS grandpa_scheduled_authorities( - idx INTEGER NOT NULL PRIMARY KEY, - public_key BLOB NOT NULL, - weight INTEGER NOT NULL, - CHECK(length(public_key) == 32) -); - -/* -List of public keys of the Aura authorities that must author the children of the finalized block. -*/ -CREATE TABLE IF NOT EXISTS aura_finalized_authorities( - idx INTEGER NOT NULL PRIMARY KEY, - public_key BLOB NOT NULL, - CHECK(length(public_key) == 32) -); - "#, ) .map_err(super::InternalError)?; @@ -269,19 +212,14 @@ impl DatabaseEmpty { /// Must also pass the body, justification, and state of the storage of the finalized block. pub fn initialize<'a>( self, - chain_information: impl Into>, + finalized_block_header: header::HeaderRef, finalized_block_body: impl ExactSizeIterator, finalized_block_justification: Option>, finalized_block_storage_top_trie_entries: impl Iterator + Clone, ) -> Result { - let chain_information = chain_information.into(); - - let finalized_block_hash = chain_information - .finalized_block_header - .hash(self.block_number_bytes); + let finalized_block_hash = finalized_block_header.hash(self.block_number_bytes); - let scale_encoded_finalized_block_header = chain_information - .finalized_block_header + let scale_encoded_finalized_block_header = finalized_block_header .scale_encoding(self.block_number_bytes) .fold(Vec::new(), |mut a, b| { a.extend_from_slice(b.as_ref()); @@ -309,10 +247,7 @@ impl DatabaseEmpty { .unwrap() .bind(1, &finalized_block_hash[..]) .unwrap() - .bind( - 2, - i64::try_from(chain_information.finalized_block_header.number).unwrap(), - ) + .bind(2, i64::try_from(finalized_block_header.number).unwrap()) .unwrap() .bind(3, &scale_encoded_finalized_block_header[..]) .unwrap(); @@ -345,114 +280,7 @@ impl DatabaseEmpty { } super::meta_set_blob(&self.database, "best", &finalized_block_hash[..]).unwrap(); - super::meta_set_number( - &self.database, - "finalized", - chain_information.finalized_block_header.number, - ) - .unwrap(); - - match &chain_information.finality { - chain_information::ChainInformationFinalityRef::Outsourced => {} - chain_information::ChainInformationFinalityRef::Grandpa { - finalized_triggered_authorities, - after_finalized_block_authorities_set_id, - finalized_scheduled_change, - } => { - super::meta_set_number( - &self.database, - "grandpa_authorities_set_id", - *after_finalized_block_authorities_set_id, - ) - .unwrap(); - - let mut statement = self - .database - .prepare("INSERT INTO grandpa_triggered_authorities(idx, public_key, weight) VALUES(?, ?, ?)") - .unwrap(); - for (index, item) in finalized_triggered_authorities.iter().enumerate() { - statement = statement - .bind(1, i64::try_from(index).unwrap()) - .unwrap() - .bind(2, &item.public_key[..]) - .unwrap() - .bind(3, i64::from_ne_bytes(item.weight.get().to_ne_bytes())) - .unwrap(); - statement.next().unwrap(); - statement = statement.reset().unwrap(); - } - - if let Some((height, list)) = finalized_scheduled_change { - super::meta_set_number(&self.database, "grandpa_scheduled_target", *height) - .unwrap(); - - let mut statement = self - .database - .prepare("INSERT INTO grandpa_scheduled_authorities(idx, public_key, weight) VALUES(?, ?, ?)") - .unwrap(); - for (index, item) in list.iter().enumerate() { - statement = statement - .bind(1, i64::try_from(index).unwrap()) - .unwrap() - .bind(2, &item.public_key[..]) - .unwrap() - .bind(3, i64::from_ne_bytes(item.weight.get().to_ne_bytes())) - .unwrap(); - statement.next().unwrap(); - statement = statement.reset().unwrap(); - } - } - } - } - - match &chain_information.consensus { - chain_information::ChainInformationConsensusRef::Unknown => {} - chain_information::ChainInformationConsensusRef::Aura { - finalized_authorities_list, - slot_duration, - } => { - super::meta_set_number(&self.database, "aura_slot_duration", slot_duration.get()) - .unwrap(); - - let mut statement = self - .database - .prepare("INSERT INTO aura_finalized_authorities(idx, public_key) VALUES(?, ?)") - .unwrap(); - for (index, item) in finalized_authorities_list.clone().enumerate() { - statement = statement - .bind(1, i64::try_from(index).unwrap()) - .unwrap() - .bind(2, &item.public_key[..]) - .unwrap(); - statement.next().unwrap(); - statement = statement.reset().unwrap(); - } - } - chain_information::ChainInformationConsensusRef::Babe { - slots_per_epoch, - finalized_next_epoch_transition, - finalized_block_epoch_information, - } => { - super::meta_set_number( - &self.database, - "babe_slots_per_epoch", - slots_per_epoch.get(), - ) - .unwrap(); - super::meta_set_blob( - &self.database, - "babe_finalized_next_epoch", - &encode_babe_epoch_information(finalized_next_epoch_transition.clone())[..], - ) - .unwrap(); - - if let Some(finalized_block_epoch_information) = finalized_block_epoch_information { - super::meta_set_blob(&self.database, "babe_finalized_epoch", &encode_babe_epoch_information( - finalized_block_epoch_information.clone(), - )[..]).unwrap(); - } - } - } + super::meta_set_number(&self.database, "finalized", finalized_block_header.number).unwrap(); super::flush(&self.database)?;