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

Farcaster Project support #170

Draft
wants to merge 29 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 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
cbef6b5
Start sketching farcaster verifiers
JoshOrndorff Feb 11, 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
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ panic = "unwind"

[workspace]
members = [
"farcaster",
"node",
"parachain-node",
"tuxedo-template-runtime",
Expand Down
26 changes: 26 additions & 0 deletions farcaster/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
description = "Farcaster Atomic Swap protocol support for Tuxedo based chains"
edition = "2021"
name = "farcaster-tuxedo"
version = "0.1.0"

# TODO These were copy pasted. Prune them.
[dependencies]
parity-scale-codec = { features = [ "derive" ], workspace = true }
scale-info = { features = [ "derive" ], workspace = true }
serde = { features = [ "derive" ], workspace = true }
sp-core = { default_features = false, workspace = true }
sp-runtime = { default_features = false, workspace = true }
sp-std = { default_features = false, workspace = true }
tuxedo-core = { default-features = false, path = "../tuxedo-core" }

[features]
default = [ "std" ]
std = [
"tuxedo-core/std",
"parity-scale-codec/std",
"sp-runtime/std",
"serde/std",
"sp-core/std",
"sp-std/std",
]
60 changes: 60 additions & 0 deletions farcaster/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//! The [Farcaster project](https://github.com/farcaster-project) s a cross-chain atomic swap protocol
//! that allows swaps with Monero despite its lack of any on chain logic.
//!
//! This crate contains several Tuxedo `Verifier`s that implement the same logic as Farcaster's
//! original Bitcoin scripts the allowing any Tuxedo chain to act on the arbitrating side of a
//! Farcaster protocol swap.

use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
use serde::{Deserialize, Serialize};
use sp_core::sr25519::{Public, Signature};
use tuxedo_core::Verifier;

/// Allows coins on the arbitrating Tuxedo chain to be bought or moved into in intermediate
/// utxo that represents the cancellation phase.
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub struct SwapLock {
recipient: Public,
canceller: Public,
cancelation_timeout: u32,
}

impl Verifier for SwapLock {
type Redeemer = UnlockSwap;

fn verify(&self, simplified_tx: &[u8], block_height: u32, redeemer: &Self::Redeemer) -> bool {
todo!()
}
}

/// Satisfies a `SwapLock` verifier.
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub enum UnlockSwap {
///
Buy,
///
Cancel,
}

/// Allows coins in the intermediate cancellation state to be refunded to the original owner
/// or for an alternate punish path. TODO better docs after I fully understand the punish path
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub struct SwapCancellation {}

impl Verifier for SwapCancellation {
type Redeemer = CompleteCancellation;

fn verify(&self, simplified_tx: &[u8], block_height: u32, redeemer: &Self::Redeemer) -> bool {
todo!()
}
}

///
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
pub enum CompleteCancellation {
///
Refund,
///
Punish,
}
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