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

Hash Time Lock Contracts #168

Merged
merged 34 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ee77117
Prototype hash lock
JoshOrndorff Feb 5, 2024
720c6ae
`Verifier` trait passes block height and timelock prototype
JoshOrndorff Feb 5, 2024
0e2f098
cargo fmt
JoshOrndorff Feb 5, 2024
0492168
Better structure in the `verifier` module
JoshOrndorff Feb 6, 2024
ae0a41a
warnings
JoshOrndorff Feb 6, 2024
8e03d9e
Update executive for new verifier signaute, and enforce u32 block hei…
JoshOrndorff Feb 6, 2024
03462aa
more warnings
JoshOrndorff Feb 6, 2024
c989b0a
sketch timelock tests
JoshOrndorff Feb 6, 2024
e3e9fb5
update verifier signature in macro
JoshOrndorff Feb 6, 2024
306fa93
move hash lock to propoer module and write test
JoshOrndorff Feb 6, 2024
22bec39
expose the hashlock and timelock in public api
JoshOrndorff Feb 6, 2024
324635a
more hash lock tests
JoshOrndorff Feb 7, 2024
324fe26
Idea for P2PKH verifier
JoshOrndorff Feb 7, 2024
a08fafe
cargo fmt
JoshOrndorff Feb 7, 2024
3955506
fmt
JoshOrndorff Feb 8, 2024
ec84e43
HTLC good enough for swaps with something bitcoinish
JoshOrndorff Feb 8, 2024
592232d
Add `Redeemer` associated type to `Verifier` trait.
JoshOrndorff Feb 8, 2024
eea0db4
Finish filling in P2PKH impl
JoshOrndorff Feb 8, 2024
42d0a68
first p2pkh test
JoshOrndorff Feb 8, 2024
d1f5539
aggregate redeemer type
JoshOrndorff Feb 8, 2024
76bc6a9
Finish testing P2PKH
JoshOrndorff Feb 8, 2024
b6e0d28
clippy
JoshOrndorff Feb 8, 2024
76df42b
vec import
JoshOrndorff Feb 8, 2024
b19586d
htlc happy path test
JoshOrndorff Feb 8, 2024
ff07b39
fmt
JoshOrndorff Feb 8, 2024
29b6e5c
vec
JoshOrndorff Feb 8, 2024
60234de
u32 bound in parachain
JoshOrndorff Feb 10, 2024
6747f35
Finish tests for HTCL
JoshOrndorff Feb 10, 2024
541bafa
Update tuxedo-core/src/verifier.rs
JoshOrndorff Feb 10, 2024
2256f27
clarify that happy path remains open.
JoshOrndorff Feb 13, 2024
e9fb8d8
Docs for HTLC spend path enum.
JoshOrndorff Feb 13, 2024
551d574
better signature for "new_from_secret". Make caller encode.
JoshOrndorff Feb 13, 2024
2837dba
fmt
JoshOrndorff Feb 13, 2024
7342680
Merge branch 'main' into joshy-hash-time-lock
JoshOrndorff Feb 15, 2024
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
12 changes: 9 additions & 3 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
Loading
Loading