use crate::util;
use alloc::{borrow::ToOwned as _, vec::Vec};
use core::{iter, num::NonZero};
mod tests;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TransactionSource {
InBlock,
Local,
External,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ValidTransaction {
pub priority: u64,
pub requires: Vec<Vec<u8>>,
pub provides: Vec<Vec<u8>>,
pub longevity: NonZero<u64>,
pub propagate: bool,
}
#[derive(Debug, derive_more::Display, derive_more::Error, Clone, PartialEq, Eq)]
pub enum InvalidTransaction {
Call,
Payment,
Future,
Stale,
BadProof,
AncientBirthBlock,
ExhaustsResources,
#[display("Other reason (code: {_0})")]
Custom(#[error(not(source))] u8),
BadMandatory,
MandatoryDispatch,
}
#[derive(Debug, derive_more::Display, derive_more::Error, Clone, PartialEq, Eq)]
pub enum UnknownTransaction {
CannotLookup,
NoUnsignedValidator,
#[display("Other reason (code: {_0})")]
Custom(#[error(not(source))] u8),
}
#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
pub struct DecodeError();
#[derive(Debug, derive_more::Display, derive_more::Error, Clone, PartialEq, Eq)]
pub enum TransactionValidityError {
#[display("Invalid transaction: {_0}")]
Invalid(InvalidTransaction),
#[display("Transaction validity couldn't be determined: {_0}")]
Unknown(UnknownTransaction),
}
pub fn validate_transaction_runtime_parameters_v2<'a>(
scale_encoded_transaction: impl Iterator<Item = impl AsRef<[u8]> + 'a> + Clone + 'a,
source: TransactionSource,
) -> impl Iterator<Item = impl AsRef<[u8]>> + Clone {
validate_transaction_runtime_parameters_inner(scale_encoded_transaction, source, &[])
}
pub fn validate_transaction_runtime_parameters_v3<'a>(
scale_encoded_transaction: impl Iterator<Item = impl AsRef<[u8]> + 'a> + Clone + 'a,
source: TransactionSource,
block_hash: &'a [u8; 32],
) -> impl Iterator<Item = impl AsRef<[u8]>> + Clone {
validate_transaction_runtime_parameters_inner(scale_encoded_transaction, source, block_hash)
}
fn validate_transaction_runtime_parameters_inner<'a>(
scale_encoded_transaction: impl Iterator<Item = impl AsRef<[u8]> + 'a> + Clone + 'a,
source: TransactionSource,
block_hash: &'a [u8],
) -> impl Iterator<Item = impl AsRef<[u8]>> + Clone {
let source = match source {
TransactionSource::InBlock => &[0],
TransactionSource::Local => &[1],
TransactionSource::External => &[2],
};
iter::once(source)
.map(either::Left)
.chain(
scale_encoded_transaction
.map(either::Right)
.map(either::Right),
)
.chain(iter::once(block_hash).map(either::Left).map(either::Right))
}
pub const VALIDATION_FUNCTION_NAME: &str = "TaggedTransactionQueue_validate_transaction";
pub fn decode_validate_transaction_return_value(
scale_encoded: &[u8],
) -> Result<Result<ValidTransaction, TransactionValidityError>, DecodeError> {
match nom::Parser::parse(
&mut nom::combinator::all_consuming(transaction_validity),
scale_encoded,
) {
Ok((_, data)) => Ok(data),
Err(_) => Err(DecodeError()),
}
}
fn transaction_validity(
bytes: &[u8],
) -> nom::IResult<&[u8], Result<ValidTransaction, TransactionValidityError>> {
nom::Parser::parse(
&mut nom::error::context(
"transaction validity",
nom::branch::alt((
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[0][..]),
valid_transaction,
),
Ok,
),
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[1][..]),
transaction_validity_error,
),
Err,
),
)),
),
bytes,
)
}
fn valid_transaction(bytes: &[u8]) -> nom::IResult<&[u8], ValidTransaction> {
nom::Parser::parse(
&mut nom::error::context(
"valid transaction",
nom::combinator::map(
(
nom::number::streaming::le_u64,
tags,
nom::combinator::verify(tags, |provides: &Vec<Vec<u8>>| !provides.is_empty()),
nom::combinator::map_opt(nom::number::streaming::le_u64, NonZero::<u64>::new),
util::nom_bool_decode,
),
|(priority, requires, provides, longevity, propagate)| ValidTransaction {
priority,
requires,
provides,
longevity,
propagate,
},
),
),
bytes,
)
}
fn transaction_validity_error(bytes: &[u8]) -> nom::IResult<&[u8], TransactionValidityError> {
nom::Parser::parse(
&mut nom::error::context(
"transaction validity error",
nom::branch::alt((
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[0][..]),
invalid_transaction,
),
TransactionValidityError::Invalid,
),
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[1][..]),
unknown_transaction,
),
TransactionValidityError::Unknown,
),
)),
),
bytes,
)
}
fn invalid_transaction(bytes: &[u8]) -> nom::IResult<&[u8], InvalidTransaction> {
nom::Parser::parse(
&mut nom::error::context(
"invalid transaction",
nom::branch::alt((
nom::combinator::map(nom::bytes::streaming::tag(&[0][..]), |_| {
InvalidTransaction::Call
}),
nom::combinator::map(nom::bytes::streaming::tag(&[1][..]), |_| {
InvalidTransaction::Payment
}),
nom::combinator::map(nom::bytes::streaming::tag(&[2][..]), |_| {
InvalidTransaction::Future
}),
nom::combinator::map(nom::bytes::streaming::tag(&[3][..]), |_| {
InvalidTransaction::Stale
}),
nom::combinator::map(nom::bytes::streaming::tag(&[4][..]), |_| {
InvalidTransaction::BadProof
}),
nom::combinator::map(nom::bytes::streaming::tag(&[5][..]), |_| {
InvalidTransaction::AncientBirthBlock
}),
nom::combinator::map(nom::bytes::streaming::tag(&[6][..]), |_| {
InvalidTransaction::ExhaustsResources
}),
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[7][..]),
nom::bytes::streaming::take(1u32),
),
|n: &[u8]| InvalidTransaction::Custom(n[0]),
),
nom::combinator::map(nom::bytes::streaming::tag(&[8][..]), |_| {
InvalidTransaction::BadMandatory
}),
nom::combinator::map(nom::bytes::streaming::tag(&[9][..]), |_| {
InvalidTransaction::MandatoryDispatch
}),
)),
),
bytes,
)
}
fn unknown_transaction(bytes: &[u8]) -> nom::IResult<&[u8], UnknownTransaction> {
nom::Parser::parse(
&mut nom::error::context(
"unknown transaction",
nom::branch::alt((
nom::combinator::map(nom::bytes::streaming::tag(&[0][..]), |_| {
UnknownTransaction::CannotLookup
}),
nom::combinator::map(nom::bytes::streaming::tag(&[1][..]), |_| {
UnknownTransaction::NoUnsignedValidator
}),
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[2][..]),
nom::bytes::streaming::take(1u32),
),
|n: &[u8]| UnknownTransaction::Custom(n[0]),
),
)),
),
bytes,
)
}
fn tags(bytes: &[u8]) -> nom::IResult<&[u8], Vec<Vec<u8>>> {
nom::Parser::parse(
&mut 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::multi::length_data(crate::util::nom_scale_compact_usize),
|tag| tag.to_owned(),
),
)
}),
bytes,
)
}