Round out the runtime

Ensures the block's size limit is respected.

Defines a policy for weights. While I'm unsure I want to commit to this
forever, I do want to acknowledge it's valid and well-defined.

Cleans up the `serai-runtime` crate a bit with further modules in the `wasm`
folder.
This commit is contained in:
Luke Parker
2025-12-02 21:04:47 -05:00
parent 98044f93b1
commit ff95c58341
10 changed files with 347 additions and 325 deletions

View File

@@ -63,6 +63,11 @@ pub struct HeaderV1 {
pub consensus_commitment: [u8; 32],
}
impl HeaderV1 {
/// The size of a serialized V1 header.
pub const SIZE: usize = 8 + 32 + 8 + 32 + 32 + 32;
}
/// A header for a block.
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
pub enum Header {
@@ -71,6 +76,9 @@ pub enum Header {
}
impl Header {
/// The size of a serialized header.
pub const SIZE: usize = 1 + HeaderV1::SIZE;
/// Get the hash of the header.
pub fn number(&self) -> u64 {
match self {
@@ -109,8 +117,8 @@ impl Header {
/// A block.
///
/// This does not guarantee consistency. The header's `transactions_root` may not match the
/// contained transactions.
/// This does not guarantee consistency nor validity. The header's `transactions_root` may not
/// match the contained transactions, among other ill effects.
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
pub struct Block {
/// The block's header.
@@ -119,6 +127,13 @@ pub struct Block {
pub transactions: Vec<Transaction>,
}
impl Block {
/// The size limit for a block.
///
/// This is not enforced upon deserialization. Be careful accordingly.
pub const SIZE_LIMIT: usize = 1024 * 1024;
}
#[cfg(feature = "substrate")]
mod substrate {
use core::fmt::Debug;
@@ -133,7 +148,7 @@ mod substrate {
use super::*;
// Add `serde` implementations which treat self as a `Vec<u8>`
// Add `serde` implementations which treat `self` as a `Vec<u8>`
impl sp_core::serde::Serialize for Transaction {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where

View File

@@ -279,12 +279,13 @@ mod substrate {
/// The implicit context to verify transactions with.
fn implicit_context() -> ImplicitContext;
/// The size of the current block.
fn current_block_size(&self) -> usize;
/// If a block is present in the blockchain.
fn block_is_present_in_blockchain(&self, hash: &BlockHash) -> bool;
/// The time embedded into the current block.
///
/// Returns `None` if the time has yet to be set.
fn current_time(&self) -> Option<u64>;
fn current_time(&self) -> u64;
/// Get the next nonce for an account.
fn next_nonce(&self, signer: &SeraiAddress) -> u32;
/// If the signer can pay the SRI fee.
@@ -295,7 +296,7 @@ mod substrate {
) -> Result<(), TransactionValidityError>;
/// Begin execution of a transaction.
fn start_transaction(&self);
fn start_transaction(&self, len: usize);
/// Consume the next nonce for an account.
///
/// This MUST NOT be called if the next nonce is `u32::MAX`. The caller MAY panic in that case.
@@ -390,9 +391,14 @@ mod substrate {
impl<Context: TransactionContext> TransactionWithContext<Context> {
fn validate_except_fee<V: ValidateUnsigned<Call = Context::RuntimeCall>>(
&self,
len: usize,
source: TransactionSource,
mempool_priority_if_signed: u64,
) -> TransactionValidity {
if self.1.current_block_size().saturating_add(len) > crate::Block::SIZE_LIMIT {
Err(TransactionValidityError::Invalid(InvalidTransaction::ExhaustsResources))?;
}
match &self.0 {
Transaction::Unsigned { call } => {
let ValidTransaction { priority: _, requires, provides, longevity: _, propagate: _ } =
@@ -417,13 +423,8 @@ mod substrate {
Err(TransactionValidityError::Unknown(UnknownTransaction::CannotLookup))?;
}
if let Some(include_by) = *include_by {
if let Some(current_time) = self.1.current_time() {
if current_time >= u64::from(include_by) {
// Since this transaction has a time bound which has passed, error
Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))?;
}
} else {
// Since this transaction has a time bound, yet we don't know the time, error
if self.1.current_time() >= u64::from(include_by) {
// Since this transaction has a time bound which has passed, error
Err(TransactionValidityError::Invalid(InvalidTransaction::Stale))?;
}
}
@@ -471,7 +472,7 @@ mod substrate {
&self,
source: TransactionSource,
info: &DispatchInfo,
_len: usize,
len: usize,
) -> TransactionValidity {
let mempool_priority_if_signed = match &self.0 {
Transaction::Unsigned { .. } => {
@@ -493,19 +494,19 @@ mod substrate {
}
}
};
self.validate_except_fee::<V>(source, mempool_priority_if_signed)
self.validate_except_fee::<V>(len, source, mempool_priority_if_signed)
}
fn apply<V: ValidateUnsigned<Call = Context::RuntimeCall>>(
self,
_info: &DispatchInfo,
_len: usize,
len: usize,
) -> sp_runtime::ApplyExtrinsicResultWithInfo<PostDispatchInfo> {
// We use 0 for the mempool priority, as this is no longer in the mempool so it's irrelevant
self.validate_except_fee::<V>(TransactionSource::InBlock, 0)?;
self.validate_except_fee::<V>(len, TransactionSource::InBlock, 0)?;
// Start the transaction
self.1.start_transaction();
self.1.start_transaction(len);
let transaction_hash = self.0.hash();