use crate::{header, util, verify::inherents};
use alloc::vec::Vec;
use core::{iter, time::Duration};
pub const EXECUTE_BLOCK_FUNCTION_NAME: &str = "Core_execute_block";
pub fn execute_block_parameter(
block_header: &[u8],
block_number_bytes: usize,
block_body: impl ExactSizeIterator<Item = impl AsRef<[u8]> + Clone> + Clone,
) -> Result<impl Iterator<Item = impl AsRef<[u8]> + Clone> + Clone, ExecuteBlockParameterError> {
let mut unsealed_header = match header::decode(block_header, block_number_bytes) {
Ok(h) => h,
Err(err) => return Err(ExecuteBlockParameterError::InvalidHeader(err)),
};
let _seal_log = unsealed_header.digest.pop_seal();
let encoded_body_len = util::encode_scale_compact_usize(block_body.len());
Ok(unsealed_header
.scale_encoding(block_number_bytes)
.map(|b| either::Right(either::Left(b)))
.chain(iter::once(either::Right(either::Right(encoded_body_len))))
.chain(block_body.map(either::Left)))
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub enum ExecuteBlockParameterError {
InvalidHeader(header::Error),
}
pub fn check_execute_block_output(output: &[u8]) -> Result<(), ExecuteBlockOutputError> {
if !output.is_empty() {
return Err(ExecuteBlockOutputError::NotEmpty);
}
Ok(())
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub enum ExecuteBlockOutputError {
NotEmpty,
}
pub const CHECK_INHERENTS_FUNCTION_NAME: &str = "BlockBuilder_check_inherents";
pub fn check_inherents_parameter(
block_header: &[u8],
block_number_bytes: usize,
block_body: impl ExactSizeIterator<Item = impl AsRef<[u8]> + Clone> + Clone,
now_from_unix_epoch: Duration,
) -> Result<impl Iterator<Item = impl AsRef<[u8]> + Clone> + Clone, ExecuteBlockParameterError> {
let execute_block_parameter =
execute_block_parameter(block_header, block_number_bytes, block_body)?;
let inherent_data = inherents::InherentData {
timestamp: u64::try_from(now_from_unix_epoch.as_millis()).unwrap_or(u64::MAX),
};
let list = inherent_data.into_raw_list();
let len = util::encode_scale_compact_usize(list.len());
let encoded_list = list.flat_map(|(id, value)| {
let value_len = util::encode_scale_compact_usize(value.as_ref().len());
let value_and_len = iter::once(value_len)
.map(either::Left)
.chain(iter::once(value).map(either::Right));
iter::once(id)
.map(either::Left)
.chain(value_and_len.map(either::Right))
});
Ok([
either::Left(execute_block_parameter.map(either::Left)),
either::Right(either::Left(iter::once(either::Right(either::Left(len))))),
either::Right(either::Right(
encoded_list.map(either::Right).map(either::Right),
)),
]
.into_iter()
.flatten())
}
pub fn check_check_inherents_output(output: &[u8]) -> Result<(), InherentsOutputError> {
let parser = nom::sequence::preceded(
(crate::util::nom_bool_decode, crate::util::nom_bool_decode),
nom::combinator::flat_map(crate::util::nom_scale_compact_usize, |num_elems| {
nom::multi::fold_many_m_n(
num_elems,
num_elems,
(
nom::combinator::map(nom::bytes::streaming::take(8u8), |b| {
<[u8; 8]>::try_from(b).unwrap()
}),
crate::util::nom_bytes_decode,
),
Vec::new,
|mut errors, (module, error)| {
if module != *b"auraslot" && module != *b"babeslot" {
errors.push((module, error.to_vec()));
}
errors
},
)
}),
);
match nom::Parser::parse(
&mut nom::combinator::all_consuming::<_, nom::error::Error<&[u8]>, _>(parser),
output,
) {
Err(_err) => Err(InherentsOutputError::ParseFailure),
Ok((_, errors)) => {
if errors.is_empty() {
Ok(())
} else {
Err(InherentsOutputError::Error { errors })
}
}
}
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
pub enum InherentsOutputError {
#[display("Runtime has returned some errors when verifying inherents: {errors:?}")]
Error {
errors: Vec<([u8; 8], Vec<u8>)>,
},
ParseFailure,
}