Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic SignatureCheck Verifier #173

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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], 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, redeemer),
Self::#variants4(inner) => inner.verify(simplified_tx, block_number, redeemer.#variants4().expect("redeemer variant exists because the macro constructed that type.")),
)*
}
}
Expand Down
27 changes: 19 additions & 8 deletions tuxedo-core/src/executive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@ use sp_std::{collections::btree_set::BTreeSet, vec::Vec};
/// in the proper generic types.
pub struct Executive<B, V, C>(PhantomData<(B, V, C)>);

impl<B: BlockT<Extrinsic = Transaction<V, C>>, V: Verifier, C: ConstraintChecker<V>>
Executive<B, V, C>
impl<B, V, C> Executive<B, V, C>
where
B: BlockT<Extrinsic = Transaction<V, C>>,
B::Header: HeaderT<Number = u32>, // Tuxedo always uses u32 for block number.
V: Verifier,
C: ConstraintChecker<V>,
{
/// Does pool-style validation of a tuxedo transaction.
/// Does not commit anything to storage.
Expand Down Expand Up @@ -75,10 +79,12 @@ impl<B: BlockT<Extrinsic = Transaction<V, C>>, V: Verifier, C: ConstraintChecker
let mut missing_inputs = Vec::new();
for input in transaction.inputs.iter() {
if let Some(input_utxo) = TransparentUtxoSet::<V>::peek_utxo(&input.output_ref) {
let redeemer = V::Redeemer::decode(&mut &input.redeemer[..])
.map_err(|_| UtxoError::VerifierError)?;
ensure!(
input_utxo
.verifier
.verify(&stripped_encoded, &input.redeemer),
.verify(&stripped_encoded, Self::block_height(), &redeemer),
UtxoError::VerifierError
);
input_utxos.push(input_utxo);
Expand Down Expand Up @@ -475,7 +481,7 @@ impl<B: BlockT<Extrinsic = Transaction<V, C>>, V: Verifier, C: ConstraintChecker
mod tests {
use sp_core::H256;
use sp_io::TestExternalities;
use sp_runtime::transaction_validity::ValidTransactionBuilder;
use sp_runtime::{generic::Header, transaction_validity::ValidTransactionBuilder};

use crate::{
constraint_checker::testing::TestConstraintChecker,
Expand Down Expand Up @@ -619,10 +625,15 @@ mod tests {
ext.insert(output_ref.encode(), output.encode());
}

// Write the pre-header
if let Some(pre_header) = self.pre_header {
ext.insert(HEADER_KEY.to_vec(), pre_header.encode());
}
// Write a pre-header. If none was supplied, create a use a default one.
let pre_header = self.pre_header.unwrap_or(Header {
parent_hash: Default::default(),
number: 0,
state_root: H256::zero(),
extrinsics_root: H256::zero(),
digest: Default::default(),
});
ext.insert(HEADER_KEY.to_vec(), pre_header.encode());

// Write the noted extrinsics
ext.insert(EXTRINSIC_KEY.to_vec(), self.noted_extrinsics.encode());
Expand Down
Loading
Loading