From d853b8ec0b51feaf0d372d9b0a80fb44ed25fd8f Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Thu, 18 Nov 2021 16:27:41 +1100 Subject: [PATCH] Move tests to bottom of file --- daemon/src/model/cfd.rs | 350 ++++++++++++++++++++-------------------- 1 file changed, 175 insertions(+), 175 deletions(-) diff --git a/daemon/src/model/cfd.rs b/daemon/src/model/cfd.rs index a4ad16d..4af0e8c 100644 --- a/daemon/src/model/cfd.rs +++ b/daemon/src/model/cfd.rs @@ -1464,6 +1464,181 @@ fn calculate_profit( Ok((profit, Percent(percent))) } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct Cet { + pub tx: Transaction, + pub adaptor_sig: EcdsaAdaptorSignature, + + // TODO: Range + number of digits (usize) could be represented as Digits similar to what we do + // in the protocol lib + pub range: RangeInclusive, + pub n_bits: usize, +} + +/// Contains all data we've assembled about the CFD through the setup protocol. +/// +/// All contained signatures are the signatures of THE OTHER PARTY. +/// To use any of these transactions, we need to re-sign them with the correct secret key. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct Dlc { + pub identity: SecretKey, + pub identity_counterparty: PublicKey, + pub revocation: SecretKey, + pub revocation_pk_counterparty: PublicKey, + pub publish: SecretKey, + pub publish_pk_counterparty: PublicKey, + pub maker_address: Address, + pub taker_address: Address, + + /// The fully signed lock transaction ready to be published on chain + pub lock: (Transaction, Descriptor), + pub commit: (Transaction, EcdsaAdaptorSignature, Descriptor), + pub cets: HashMap>, + pub refund: (Transaction, Signature), + + #[serde(with = "::bdk::bitcoin::util::amount::serde::as_sat")] + pub maker_lock_amount: Amount, + #[serde(with = "::bdk::bitcoin::util::amount::serde::as_sat")] + pub taker_lock_amount: Amount, + + pub revoked_commit: Vec, +} + +impl Dlc { + /// Create a close transaction based on the current contract and a settlement proposals + pub fn close_transaction( + &self, + proposal: &crate::model::cfd::SettlementProposal, + ) -> Result<(Transaction, Signature)> { + let (lock_tx, lock_desc) = &self.lock; + let (lock_outpoint, lock_amount) = { + let outpoint = lock_tx + .outpoint(&lock_desc.script_pubkey()) + .expect("lock script to be in lock tx"); + let amount = Amount::from_sat(lock_tx.output[outpoint.vout as usize].value); + + (outpoint, amount) + }; + let (tx, sighash) = maia::close_transaction( + lock_desc, + lock_outpoint, + lock_amount, + (&self.maker_address, proposal.maker), + (&self.taker_address, proposal.taker), + ) + .context("Unable to collaborative close transaction")?; + + let sig = SECP256K1.sign(&sighash, &self.identity); + + Ok((tx, sig)) + } + + pub fn finalize_spend_transaction( + &self, + (close_tx, own_sig): (Transaction, Signature), + counterparty_sig: Signature, + ) -> Result { + let own_pk = PublicKey::new(secp256k1_zkp::PublicKey::from_secret_key( + SECP256K1, + &self.identity, + )); + + let (_, lock_desc) = &self.lock; + let spend_tx = maia::finalize_spend_transaction( + close_tx, + lock_desc, + (own_pk, own_sig), + (self.identity_counterparty, counterparty_sig), + )?; + + Ok(spend_tx) + } + + pub fn refund_amount(&self, role: Role) -> Amount { + let our_script_pubkey = match role { + Role::Taker => self.taker_address.script_pubkey(), + Role::Maker => self.maker_address.script_pubkey(), + }; + + self.refund + .0 + .output + .iter() + .find(|output| output.script_pubkey == our_script_pubkey) + .map(|output| Amount::from_sat(output.value)) + .unwrap_or_default() + } + + pub fn script_pubkey_for(&self, role: Role) -> Script { + match role { + Role::Maker => self.maker_address.script_pubkey(), + Role::Taker => self.taker_address.script_pubkey(), + } + } +} + +/// Information which we need to remember in order to construct a +/// punishment transaction in case the counterparty publishes a +/// revoked commit transaction. +/// +/// It also includes the information needed to monitor for the +/// publication of the revoked commit transaction. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct RevokedCommit { + // To build punish transaction + pub encsig_ours: EcdsaAdaptorSignature, + pub revocation_sk_theirs: SecretKey, + pub publication_pk_theirs: PublicKey, + // To monitor revoked commit transaction + pub txid: Txid, + pub script_pubkey: Script, +} + +/// Used when transactions (e.g. collaborative close) are recorded as a part of +/// CfdState in the cases when we can't solely rely on state transition +/// timestamp as it could have occured for different reasons (like a new +/// attestation in Open state) +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct CollaborativeSettlement { + pub tx: Transaction, + pub timestamp: Timestamp, + #[serde(with = "::bdk::bitcoin::util::amount::serde::as_sat")] + payout: Amount, + price: Price, +} + +impl CollaborativeSettlement { + pub fn new(tx: Transaction, own_script_pubkey: Script, price: Price) -> Result { + // Falls back to Amount::ZERO in case we don't find an output that matches out script pubkey + // The assumption is, that this can happen for cases where we were liuqidated + let payout = match tx + .output + .iter() + .find(|output| output.script_pubkey == own_script_pubkey) + .map(|output| Amount::from_sat(output.value)) + { + Some(payout) => payout, + None => { + tracing::error!( + "Collaborative settlement with a zero amount, this should really not happen!" + ); + Amount::ZERO + } + }; + + Ok(Self { + tx, + timestamp: Timestamp::now(), + payout, + price, + }) + } + + pub fn payout(&self) -> Amount { + self.payout + } +} + #[cfg(test)] mod tests { use super::*; @@ -1715,178 +1890,3 @@ mod tests { assert_eq!(id, deserialized); } } - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct Cet { - pub tx: Transaction, - pub adaptor_sig: EcdsaAdaptorSignature, - - // TODO: Range + number of digits (usize) could be represented as Digits similar to what we do - // in the protocol lib - pub range: RangeInclusive, - pub n_bits: usize, -} - -/// Contains all data we've assembled about the CFD through the setup protocol. -/// -/// All contained signatures are the signatures of THE OTHER PARTY. -/// To use any of these transactions, we need to re-sign them with the correct secret key. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct Dlc { - pub identity: SecretKey, - pub identity_counterparty: PublicKey, - pub revocation: SecretKey, - pub revocation_pk_counterparty: PublicKey, - pub publish: SecretKey, - pub publish_pk_counterparty: PublicKey, - pub maker_address: Address, - pub taker_address: Address, - - /// The fully signed lock transaction ready to be published on chain - pub lock: (Transaction, Descriptor), - pub commit: (Transaction, EcdsaAdaptorSignature, Descriptor), - pub cets: HashMap>, - pub refund: (Transaction, Signature), - - #[serde(with = "::bdk::bitcoin::util::amount::serde::as_sat")] - pub maker_lock_amount: Amount, - #[serde(with = "::bdk::bitcoin::util::amount::serde::as_sat")] - pub taker_lock_amount: Amount, - - pub revoked_commit: Vec, -} - -impl Dlc { - /// Create a close transaction based on the current contract and a settlement proposals - pub fn close_transaction( - &self, - proposal: &crate::model::cfd::SettlementProposal, - ) -> Result<(Transaction, Signature)> { - let (lock_tx, lock_desc) = &self.lock; - let (lock_outpoint, lock_amount) = { - let outpoint = lock_tx - .outpoint(&lock_desc.script_pubkey()) - .expect("lock script to be in lock tx"); - let amount = Amount::from_sat(lock_tx.output[outpoint.vout as usize].value); - - (outpoint, amount) - }; - let (tx, sighash) = maia::close_transaction( - lock_desc, - lock_outpoint, - lock_amount, - (&self.maker_address, proposal.maker), - (&self.taker_address, proposal.taker), - ) - .context("Unable to collaborative close transaction")?; - - let sig = SECP256K1.sign(&sighash, &self.identity); - - Ok((tx, sig)) - } - - pub fn finalize_spend_transaction( - &self, - (close_tx, own_sig): (Transaction, Signature), - counterparty_sig: Signature, - ) -> Result { - let own_pk = PublicKey::new(secp256k1_zkp::PublicKey::from_secret_key( - SECP256K1, - &self.identity, - )); - - let (_, lock_desc) = &self.lock; - let spend_tx = maia::finalize_spend_transaction( - close_tx, - lock_desc, - (own_pk, own_sig), - (self.identity_counterparty, counterparty_sig), - )?; - - Ok(spend_tx) - } - - pub fn refund_amount(&self, role: Role) -> Amount { - let our_script_pubkey = match role { - Role::Taker => self.taker_address.script_pubkey(), - Role::Maker => self.maker_address.script_pubkey(), - }; - - self.refund - .0 - .output - .iter() - .find(|output| output.script_pubkey == our_script_pubkey) - .map(|output| Amount::from_sat(output.value)) - .unwrap_or_default() - } - - pub fn script_pubkey_for(&self, role: Role) -> Script { - match role { - Role::Maker => self.maker_address.script_pubkey(), - Role::Taker => self.taker_address.script_pubkey(), - } - } -} - -/// Information which we need to remember in order to construct a -/// punishment transaction in case the counterparty publishes a -/// revoked commit transaction. -/// -/// It also includes the information needed to monitor for the -/// publication of the revoked commit transaction. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct RevokedCommit { - // To build punish transaction - pub encsig_ours: EcdsaAdaptorSignature, - pub revocation_sk_theirs: SecretKey, - pub publication_pk_theirs: PublicKey, - // To monitor revoked commit transaction - pub txid: Txid, - pub script_pubkey: Script, -} - -/// Used when transactions (e.g. collaborative close) are recorded as a part of -/// CfdState in the cases when we can't solely rely on state transition -/// timestamp as it could have occured for different reasons (like a new -/// attestation in Open state) -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct CollaborativeSettlement { - pub tx: Transaction, - pub timestamp: Timestamp, - #[serde(with = "::bdk::bitcoin::util::amount::serde::as_sat")] - payout: Amount, - price: Price, -} - -impl CollaborativeSettlement { - pub fn new(tx: Transaction, own_script_pubkey: Script, price: Price) -> Result { - // Falls back to Amount::ZERO in case we don't find an output that matches out script pubkey - // The assumption is, that this can happen for cases where we were liuqidated - let payout = match tx - .output - .iter() - .find(|output| output.script_pubkey == own_script_pubkey) - .map(|output| Amount::from_sat(output.value)) - { - Some(payout) => payout, - None => { - tracing::error!( - "Collaborative settlement with a zero amount, this should really not happen!" - ); - Amount::ZERO - } - }; - - Ok(Self { - tx, - timestamp: Timestamp::now(), - payout, - price, - }) - } - - pub fn payout(&self) -> Amount { - self.payout - } -}