Skip to content

Commit d8bb7f0

Browse files
committed
Merge branch 'main' into joshy-constraint-checker-beef-up
2 parents 96d2604 + 1ad2343 commit d8bb7f0

File tree

10 files changed

+547
-307
lines changed

10 files changed

+547
-307
lines changed

Cargo.lock

+17-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ async-io = "2.0"
2828
async-trait = "0.1.73"
2929
clap = "4.3.0"
3030
color-print = "0.3.4"
31+
convert_case = "0.6.0"
3132
hex-literal = "0.4.1"
3233
jsonrpsee = "0.16.2"
3334
log = "0.4"

runtime-expanded.rs

Whitespace-only changes.

tuxedo-core/aggregator/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ name = "aggregator"
44
version = "0.1.0"
55

66
[dependencies]
7+
convert_case = { workspace = true }
78
quote = { workspace = true }
89
syn = { features = [ "extra-traits", "full" ], workspace = true }
910

tuxedo-core/aggregator/src/lib.rs

+72-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use convert_case::{Case, Casing};
12
use proc_macro::TokenStream;
23
use quote::quote;
34
use syn::{parse_macro_input, Ident, ItemEnum};
@@ -73,21 +74,89 @@ pub fn aggregate(_: TokenStream, body: TokenStream) -> TokenStream {
7374
pub fn tuxedo_verifier(_: TokenStream, body: TokenStream) -> TokenStream {
7475
let ast = parse_macro_input!(body as ItemEnum);
7576
let original_code = ast.clone();
77+
let vis = ast.vis;
7678

7779
let outer_type = ast.ident;
78-
let variants = ast.variants.into_iter().map(|v| v.ident);
80+
let variant_type_pairs = ast.variants.iter().map(|variant| {
81+
// Make sure there is only a single field, and if not, give a helpful error
82+
assert!(
83+
variant.fields.len() == 1,
84+
"Each variant must have a single unnamed field"
85+
);
86+
(
87+
variant.ident.clone(),
88+
variant
89+
.fields
90+
.iter()
91+
.next()
92+
.expect("exactly one field per variant")
93+
.ty
94+
.clone(),
95+
)
96+
});
97+
let variants = variant_type_pairs.clone().map(|(v, _t)| v);
98+
let inner_types = variant_type_pairs.map(|(_v, t)| t);
99+
100+
// Set up the name of the new associated type.
101+
let mut redeemer_type_name = outer_type.to_string();
102+
redeemer_type_name.push_str("Redeemer");
103+
let redeemer_type = Ident::new(&redeemer_type_name, outer_type.span());
104+
105+
// TODO there must be a better way to do this, right?
106+
let inner_types2 = inner_types.clone();
107+
let variants2 = variants.clone();
108+
let variants3 = variants.clone();
109+
110+
let as_variants = variants.clone().map(|v| {
111+
let s = format!("as_{}", v);
112+
let s = s.to_case(Case::Snake);
113+
Ident::new(&s, v.span())
114+
});
115+
let as_variants2 = as_variants.clone();
79116

80117
let output = quote! {
81118

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

123+
/// This type is generated by the `#[tuxedo_verifier]` macro.
124+
/// It is a combined redeemer type for the redeemers of each individual verifier.
125+
///
126+
/// This type is accessible downstream as `<OuterVerifier as Verifier>::Redeemer`
127+
#[derive(Debug, Decode)]
128+
#vis enum #redeemer_type {
129+
#(
130+
#variants(<#inner_types as tuxedo_core::Verifier>::Redeemer),
131+
)*
132+
}
133+
134+
// Put a bunch of methods like `.as_variant1()` on the aggregate redeemer type
135+
// These are necessary when unwrapping the onion.
136+
// Might be that we should have a helper macro for this as well
137+
impl #redeemer_type {
138+
#(
139+
pub fn #as_variants(&self) -> Option<&<#inner_types2 as tuxedo_core::Verifier>::Redeemer> {
140+
match self {
141+
Self::#variants2(inner) => Some(inner),
142+
_ => None,
143+
}
144+
}
145+
)*
146+
}
147+
86148
impl tuxedo_core::Verifier for #outer_type {
87-
fn verify(&self, simplified_tx: &[u8], redeemer: &[u8]) -> bool {
149+
150+
type Redeemer = #redeemer_type;
151+
152+
fn verify(&self, simplified_tx: &[u8], block_number: u32, redeemer: &Self::Redeemer) -> bool {
88153
match self {
89154
#(
90-
Self::#variants(inner) => inner.verify(simplified_tx, redeemer),
155+
Self::#variants3(inner) => inner.verify(
156+
simplified_tx,
157+
block_number,
158+
redeemer.#as_variants2().expect("redeemer variant exists because the macro constructed that type.")
159+
),
91160
)*
92161
}
93162
}

