Skip to content

Commit

Permalink
Construct HTLC as composition of HL & TL
Browse files Browse the repository at this point in the history
Use HashLock and TimeLock structs as building blocks for
HashTimeLockContract. More verbose for simple cases like this, but
avoiding duplication of logic ensures consistency of the interface and
is especially advantageous when constructing more complicated scripts.
  • Loading branch information
Lederstrumpf committed Feb 11, 2024
1 parent 541bafa commit 29a20fe
Showing 1 changed file with 48 additions and 32 deletions.
80 changes: 48 additions & 32 deletions tuxedo-core/src/verifier/htlc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ impl Verifier for BlakeTwoHashLock {
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub struct HashTimeLockContract {
/// The hash whose preimage must be revealed (along with the recipient's signature) to spend the UTXO.
pub hash_lock: H256,
pub hash_lock: BlakeTwoHashLock,
/// The pubkey that is intended to receive and acknowledge receipt of the funds.
pub recipient_pubkey: Public,
/// The time (as a block height) when the refund path opens up.
pub claim_period_end: u32,
pub claim_period_end: TimeLock,
/// The address who can spend the coins without revealing the preimage after the claim period has ended.
pub refunder_pubkey: Public,
}
Expand All @@ -113,7 +113,7 @@ impl Verifier for HashTimeLockContract {
match spend_path {
HtlcSpendPath::Claim { secret, signature } => {
// Claims are valid as long as the secret is correct and the receiver signature is correct.
BlakeTwo256::hash(secret) == self.hash_lock
self.hash_lock.verify(simplified_tx, block_height, secret)
&& sp_io::crypto::sr25519_verify(
signature,
simplified_tx,
Expand All @@ -122,7 +122,7 @@ impl Verifier for HashTimeLockContract {
}
HtlcSpendPath::Refund { signature } => {
// Check that the time has elapsed
block_height >= self.claim_period_end
self.claim_period_end.verify(simplified_tx, block_height, &())

&&

Expand Down Expand Up @@ -193,21 +193,23 @@ mod test {
#[test]
fn htlc_claim_success() {
const THRESHOLD: u32 = 100;
let secret = "htlc ftw".encode();
let secret = "htlc ftw";
let recipient_pair = Pair::from_seed(&[0u8; 32]);
let refunder_pair = Pair::from_seed(&[1u8; 32]);

let htlc = HashTimeLockContract {
hash_lock: BlakeTwo256::hash(&secret),
hash_lock: BlakeTwoHashLock::new_from_secret(&secret),
recipient_pubkey: recipient_pair.public(),
claim_period_end: THRESHOLD,
claim_period_end: TimeLock {
unlock_block_height: THRESHOLD,
},
refunder_pubkey: refunder_pair.public(),
};

let simplified_tx = b"hello world".as_slice();
let recipient_sig = recipient_pair.sign(simplified_tx);
let redeemer = HtlcSpendPath::Claim {
secret,
secret: secret.encode(),
signature: recipient_sig,
};

Expand All @@ -217,14 +219,16 @@ mod test {
#[test]
fn htlc_claim_wrong_secret() {
const THRESHOLD: u32 = 100;
let secret = "htlc ftw".encode();
let secret = "htlc ftw";
let recipient_pair = Pair::from_seed(&[0u8; 32]);
let refunder_pair = Pair::from_seed(&[1u8; 32]);

let htlc = HashTimeLockContract {
hash_lock: BlakeTwo256::hash(&secret),
hash_lock: BlakeTwoHashLock::new_from_secret(&secret),
recipient_pubkey: recipient_pair.public(),
claim_period_end: THRESHOLD,
claim_period_end: TimeLock {
unlock_block_height: THRESHOLD,
},
refunder_pubkey: refunder_pair.public(),
};

Expand All @@ -233,7 +237,7 @@ mod test {
let simplified_tx = b"hello world".as_slice();
let recipient_sig = recipient_pair.sign(simplified_tx);
let redeemer = HtlcSpendPath::Claim {
secret: incorrect_secret,
secret: incorrect_secret.encode(),
signature: recipient_sig,
};

Expand All @@ -243,20 +247,22 @@ mod test {
#[test]
fn htlc_claim_bogus_signature() {
const THRESHOLD: u32 = 100;
let secret = "htlc ftw".encode();
let secret = "htlc ftw";
let recipient_pair = Pair::from_seed(&[0u8; 32]);
let refunder_pair = Pair::from_seed(&[1u8; 32]);

let htlc = HashTimeLockContract {
hash_lock: BlakeTwo256::hash(&secret),
hash_lock: BlakeTwoHashLock::new_from_secret(&secret),
recipient_pubkey: recipient_pair.public(),
claim_period_end: THRESHOLD,
claim_period_end: TimeLock {
unlock_block_height: THRESHOLD,
},
refunder_pubkey: refunder_pair.public(),
};

let simplified_tx = b"hello world".as_slice();
let redeemer = HtlcSpendPath::Claim {
secret,
secret: secret.encode(),
signature: bad_sig(),
};

Expand All @@ -266,21 +272,23 @@ mod test {
#[test]
fn htlc_claim_fails_when_signature_is_from_refunder() {
const THRESHOLD: u32 = 100;
let secret = "htlc ftw".encode();
let secret = "htlc ftw";
let recipient_pair = Pair::from_seed(&[0u8; 32]);
let refunder_pair = Pair::from_seed(&[1u8; 32]);

let htlc = HashTimeLockContract {
hash_lock: BlakeTwo256::hash(&secret),
hash_lock: BlakeTwoHashLock::new_from_secret(&secret),
recipient_pubkey: recipient_pair.public(),
claim_period_end: THRESHOLD,
claim_period_end: TimeLock {
unlock_block_height: THRESHOLD,
},
refunder_pubkey: refunder_pair.public(),
};

let simplified_tx = b"hello world".as_slice();
let refunder_sig = refunder_pair.sign(simplified_tx);
let redeemer = HtlcSpendPath::Claim {
secret,
secret: secret.encode(),
signature: refunder_sig,
};

Expand All @@ -290,14 +298,16 @@ mod test {
#[test]
fn htlc_refund_success() {
const THRESHOLD: u32 = 100;
let secret = "htlc ftw".encode();
let secret = "htlc ftw";
let recipient_pair = Pair::from_seed(&[0u8; 32]);
let refunder_pair = Pair::from_seed(&[1u8; 32]);

let htlc = HashTimeLockContract {
hash_lock: BlakeTwo256::hash(&secret),
hash_lock: BlakeTwoHashLock::new_from_secret(&secret),
recipient_pubkey: recipient_pair.public(),
claim_period_end: THRESHOLD,
claim_period_end: TimeLock {
unlock_block_height: THRESHOLD,
},
refunder_pubkey: refunder_pair.public(),
};

Expand All @@ -313,14 +323,16 @@ mod test {
#[test]
fn htlc_refund_too_early() {
const THRESHOLD: u32 = 100;
let secret = "htlc ftw".encode();
let secret = "htlc ftw";
let recipient_pair = Pair::from_seed(&[0u8; 32]);
let refunder_pair = Pair::from_seed(&[1u8; 32]);

let htlc = HashTimeLockContract {
hash_lock: BlakeTwo256::hash(&secret),
hash_lock: BlakeTwoHashLock::new_from_secret(&secret),
recipient_pubkey: recipient_pair.public(),
claim_period_end: THRESHOLD,
claim_period_end: TimeLock {
unlock_block_height: THRESHOLD,
},
refunder_pubkey: refunder_pair.public(),
};

Expand All @@ -336,14 +348,16 @@ mod test {
#[test]
fn htlc_refund_bogus_sig() {
const THRESHOLD: u32 = 100;
let secret = "htlc ftw".encode();
let secret = "htlc ftw";
let recipient_pair = Pair::from_seed(&[0u8; 32]);
let refunder_pair = Pair::from_seed(&[1u8; 32]);

let htlc = HashTimeLockContract {
hash_lock: BlakeTwo256::hash(&secret),
hash_lock: BlakeTwoHashLock::new_from_secret(&secret),
recipient_pubkey: recipient_pair.public(),
claim_period_end: THRESHOLD,
claim_period_end: TimeLock {
unlock_block_height: THRESHOLD,
},
refunder_pubkey: refunder_pair.public(),
};

Expand All @@ -358,14 +372,16 @@ mod test {
#[test]
fn htlc_refund_fails_when_signature_is_from_recipient() {
const THRESHOLD: u32 = 100;
let secret = "htlc ftw".encode();
let secret = "htlc ftw";
let recipient_pair = Pair::from_seed(&[0u8; 32]);
let refunder_pair = Pair::from_seed(&[1u8; 32]);

let htlc = HashTimeLockContract {
hash_lock: BlakeTwo256::hash(&secret),
hash_lock: BlakeTwoHashLock::new_from_secret(&secret),
recipient_pubkey: recipient_pair.public(),
claim_period_end: THRESHOLD,
claim_period_end: TimeLock {
unlock_block_height: THRESHOLD,
},
refunder_pubkey: refunder_pair.public(),
};

Expand Down

0 comments on commit 29a20fe

Please sign in to comment.