Skip to content

Commit

Permalink
Cleaner separation of Verifier / Constraint Cheker duties (#188)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshOrndorff authored Mar 20, 2024
1 parent 8a2f661 commit 9a18761
Show file tree
Hide file tree
Showing 20 changed files with 409 additions and 322 deletions.
113 changes: 52 additions & 61 deletions tuxedo-core/aggregator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,19 @@ pub fn tuxedo_verifier(_: TokenStream, body: TokenStream) -> TokenStream {
let mut redeemer_type_name = outer_type.to_string();
redeemer_type_name.push_str("Redeemer");
let redeemer_type = Ident::new(&redeemer_type_name, outer_type.span());
let type_for_new_unspendable = inner_types
.clone()
.next()
.expect("At least one verifier variant expected.");

// TODO there must be a better way to do this, right?
let inner_types2 = inner_types.clone();
let variants2 = variants.clone();
let variants3 = variants.clone();
let variant_for_new_unspendable = variants
.clone()
.next()
.expect("At least one verifier variant expected.");

let as_variants = variants.clone().map(|v| {
let s = format!("as_{}", v);
Expand Down Expand Up @@ -160,6 +168,14 @@ pub fn tuxedo_verifier(_: TokenStream, body: TokenStream) -> TokenStream {
)*
}
}

// The aggregation macro assumes that the first variant is able to produce a new unspendable instance.
// In the future this could be made nicer (but maybe not worth the complexity) by allowing an additional
// annotation to the one that can be used as unspendable eg `#[unspendable]`
// If this ever becomes a challenge just add an explicit `Unspendable` variant first.
fn new_unspendable() -> Option<Self> {
#type_for_new_unspendable::new_unspendable().map(|inner| Self::#variant_for_new_unspendable(inner))
}
}
};
output.into()
Expand All @@ -173,9 +189,8 @@ pub fn tuxedo_verifier(_: TokenStream, body: TokenStream) -> TokenStream {
/// just like this original enum. however, the contained values in the error enum are of the corresponding types
/// for the inner constraint checker.
#[proc_macro_attribute]
pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> TokenStream {
pub fn tuxedo_constraint_checker(_attrs: TokenStream, body: TokenStream) -> TokenStream {
let ast = parse_macro_input!(body as ItemEnum);
let verifier = parse_macro_input!(attrs as Ident);
let original_code = ast.clone();

let outer_type = ast.ident;
Expand Down Expand Up @@ -204,23 +219,16 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token
error_type_name.push_str("Error");
let error_type = Ident::new(&error_type_name, outer_type.span());

let mut inherent_hooks_name = outer_type.to_string();
inherent_hooks_name.push_str("InherentHooks");
let inherent_hooks = Ident::new(&inherent_hooks_name, outer_type.span());

let vis = ast.vis;

// TODO there must be a better way to do this, right?
let inner_types2 = inner_types.clone();
let inner_types3 = inner_types.clone();
let inner_types4 = inner_types.clone();
let inner_types6 = inner_types.clone();
let inner_types7 = inner_types.clone();
let variants2 = variants.clone();
let variants3 = variants.clone();
let variants4 = variants.clone();
let variants5 = variants.clone();
let variants6 = variants.clone();

let output = quote! {
// Preserve the original enum, and write the From impls
Expand All @@ -235,27 +243,39 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token
#[derive(Debug)]
#vis enum #error_type {
#(
#variants(<#inner_types as tuxedo_core::ConstraintChecker<#verifier>>::Error),
#variants(<#inner_types as tuxedo_core::ConstraintChecker>::Error),
)*
}

/// This type is generated by the `#[tuxedo_constraint_checker]` macro.
/// It is a combined set of inherent hooks for the inherent hooks of each individual checker.
///
/// This type is accessible downstream as `<OuterConstraintChecker as ConstraintChecker>::InherentHooks`
#[derive(Debug, scale_info::TypeInfo)]
#vis enum #inherent_hooks {
#(
#variants2(<#inner_types2 as tuxedo_core::ConstraintChecker<#verifier>>::InherentHooks),
)*
}
impl tuxedo_core::ConstraintChecker for #outer_type {
type Error = #error_type;

impl tuxedo_core::inherents::InherentInternal<#verifier, #outer_type> for #inherent_hooks {
fn check (
&self,
inputs: &[tuxedo_core::dynamic_typing::DynamicallyTypedData],
peeks: &[tuxedo_core::dynamic_typing::DynamicallyTypedData],
outputs: &[tuxedo_core::dynamic_typing::DynamicallyTypedData],
) -> Result<TransactionPriority, Self::Error> {
match self {
#(
Self::#variants5(inner) => inner.check(inputs, peeks, outputs).map_err(|e| Self::Error::#variants5(e)),
)*
}
}

