diff --git a/core/src/builder/sighash.rs b/core/src/builder/sighash.rs index 6c5045f8..82d6f352 100644 --- a/core/src/builder/sighash.rs +++ b/core/src/builder/sighash.rs @@ -128,6 +128,14 @@ pub async fn dummy( Ok(()) } +pub fn calculate_num_required_sigs( + num_operators: usize, + num_time_txs: usize, + num_watchtowers: usize, +) -> usize { + num_operators * num_time_txs * (1 + 2 * num_watchtowers) +} + pub fn create_nofn_sighash_stream( db: Database, config: BridgeConfig, @@ -231,6 +239,23 @@ pub fn create_nofn_sighash_stream( 0, 0, )?; + + let mut operator_challenge_nack_txhandler = builder::transaction::create_operator_challenge_nack_txhandler( + wcp_txid, + time_txid, + input_amunt, + i, + &[0u8; 20], + nofn_xonly_pk, + *operator_xonly_pk, + network, + ); + + yield Actor::convert_tx_to_sighash_script_spend( + &mut operator_challenge_nack_txhandler, + 0, + 1, + )?; } let time2_tx = builder::transaction::create_time2_tx( diff --git a/core/src/builder/transaction.rs b/core/src/builder/transaction.rs index 22ead7e7..2bc98535 100644 --- a/core/src/builder/transaction.rs +++ b/core/src/builder/transaction.rs @@ -466,6 +466,62 @@ pub fn create_watchtower_challenge_txhandler( } } +pub fn create_operator_challenge_nack_txhandler( + wcp_txid: Txid, + time_txid: Txid, + time_tx_amount: Amount, + watchtower_idx: usize, + operator_unlock_hash: &[u8; 20], + nofn_xonly_pk: XOnlyPublicKey, + operator_xonly_pk: XOnlyPublicKey, + network: bitcoin::Network, +) -> TxHandler { + let tx_ins = create_tx_ins(vec![ + OutPoint { + txid: wcp_txid, + vout: watchtower_idx as u32, + }, + OutPoint { + txid: time_txid, + vout: 0, + }, + ]); + + let tx_outs = vec![builder::script::anyone_can_spend_txout()]; + + let challenge_nack_tx = create_btc_tx(tx_ins, tx_outs); + + let nofn_1week = builder::script::generate_relative_timelock_script(nofn_xonly_pk, 7 * 24 * 6); + let operator_with_preimage = + builder::script::actor_with_preimage_script(operator_xonly_pk, operator_unlock_hash); + let (nofn_or_nofn_1week, nofn_or_nofn_1week_taproot_spend_info) = + builder::address::create_taproot_address( + &[operator_with_preimage.clone(), nofn_1week.clone()], + None, + network, + ); + + let prevouts = vec![ + TxOut { + value: Amount::from_sat(1000), // TODO: Hand calculate this + script_pubkey: nofn_or_nofn_1week.script_pubkey(), + }, + TxOut { + value: time_tx_amount, + script_pubkey: builder::address::create_musig2_address(operator_xonly_pk, network) + .0 + .script_pubkey(), + }, + ]; + + TxHandler { + tx: challenge_nack_tx, + prevouts, + scripts: vec![vec![operator_with_preimage, nofn_1week]], + taproot_spend_infos: vec![nofn_or_nofn_1week_taproot_spend_info], + } +} + pub fn create_slash_or_take_tx( deposit_outpoint: OutPoint, kickoff_utxo: UTXO, diff --git a/core/src/rpc/aggregator.rs b/core/src/rpc/aggregator.rs index 884abdf6..361b0ecc 100644 --- a/core/src/rpc/aggregator.rs +++ b/core/src/rpc/aggregator.rs @@ -3,7 +3,7 @@ use super::clementine::{ }; use crate::{ aggregator::Aggregator, - builder::sighash::create_nofn_sighash_stream, + builder::sighash::{calculate_num_required_sigs, create_nofn_sighash_stream}, errors::BridgeError, musig2::{aggregate_nonces, MuSigPubNonce}, rpc::clementine::{self, DepositSignSession}, @@ -218,9 +218,11 @@ impl ClementineAggregator for Aggregator { tracing::debug!("Parsed deposit params"); // generate nonces from all verifiers - let num_required_sigs = self.config.num_operators - * self.config.num_time_txs - * (1 + self.config.num_watchtowers); + let num_required_sigs = calculate_num_required_sigs( + self.config.num_operators, + self.config.num_time_txs, + self.config.num_watchtowers, + ); let (first_responses, mut nonce_streams) = self.create_nonce_streams(num_required_sigs as u32).await?; @@ -310,9 +312,12 @@ impl ClementineAggregator for Aggregator { self.config.bridge_amount_sats, self.config.network, )); - let num_required_sigs = self.config.num_operators - * self.config.num_time_txs - * (1 + self.config.num_watchtowers); + + let num_required_sigs = calculate_num_required_sigs( + self.config.num_operators, + self.config.num_time_txs, + self.config.num_watchtowers, + ); for _ in 0..num_required_sigs { // Get the next nonce from each stream diff --git a/core/src/rpc/verifier.rs b/core/src/rpc/verifier.rs index f2ca3d54..a5a7eb8d 100644 --- a/core/src/rpc/verifier.rs +++ b/core/src/rpc/verifier.rs @@ -4,7 +4,10 @@ use super::clementine::{ VerifierDepositSignParams, VerifierParams, VerifierPublicKeys, WatchtowerParams, }; use crate::{ - builder::{self, sighash::create_nofn_sighash_stream}, + builder::{ + self, + sighash::{calculate_num_required_sigs, create_nofn_sighash_stream}, + }, errors::BridgeError, musig2::{self, MuSigPubNonce, MuSigSecNonce}, sha256_hash, utils, @@ -347,10 +350,11 @@ impl ClementineVerifier for Verifier { verifier.config.bridge_amount_sats, verifier.config.network, )); - let num_required_sigs = verifier.config.num_operators - * verifier.config.num_time_txs - * (1 + verifier.config.num_watchtowers); - + let num_required_sigs = calculate_num_required_sigs( + verifier.config.num_operators, + verifier.config.num_time_txs, + verifier.config.num_watchtowers, + ); while let Some(result) = in_stream.message().await.unwrap() { let agg_nonce = match result .params @@ -463,10 +467,11 @@ impl ClementineVerifier for Verifier { self.config.bridge_amount_sats, self.config.network, )); - let num_required_sigs = self.config.num_operators - * self.config.num_time_txs - * (1 + self.config.num_watchtowers); - + let num_required_sigs = calculate_num_required_sigs( + self.config.num_operators, + self.config.num_time_txs, + self.config.num_watchtowers, + ); let mut nonce_idx: usize = 0; while let Some(result) = in_stream.message().await.unwrap() { let sighash = sighash_stream.next().await.unwrap().unwrap();