tuxedo-core/src/executive.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ use sp_std::{collections::btree_set::BTreeSet, vec::Vec};
3535
/// in the proper generic types.
3636
pub struct Executive<B, V, C>(PhantomData<(B, V, C)>);
3737

38-
impl<B: BlockT<Extrinsic = Transaction<V, C>>, V: Verifier, C: SimpleConstraintChecker + InherentInternal>
39-
Executive<B, V, C>
38+
impl<B, V, C> Executive<B, V, C>
39+
where
40+
B: BlockT<Extrinsic = Transaction<V, C>>,
41+
B::Header: HeaderT<Number = u32>, // Tuxedo always uses u32 for block number.
42+
V: Verifier,
43+
C: SimpleConstraintChecker + InherentInternal,
4044
{
4145
/// Does pool-style validation of a tuxedo transaction.
4246
/// Does not commit anything to storage.
@@ -75,10 +79,12 @@ impl<B: BlockT<Extrinsic = Transaction<V, C>>, V: Verifier, C: SimpleConstraintC
7579
let mut missing_inputs = Vec::new();
7680
for input in transaction.inputs.iter() {
7781
if let Some(input_utxo) = TransparentUtxoSet::<V>::peek_utxo(&input.output_ref) {
82+
let redeemer = V::Redeemer::decode(&mut &input.redeemer[..])
83+
.map_err(|_| UtxoError::VerifierError)?;
7884
ensure!(
7985
input_utxo
8086
.verifier
81-
.verify(&stripped_encoded, &input.redeemer),
87+
.verify(&stripped_encoded, Self::block_height(), &redeemer),
8288
UtxoError::VerifierError
8389
);
8490
input_utxos.push(input_utxo);
@@ -475,7 +481,7 @@ impl<B: BlockT<Extrinsic = Transaction<V, C>>, V: Verifier, C: SimpleConstraintC
475481
mod tests {
476482
use sp_core::H256;
477483
use sp_io::TestExternalities;
478-
use sp_runtime::transaction_validity::ValidTransactionBuilder;
484+
use sp_runtime::{generic::Header, transaction_validity::ValidTransactionBuilder};
479485

480486
use crate::{
481487
constraint_checker::testing::TestConstraintChecker,
@@ -619,10 +625,15 @@ mod tests {
619625
ext.insert(output_ref.encode(), output.encode());
620626
}
621627

622-
// Write the pre-header
623-
if let Some(pre_header) = self.pre_header {
624-
ext.insert(HEADER_KEY.to_vec(), pre_header.encode());
625-
}
628+
// Write a pre-header. If none was supplied, create a use a default one.
629+
let pre_header = self.pre_header.unwrap_or(Header {
630+
parent_hash: Default::default(),
631+
number: 0,
632+
state_root: H256::zero(),
633+
extrinsics_root: H256::zero(),
634+
digest: Default::default(),
635+
});
636+
ext.insert(HEADER_KEY.to_vec(), pre_header.encode());
626637

627638
// Write the noted extrinsics
628639
ext.insert(EXTRINSIC_KEY.to_vec(), self.noted_extrinsics.encode());

0 commit comments

Comments
 (0)