Skip to content

Commit

Permalink
aggregate redeemer type
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshOrndorff committed Feb 8, 2024
1 parent 42d0a68 commit d1f5539
Showing 1 changed file with 64 additions and 3 deletions.
67 changes: 64 additions & 3 deletions tuxedo-core/aggregator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,82 @@ pub fn aggregate(_: TokenStream, body: TokenStream) -> TokenStream {
pub fn tuxedo_verifier(_: TokenStream, body: TokenStream) -> TokenStream {
let ast = parse_macro_input!(body as ItemEnum);
let original_code = ast.clone();
let vis = ast.vis;

let outer_type = ast.ident;
let variants = ast.variants.into_iter().map(|v| v.ident);
let variant_type_pairs = ast.variants.iter().map(|variant| {
// Make sure there is only a single field, and if not, give a helpful error
assert!(
variant.fields.len() == 1,
"Each variant must have a single unnamed field"
);
(
variant.ident.clone(),
variant
.fields
.iter()
.next()
.expect("exactly one field per variant")
.ty
.clone(),
)
});
let variants = variant_type_pairs.clone().map(|(v, _t)| v);
let inner_types = variant_type_pairs.map(|(_v, t)| t);

// Set up the name of the new associated type.
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());

// 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 variants4 = variants.clone();

let output = quote! {

// Preserve the original enum, and write the From impls
#[tuxedo_core::aggregate]
#original_code

/// This type is generated by the `#[tuxedo_verifier]` macro.
/// It is a combined redeemer type for the redeemers of each individual verifier.
///
/// This type is accessible downstream as `<OuterVerifier as Verifier>::Redeemer`
#[derive(Debug, Decode)]
#vis enum #redeemer_type {
#(
#variants(<#inner_types as tuxedo_core::Verifier>::Redeemer),
)*
}

// Put a bunch of methods like `.as_variant1()` on the aggregate redeemer type
// These are necessary when unwrapping the onion.
// Might be that we should have a helper macro for this as well
impl #redeemer_type {
#(
//TODO I would rather the function be called as_variant2,
// but my macro n00b skills can't figure it out.
#[allow(non_snake_case)]
pub fn #variants2(&self) -> Option<&<#inner_types2 as tuxedo_core::Verifier>::Redeemer> {
match self {
Self::#variants3(inner) => Some(inner),
_ => None,
}
}
)*
}

impl tuxedo_core::Verifier for #outer_type {
fn verify(&self, simplified_tx: &[u8], block_number: u32, redeemer: &[u8]) -> bool {

type Redeemer = #redeemer_type;

fn verify(&self, simplified_tx: &[u8], block_number: u32, redeemer: &Self::Redeemer) -> bool {
match self {
#(
Self::#variants(inner) => inner.verify(simplified_tx, block_number, redeemer),
Self::#variants4(inner) => inner.verify(simplified_tx, block_number, redeemer.#variants4().expect("redeemer variant exists because the macro constructed that type.")),
)*
}
}
Expand Down

0 comments on commit d1f5539

Please sign in to comment.