fn is_inherent(&self) -> bool {
match self {
#(
Self::#variants2(inner) => inner.is_inherent(),
)*
}

fn create_inherents(
}

fn create_inherents<V: tuxedo_core::Verifier>(
authoring_inherent_data: &InherentData,
previous_inherents: Vec<(tuxedo_core::types::Transaction<#verifier, #outer_type>, sp_core::H256)>,
) -> Vec<tuxedo_core::types::Transaction<#verifier, #outer_type>> {
previous_inherents: Vec<(tuxedo_core::types::Transaction<V, #outer_type>, sp_core::H256)>,
) -> Vec<tuxedo_core::types::Transaction<V, #outer_type>> {

let mut all_inherents = Vec::new();

Expand All @@ -272,7 +292,7 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token
})
.collect();

let inherents = <#inner_types3 as tuxedo_core::ConstraintChecker<#verifier>>::InherentHooks::create_inherents(authoring_inherent_data, previous_inherents)
let inherents = <#inner_types3 as tuxedo_core::ConstraintChecker>::create_inherents(authoring_inherent_data, previous_inherents)
.iter()
.map(|tx| tx.transform::<#outer_type>())
.collect::<Vec<_>>();
Expand All @@ -284,13 +304,13 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token
all_inherents
}

fn check_inherents(
fn check_inherents<V: tuxedo_core::Verifier>(
importing_inherent_data: &sp_inherents::InherentData,
inherents: Vec<tuxedo_core::types::Transaction<#verifier, #outer_type>>,
inherents: Vec<tuxedo_core::types::Transaction<V, #outer_type>>,
result: &mut sp_inherents::CheckInherentsResult,
) {
#(
let relevant_inherents: Vec<tuxedo_core::types::Transaction<#verifier, #inner_types4>> = inherents
let relevant_inherents: Vec<tuxedo_core::types::Transaction<V, #inner_types4>> = inherents
.iter()
.filter_map(|tx| {
match tx.checker {
Expand All @@ -300,7 +320,7 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token
})
.collect();

<#inner_types4 as tuxedo_core::ConstraintChecker<#verifier>>::InherentHooks::check_inherents(importing_inherent_data, relevant_inherents, result);
<#inner_types4 as tuxedo_core::ConstraintChecker>::check_inherents(importing_inherent_data, relevant_inherents, result);

// According to https://paritytech.github.io/polkadot-sdk/master/sp_inherents/struct.CheckInherentsResult.html
// "When a fatal error occurs, all other errors are removed and the implementation needs to abort checking inherents."
Expand All @@ -311,12 +331,12 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token
}

#[cfg(feature = "std")]
fn genesis_transactions() -> Vec<tuxedo_core::types::Transaction<#verifier, #outer_type>> {
let mut all_transactions: Vec<tuxedo_core::types::Transaction<#verifier, #outer_type>> = Vec::new();
fn genesis_transactions<V: tuxedo_core::Verifier>() -> Vec<tuxedo_core::types::Transaction<V, #outer_type>> {
let mut all_transactions: Vec<tuxedo_core::types::Transaction<V, #outer_type>> = Vec::new();

#(
let transactions =
<<#inner_types6 as tuxedo_core::ConstraintChecker<#verifier>>::InherentHooks as tuxedo_core::inherents::InherentInternal<#verifier, #inner_types6>>::genesis_transactions();
<#inner_types2 as tuxedo_core::ConstraintChecker>::genesis_transactions();
all_transactions.extend(
transactions
.into_iter()
Expand All @@ -329,35 +349,6 @@ pub fn tuxedo_constraint_checker(attrs: TokenStream, body: TokenStream) -> Token
}

}

impl tuxedo_core::ConstraintChecker<#verifier> for #outer_type {
type Error = #error_type;

type InherentHooks = #inherent_hooks;

fn check (
&self,
inputs: &[tuxedo_core::types::Output<#verifier>],
peeks: &[tuxedo_core::types::Output<#verifier>],
outputs: &[tuxedo_core::types::Output<#verifier>],
) -> Result<TransactionPriority, Self::Error> {
match self {
#(
Self::#variants5(inner) => inner.check(inputs, peeks, outputs).map_err(|e| Self::Error::#variants5(e)),
)*
}
}

fn is_inherent(&self) -> bool {
match self {
#(
Self::#variants6(inner) => <#inner_types7 as tuxedo_core::ConstraintChecker<#verifier>>::is_inherent(inner),
)*
}

}

}
};

output.into()
Expand Down
Loading

0 comments on commit 9a18761

Please sign in to comment.