From b9be24eb370a302cf33c87f8cc208871fcfbf4fc Mon Sep 17 00:00:00 2001 From: ozankaymak Date: Thu, 22 Aug 2024 17:01:59 +0300 Subject: [PATCH 1/8] WIP Implement endpoints with db operations and tests --- core/src/database/common.rs | 63 +++++++++++++++++++++++++++++++++++++ core/src/errors.rs | 18 +++++++++++ core/src/lib.rs | 9 ++++++ core/src/operator.rs | 17 ++++++++++ core/src/traits/rpc.rs | 11 ++++--- core/src/verifier.rs | 16 +++++++++- scripts/schema.sql | 7 +++++ 7 files changed, 135 insertions(+), 6 deletions(-) diff --git a/core/src/database/common.rs b/core/src/database/common.rs index e26fc050..c2ac707e 100644 --- a/core/src/database/common.rs +++ b/core/src/database/common.rs @@ -442,6 +442,39 @@ impl Database { None => Ok(None), } } + + pub async fn save_kickoff_root( + &self, + deposit_outpoint: OutPoint, + kickoff_root: [u8; 32], + ) -> Result<(), BridgeError> { + sqlx::query( + "INSERT INTO kickoff_roots (deposit_outpoint, kickoff_merkle_root) VALUES ($1, $2);", + ) + .bind(OutPointDB(deposit_outpoint)) + .bind(hex::encode(kickoff_root)) + .execute(&self.connection) + .await?; + + Ok(()) + } + + pub async fn get_kickoff_root( + &self, + deposit_outpoint: OutPoint, + ) -> Result, BridgeError> { + let qr: Option = sqlx::query_scalar( + "SELECT kickoff_merkle_root FROM kickoff_roots WHERE deposit_outpoint = $1;", + ) + .bind(OutPointDB(deposit_outpoint)) + .fetch_optional(&self.connection) + .await?; + + match qr { + Some(root) => Ok(Some(hex::decode(root)?.try_into()?)), + None => Ok(None), + } + } } #[cfg(test)] @@ -868,6 +901,36 @@ mod tests { let res = db.get_deposit_kickoff_generator_tx(txid).await.unwrap(); assert!(res.is_none()); } + + #[tokio::test] + async fn test_kickoff_root_1() { + let config = create_test_config_with_thread_name!("test_config.toml"); + let db = Database::new(config).await.unwrap(); + + let outpoint = OutPoint { + txid: Txid::from_byte_array([1u8; 32]), + vout: 1, + }; + let root = [1u8; 32]; + db.save_kickoff_root(outpoint, root).await.unwrap(); + let db_root = db.get_kickoff_root(outpoint).await.unwrap().unwrap(); + + // Sanity check + assert_eq!(db_root, root); + } + + #[tokio::test] + async fn test_kickoff_root_2() { + let config = create_test_config_with_thread_name!("test_config.toml"); + let db = Database::new(config).await.unwrap(); + + let outpoint = OutPoint { + txid: Txid::from_byte_array([1u8; 32]), + vout: 1, + }; + let res = db.get_kickoff_root(outpoint).await.unwrap(); + assert!(res.is_none()); + } } #[cfg(poc)] diff --git a/core/src/errors.rs b/core/src/errors.rs index def8880a..cdd057fa 100644 --- a/core/src/errors.rs +++ b/core/src/errors.rs @@ -158,6 +158,12 @@ pub enum BridgeError { KickoffOutpointsNotFound, #[error("DepositInfoNotFound")] DepositInfoNotFound, + + #[error("FromHexError: {0}")] + FromHexError(hex::FromHexError), + + #[error("FromSliceError: {0}")] + FromSliceError(bitcoin::hashes::FromSliceError), } impl Into> for BridgeError { @@ -261,3 +267,15 @@ impl From for BridgeError { BridgeError::MuSig2VerifyError(err) } } + +impl From for BridgeError { + fn from(err: hex::FromHexError) -> Self { + BridgeError::FromHexError(err) + } +} + +impl From for BridgeError { + fn from(err: bitcoin::hashes::FromSliceError) -> Self { + BridgeError::FromSliceError(err) + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index 92c6fc0a..711c7e9f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -44,6 +44,15 @@ pub struct UTXO { pub txout: bitcoin::TxOut, } +impl UTXO { + fn to_vec(&self) -> Vec { + let outpoint_hex = bitcoin::consensus::encode::serialize_hex(&self.outpoint); + let txout_hex = bitcoin::consensus::encode::serialize_hex(&self.txout); + let all = format!("{}{}", outpoint_hex, txout_hex); + hex::decode(all).unwrap() + } +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, sqlx::Type)] #[sqlx(type_name = "bytea")] pub struct ByteArray66(#[serde(with = "hex::serde")] pub [u8; 66]); diff --git a/core/src/operator.rs b/core/src/operator.rs index 6de4795d..aecb8511 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -272,6 +272,14 @@ where let final_txid = self.rpc.send_raw_transaction(&signed_tx)?; Ok(Some(final_txid)) } + + async fn withdrawal_proved_on_citrea( + &self, + withdrawal_idx: usize, + kickoff_merkle_root: [u8; 32], + ) -> Result<(), BridgeError> { + Ok(()) + } } #[async_trait] @@ -303,4 +311,13 @@ where self.new_withdrawal_sig(withdrawal_idx, user_sig, input_utxo, output_txout) .await } + + async fn withdrawal_proved_on_citrea_rpc( + &self, + withdrawal_idx: usize, + kickoff_merkle_root: [u8; 32], + ) -> Result<(), BridgeError> { + self.withdrawal_proved_on_citrea(withdrawal_idx, kickoff_merkle_root) + .await + } } diff --git a/core/src/traits/rpc.rs b/core/src/traits/rpc.rs index 9eebee8c..4ea92651 100644 --- a/core/src/traits/rpc.rs +++ b/core/src/traits/rpc.rs @@ -80,11 +80,12 @@ pub trait OperatorRpc { output_txout: TxOut, ) -> Result, BridgeError>; - // #[method(name = "withdrawal_proved_on_citrea")] - // async fn withdrawal_proved_on_citrea_rpc( - // &self, - // withdrawal_idx: usize, - // ) -> Result<(), BridgeError>; + #[method(name = "withdrawal_proved_on_citrea")] + async fn withdrawal_proved_on_citrea_rpc( + &self, + withdrawal_idx: usize, + kickoff_merkle_root: [u8; 32], + ) -> Result<(), BridgeError>; // #[method(name = "operator_take_sendable")] // async fn operator_take_sendable_rpc(&self, withdrawal_idx: usize) -> Result<(), BridgeError>; diff --git a/core/src/verifier.rs b/core/src/verifier.rs index 0daecd1f..089d9d2d 100644 --- a/core/src/verifier.rs +++ b/core/src/verifier.rs @@ -3,6 +3,7 @@ use crate::config::BridgeConfig; use crate::database::verifier::VerifierDB; use crate::errors::BridgeError; use crate::extended_rpc::ExtendedRpc; +use crate::merkle::MerkleTree; use crate::musig2::{self, MuSigAggNonce, MuSigPartialSignature, MuSigPubNonce}; use crate::traits::rpc::VerifierRpcServer; use crate::transaction_builder::{TransactionBuilder, TxHandler}; @@ -10,10 +11,11 @@ use crate::{utils, EVMAddress, UTXO}; use ::musig2::secp::Point; use bitcoin::address::NetworkUnchecked; use bitcoin::hashes::Hash; -use bitcoin::Address; +use bitcoin::{merkle_tree, Address}; use bitcoin::{secp256k1, OutPoint}; use bitcoin_mock_rpc::RpcApiWrapper; use clementine_circuits::constants::BRIDGE_AMOUNT_SATS; +use clementine_circuits::incremental_merkle::IncrementalMerkleTree; use clementine_circuits::sha256_hash; use jsonrpsee::core::async_trait; use secp256k1::{rand, schnorr}; @@ -153,6 +155,14 @@ where )?; } + let root: bitcoin::hashes::sha256::Hash = bitcoin::merkle_tree::calculate_root( + kickoff_utxos + .iter() + .map(|utxo| Hash::from_byte_array(sha256_hash!(utxo.to_vec().as_slice()))), + ) + .unwrap(); + let root_bytes: [u8; 32] = *root.as_byte_array(); + self.db .save_agg_nonces(deposit_outpoint, &agg_nonces) .await?; @@ -161,6 +171,10 @@ where .save_kickoff_utxos(deposit_outpoint, &kickoff_utxos) .await?; + self.db + .save_kickoff_root(deposit_outpoint, root_bytes) + .await?; + // TODO: Sign burn txs Ok(vec![]) } diff --git a/scripts/schema.sql b/scripts/schema.sql index 426d864e..2c070609 100644 --- a/scripts/schema.sql +++ b/scripts/schema.sql @@ -90,4 +90,11 @@ create table funding_utxos ( created_at timestamp not null default now() ); +-- Verifier table for kickoff merkle roots for deposits +create table kickoff_roots ( + deposit_outpoint text primary key not null check (deposit_outpoint ~ '^[a-fA-F0-9]{64}:(0|[1-9][0-9]{0,9})$'), + kickoff_merkle_root text not null check (kickoff_merkle_root ~ '^[a-fA-F0-9]{64}'), + created_at timestamp not null default now() +); + COMMIT; From a0e9b0961753f7d16e878d4590ba6ad6190c8416 Mon Sep 17 00:00:00 2001 From: Ekrem BAL Date: Fri, 23 Aug 2024 11:40:33 +0300 Subject: [PATCH 2/8] wip --- core/src/traits/rpc.rs | 4 ++-- core/src/transaction_builder.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/traits/rpc.rs b/core/src/traits/rpc.rs index 4ea92651..5a55cf47 100644 --- a/core/src/traits/rpc.rs +++ b/core/src/traits/rpc.rs @@ -24,14 +24,13 @@ pub trait VerifierRpc { /// - Check the kickoff_utxos /// - for every kickoff_utxo, calculate kickoff2_tx /// - for every kickoff2_tx, partial sign burn_tx (ommitted for now) - /// - return MuSigPartialSignature of sign(kickoff2_txids) async fn operator_kickoffs_generated_rpc( &self, deposit_utxo: OutPoint, kickoff_utxos: Vec, operators_kickoff_sigs: Vec, agg_nonces: Vec, - ) -> Result, BridgeError>; + ) -> Result<(Vec, Vec), BridgeError>; #[method(name = "burn_txs_signed")] /// verify burn txs are signed by verifiers @@ -40,6 +39,7 @@ pub trait VerifierRpc { &self, deposit_utxo: OutPoint, burn_sigs: Vec, + slash_or_take_sigs: Vec, ) -> Result, BridgeError>; // operator_take_txs_signed diff --git a/core/src/transaction_builder.rs b/core/src/transaction_builder.rs index 64428d46..ff09f158 100644 --- a/core/src/transaction_builder.rs +++ b/core/src/transaction_builder.rs @@ -287,7 +287,7 @@ impl TransactionBuilder { } /// Creates the kickoff_tx for the operator. It also returns the change utxo - pub fn create_kickoff_tx(funding_utxo: &UTXO, address: &Address) -> TxHandler { + pub fn create_kickoff_tx(funding_utxo: &UTXO, nofn_xonly_pk: &XOnlyPublicKey, operator_xonly_pk: &XOnlyPublicKey) -> TxHandler { let tx_ins = TransactionBuilder::create_tx_ins(vec![funding_utxo.outpoint]); let change_amount = funding_utxo.txout.value From cbef569e692ea285fb74bb40226143541689c89e Mon Sep 17 00:00:00 2001 From: ozankaymak Date: Fri, 23 Aug 2024 11:58:19 +0300 Subject: [PATCH 3/8] WIP --- core/src/operator.rs | 9 +- core/src/transaction_builder.rs | 289 +++++++++++++++++++------------- core/src/verifier.rs | 110 ++++++------ 3 files changed, 227 insertions(+), 181 deletions(-) diff --git a/core/src/operator.rs b/core/src/operator.rs index aecb8511..856954ca 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -134,8 +134,11 @@ where )); } - let kickoff_tx_handler = - TransactionBuilder::create_kickoff_tx(&funding_utxo, &self.signer.address); + let kickoff_tx_handler = TransactionBuilder::create_kickoff_tx( + &funding_utxo, + &self.nofn_xonly_pk, + &self.signer.xonly_public_key, + ); let change_utxo = UTXO { outpoint: OutPoint { @@ -240,7 +243,7 @@ where &Message::from_digest_slice(sighash.as_byte_array()).expect("should be hash"), &user_xonly_pk, )?; - let op_return_txout = script_builder::op_return_txout(5u32.to_be_bytes()); // TODO: Instead of 5u32 use the index of the operator. + let op_return_txout = script_builder::op_return_txout(self..to_be_bytes()); // TODO: Instead of 5u32 use the index of the operator. tx.output.push(op_return_txout.clone()); let funded_tx = self .rpc diff --git a/core/src/transaction_builder.rs b/core/src/transaction_builder.rs index ff09f158..3aa38c7c 100644 --- a/core/src/transaction_builder.rs +++ b/core/src/transaction_builder.rs @@ -30,8 +30,9 @@ pub struct TransactionBuilder { } // TODO: Move these constants to a config file -pub const MOVE_COMMIT_TX_MIN_RELAY_FEE: u64 = 305; -pub const MOVE_REVEAL_TX_MIN_RELAY_FEE: u64 = 305; +// pub const MOVE_COMMIT_TX_MIN_RELAY_FEE: u64 = 305; +// pub const MOVE_REVEAL_TX_MIN_RELAY_FEE: u64 = 305; +pub const MOVE_TX_MIN_RELAY_FEE: u64 = 305; pub const WITHDRAWAL_TX_MIN_RELAY_FEE: u64 = 305; impl TransactionBuilder { @@ -126,38 +127,38 @@ impl TransactionBuilder { ) } - pub fn generate_move_commit_address( - nofn_xonly_pk: &XOnlyPublicKey, - recovery_taproot_address: &Address, - user_evm_address: &EVMAddress, - kickoff_utxos: &[OutPoint], - relative_block_height_to_take_after: u32, - network: bitcoin::Network, - ) -> CreateAddressOutputs { - let kickoffs_commit_script = script_builder::create_move_commit_script( - nofn_xonly_pk, - user_evm_address, - kickoff_utxos, - ); - - let recovery_script_pubkey = recovery_taproot_address - .clone() - .assume_checked() - .script_pubkey(); - let recovery_extracted_xonly_pk = - XOnlyPublicKey::from_slice(&recovery_script_pubkey.as_bytes()[2..34]).unwrap(); - - let timelock_script = script_builder::generate_relative_timelock_script( - &recovery_extracted_xonly_pk, - relative_block_height_to_take_after, - ); - - TransactionBuilder::create_taproot_address( - &[kickoffs_commit_script, timelock_script], - None, - network, - ) - } + // pub fn generate_move_commit_address( + // nofn_xonly_pk: &XOnlyPublicKey, + // recovery_taproot_address: &Address, + // user_evm_address: &EVMAddress, + // kickoff_utxos: &[OutPoint], + // relative_block_height_to_take_after: u32, + // network: bitcoin::Network, + // ) -> CreateAddressOutputs { + // let kickoffs_commit_script = script_builder::create_move_commit_script( + // nofn_xonly_pk, + // user_evm_address, + // kickoff_utxos, + // ); + + // let recovery_script_pubkey = recovery_taproot_address + // .clone() + // .assume_checked() + // .script_pubkey(); + // let recovery_extracted_xonly_pk = + // XOnlyPublicKey::from_slice(&recovery_script_pubkey.as_bytes()[2..34]).unwrap(); + + // let timelock_script = script_builder::generate_relative_timelock_script( + // &recovery_extracted_xonly_pk, + // relative_block_height_to_take_after, + // ); + + // TransactionBuilder::create_taproot_address( + // &[kickoffs_commit_script, timelock_script], + // None, + // network, + // ) + // } pub fn create_musig2_address( nofn_xonly_pk: XOnlyPublicKey, @@ -168,26 +169,135 @@ impl TransactionBuilder { // TX BUILDERS - pub fn create_move_commit_tx( - deposit_utxo: OutPoint, + // pub fn create_move_commit_tx( + // deposit_utxo: OutPoint, + // evm_address: &EVMAddress, + // recovery_taproot_address: &Address, + // deposit_user_takes_after: u32, + // nofn_xonly_pk: &XOnlyPublicKey, + // kickoff_utxos: &[OutPoint], + // relative_block_height_to_take_after: u32, + // network: bitcoin::Network, + // ) -> TxHandler { + // let anyone_can_spend_txout = script_builder::anyone_can_spend_txout(); + // let (move_commit_address, _) = TransactionBuilder::generate_move_commit_address( + // nofn_xonly_pk, + // recovery_taproot_address, + // evm_address, + // kickoff_utxos, + // relative_block_height_to_take_after, + // network, + // ); + + // let (deposit_address, deposit_taproot_spend_info) = + // TransactionBuilder::generate_deposit_address( + // nofn_xonly_pk, + // recovery_taproot_address, + // evm_address, + // BRIDGE_AMOUNT_SATS, + // deposit_user_takes_after, + // network, + // ); + + // let move_commit_txout = TxOut { + // value: Amount::from_sat(BRIDGE_AMOUNT_SATS) + // - Amount::from_sat(MOVE_COMMIT_TX_MIN_RELAY_FEE) + // - anyone_can_spend_txout.value, + // script_pubkey: move_commit_address.script_pubkey(), + // }; + + // let tx_ins = TransactionBuilder::create_tx_ins(vec![deposit_utxo]); + + // let move_commit_tx = TransactionBuilder::create_btc_tx( + // tx_ins, + // vec![move_commit_txout, anyone_can_spend_txout], + // ); + + // let prevouts = vec![TxOut { + // script_pubkey: deposit_address.script_pubkey(), + // value: Amount::from_sat(BRIDGE_AMOUNT_SATS), + // }]; + + // let deposit_script = vec![script_builder::create_deposit_script( + // nofn_xonly_pk, + // evm_address, + // BRIDGE_AMOUNT_SATS, + // )]; + + // TxHandler { + // tx: move_commit_tx, + // prevouts, + // scripts: vec![deposit_script], + // taproot_spend_infos: vec![deposit_taproot_spend_info], + // } + // } + + // pub fn create_move_reveal_tx( + // move_commit_utxo: OutPoint, + // evm_address: &EVMAddress, + // recovery_taproot_address: &Address, + // nofn_xonly_pk: &XOnlyPublicKey, + // kickoff_utxos: &[OutPoint], + // relative_block_height_to_take_after: u32, + // network: Network, + // ) -> TxHandler { + // let (musig2_address, _) = + // TransactionBuilder::create_musig2_address(*nofn_xonly_pk, network); + // let (move_commit_address, move_commit_taproot_spend_info) = + // TransactionBuilder::generate_move_commit_address( + // nofn_xonly_pk, + // recovery_taproot_address, + // evm_address, + // kickoff_utxos, + // relative_block_height_to_take_after, + // network, + // ); + // let move_reveal_txout = TxOut { + // value: Amount::from_sat(BRIDGE_AMOUNT_SATS) + // - Amount::from_sat(MOVE_COMMIT_TX_MIN_RELAY_FEE) + // - Amount::from_sat(MOVE_REVEAL_TX_MIN_RELAY_FEE) + // - script_builder::anyone_can_spend_txout().value + // - script_builder::anyone_can_spend_txout().value, + // script_pubkey: musig2_address.script_pubkey(), + // }; + + // let tx_ins = TransactionBuilder::create_tx_ins(vec![move_commit_utxo]); + + // let move_reveal_tx = TransactionBuilder::create_btc_tx( + // tx_ins, + // vec![move_reveal_txout, script_builder::anyone_can_spend_txout()], + // ); + + // let prevouts = vec![TxOut { + // script_pubkey: move_commit_address.script_pubkey(), + // value: Amount::from_sat(BRIDGE_AMOUNT_SATS), + // }]; + + // let move_commit_script = vec![script_builder::create_move_commit_script( + // nofn_xonly_pk, + // evm_address, + // kickoff_utxos, + // )]; + + // TxHandler { + // tx: move_reveal_tx, + // prevouts, + // scripts: vec![move_commit_script], + // taproot_spend_infos: vec![move_commit_taproot_spend_info], + // } + // } + + /// Creates the move_tx to move the deposit. + pub fn create_move_tx( + deposit_outpoint: OutPoint, evm_address: &EVMAddress, recovery_taproot_address: &Address, deposit_user_takes_after: u32, nofn_xonly_pk: &XOnlyPublicKey, - kickoff_utxos: &[OutPoint], - relative_block_height_to_take_after: u32, network: bitcoin::Network, ) -> TxHandler { let anyone_can_spend_txout = script_builder::anyone_can_spend_txout(); - let (move_commit_address, _) = TransactionBuilder::generate_move_commit_address( - nofn_xonly_pk, - recovery_taproot_address, - evm_address, - kickoff_utxos, - relative_block_height_to_take_after, - network, - ); - + let (musig2_address, _) = Self::create_musig2_address(*nofn_xonly_pk, network); let (deposit_address, deposit_taproot_spend_info) = TransactionBuilder::generate_deposit_address( nofn_xonly_pk, @@ -197,97 +307,38 @@ impl TransactionBuilder { deposit_user_takes_after, network, ); - - let move_commit_txout = TxOut { + let move_txout = TxOut { value: Amount::from_sat(BRIDGE_AMOUNT_SATS) - - Amount::from_sat(MOVE_COMMIT_TX_MIN_RELAY_FEE) + - Amount::from_sat(MOVE_TX_MIN_RELAY_FEE) - anyone_can_spend_txout.value, - script_pubkey: move_commit_address.script_pubkey(), + script_pubkey: musig2_address.script_pubkey(), }; - - let tx_ins = TransactionBuilder::create_tx_ins(vec![deposit_utxo]); - - let move_commit_tx = TransactionBuilder::create_btc_tx( - tx_ins, - vec![move_commit_txout, anyone_can_spend_txout], - ); - + let tx_ins = TransactionBuilder::create_tx_ins(vec![deposit_outpoint]); + let move_tx = + TransactionBuilder::create_btc_tx(tx_ins, vec![move_txout, anyone_can_spend_txout]); let prevouts = vec![TxOut { script_pubkey: deposit_address.script_pubkey(), value: Amount::from_sat(BRIDGE_AMOUNT_SATS), }]; - let deposit_script = vec![script_builder::create_deposit_script( nofn_xonly_pk, evm_address, BRIDGE_AMOUNT_SATS, )]; - TxHandler { - tx: move_commit_tx, + tx: move_tx, prevouts, scripts: vec![deposit_script], taproot_spend_infos: vec![deposit_taproot_spend_info], } } - pub fn create_move_reveal_tx( - move_commit_utxo: OutPoint, - evm_address: &EVMAddress, - recovery_taproot_address: &Address, + /// Creates the kickoff_tx for the operator. It also returns the change utxo + pub fn create_kickoff_tx( + funding_utxo: &UTXO, nofn_xonly_pk: &XOnlyPublicKey, - kickoff_utxos: &[OutPoint], - relative_block_height_to_take_after: u32, - network: Network, + operator_xonly_pk: &XOnlyPublicKey, ) -> TxHandler { - let (musig2_address, _) = - TransactionBuilder::create_musig2_address(*nofn_xonly_pk, network); - let (move_commit_address, move_commit_taproot_spend_info) = - TransactionBuilder::generate_move_commit_address( - nofn_xonly_pk, - recovery_taproot_address, - evm_address, - kickoff_utxos, - relative_block_height_to_take_after, - network, - ); - let move_reveal_txout = TxOut { - value: Amount::from_sat(BRIDGE_AMOUNT_SATS) - - Amount::from_sat(MOVE_COMMIT_TX_MIN_RELAY_FEE) - - Amount::from_sat(MOVE_REVEAL_TX_MIN_RELAY_FEE) - - script_builder::anyone_can_spend_txout().value - - script_builder::anyone_can_spend_txout().value, - script_pubkey: musig2_address.script_pubkey(), - }; - - let tx_ins = TransactionBuilder::create_tx_ins(vec![move_commit_utxo]); - - let move_reveal_tx = TransactionBuilder::create_btc_tx( - tx_ins, - vec![move_reveal_txout, script_builder::anyone_can_spend_txout()], - ); - - let prevouts = vec![TxOut { - script_pubkey: move_commit_address.script_pubkey(), - value: Amount::from_sat(BRIDGE_AMOUNT_SATS), - }]; - - let move_commit_script = vec![script_builder::create_move_commit_script( - nofn_xonly_pk, - evm_address, - kickoff_utxos, - )]; - - TxHandler { - tx: move_reveal_tx, - prevouts, - scripts: vec![move_commit_script], - taproot_spend_infos: vec![move_commit_taproot_spend_info], - } - } - - /// Creates the kickoff_tx for the operator. It also returns the change utxo - pub fn create_kickoff_tx(funding_utxo: &UTXO, nofn_xonly_pk: &XOnlyPublicKey, operator_xonly_pk: &XOnlyPublicKey) -> TxHandler { let tx_ins = TransactionBuilder::create_tx_ins(vec![funding_utxo.outpoint]); let change_amount = funding_utxo.txout.value @@ -428,10 +479,10 @@ impl TransactionBuilder { } } - pub fn create_tx_ins(utxos: Vec) -> Vec { + pub fn create_tx_ins(outpoints: Vec) -> Vec { let mut tx_ins = Vec::new(); - for utxo in utxos { + for utxo in outpoints { tx_ins.push(TxIn { previous_output: utxo, sequence: bitcoin::transaction::Sequence::ENABLE_RBF_NO_LOCKTIME, diff --git a/core/src/verifier.rs b/core/src/verifier.rs index 089d9d2d..c5e6154a 100644 --- a/core/src/verifier.rs +++ b/core/src/verifier.rs @@ -182,7 +182,7 @@ where async fn create_deposit_details( &self, deposit_outpoint: OutPoint, - ) -> Result<(Vec, TxHandler, TxHandler, OutPoint), BridgeError> { + ) -> Result<(Vec, TxHandler, OutPoint), BridgeError> { let kickoff_utxos = self .db .get_kickoff_utxos(deposit_outpoint) @@ -200,40 +200,44 @@ where .await? .ok_or(BridgeError::DepositInfoNotFound)?; - let move_commit_tx_handler = TransactionBuilder::create_move_commit_tx( + // let move_commit_tx_handler = TransactionBuilder::create_move_commit_tx( + // deposit_outpoint, + // &evm_address, + // &recovery_taproot_address, + // 200, // TODO: Fix this + // &self.nofn_xonly_pk, + // &kickoff_outpoints, + // 201, // TODO: Fix this + // self.config.network, + // ); + + // let move_reveal_tx_handler = TransactionBuilder::create_move_reveal_tx( + // OutPoint { + // txid: move_commit_tx_handler.tx.compute_txid(), + // vout: 0, + // }, + // &evm_address, + // &recovery_taproot_address, + // &self.nofn_xonly_pk, + // &kickoff_outpoints, + // 201, // TODO: Fix this + // self.config.network, + // ); + + let move_tx_handler = TransactionBuilder::create_move_tx( deposit_outpoint, &evm_address, &recovery_taproot_address, 200, // TODO: Fix this &self.nofn_xonly_pk, - &kickoff_outpoints, - 201, // TODO: Fix this - self.config.network, - ); - - let move_reveal_tx_handler = TransactionBuilder::create_move_reveal_tx( - OutPoint { - txid: move_commit_tx_handler.tx.compute_txid(), - vout: 0, - }, - &evm_address, - &recovery_taproot_address, - &self.nofn_xonly_pk, - &kickoff_outpoints, - 201, // TODO: Fix this self.config.network, ); let bridge_fund_outpoint = OutPoint { - txid: move_reveal_tx_handler.tx.compute_txid(), + txid: move_tx_handler.tx.compute_txid(), vout: 0, }; - Ok(( - kickoff_utxos, - move_commit_tx_handler, - move_reveal_tx_handler, - bridge_fund_outpoint, - )) + Ok((kickoff_utxos, move_tx_handler, bridge_fund_outpoint)) } /// verify burn txs are signed by verifiers @@ -244,7 +248,7 @@ where _burn_sigs: Vec, ) -> Result, BridgeError> { // TODO: Verify burn txs are signed by verifiers - let (kickoff_utxos, _, _, bridge_fund_outpoint) = + let (kickoff_utxos, _, bridge_fund_outpoint) = self.create_deposit_details(deposit_outpoint).await?; let operator_takes_sighashes = kickoff_utxos @@ -311,13 +315,9 @@ where &self, deposit_outpoint: OutPoint, operator_take_sigs: Vec, - ) -> Result<(MuSigPartialSignature, MuSigPartialSignature), BridgeError> { - let ( - kickoff_utxos, - mut move_commit_tx_handler, - mut move_reveal_tx_handler, - bridge_fund_outpoint, - ) = self.create_deposit_details(deposit_outpoint).await?; + ) -> Result { + let (kickoff_utxos, mut move_tx_handler, bridge_fund_outpoint) = + self.create_deposit_details(deposit_outpoint).await?; let _ = kickoff_utxos .iter() @@ -361,47 +361,39 @@ where .unwrap(); }); - let move_commit_sighash = - Actor::convert_tx_to_sighash_script_spend(&mut move_commit_tx_handler, 0, 0)?; // TODO: This should be musig + let move_tx_sighash = + Actor::convert_tx_to_sighash_script_spend(&mut move_tx_handler, 0, 0)?; // TODO: This should be musig - let move_reveal_sighash = - Actor::convert_tx_to_sighash_script_spend(&mut move_reveal_tx_handler, 0, 0)?; // TODO: This should be musig + // let move_reveal_sighash = + // Actor::convert_tx_to_sighash_script_spend(&mut move_reveal_tx_handler, 0, 0)?; // TODO: This should be musig let nonces = self .db - .save_sighashes_and_get_nonces( - deposit_outpoint, - 0, - &[ - move_commit_sighash.to_byte_array(), - move_reveal_sighash.to_byte_array(), - ], - ) + .save_sighashes_and_get_nonces(deposit_outpoint, 0, &[move_tx_sighash.to_byte_array()]) .await? .ok_or(BridgeError::NoncesNotFound)?; - let move_commit_sig = musig2::partial_sign( + let move_tx_sig = musig2::partial_sign( self.config.verifiers_public_keys.clone(), None, nonces[0].0, nonces[0].1.clone(), &self.signer.keypair, - move_commit_sighash.to_byte_array(), - ); - - let move_reveal_sig = musig2::partial_sign( - self.config.verifiers_public_keys.clone(), - None, - nonces[1].0, - nonces[2].1.clone(), - &self.signer.keypair, - move_reveal_sighash.to_byte_array(), + move_tx_sighash.to_byte_array(), ); - Ok(( - move_commit_sig as MuSigPartialSignature, - move_reveal_sig as MuSigPartialSignature, - )) + // let move_reveal_sig = musig2::partial_sign( + // self.config.verifiers_public_keys.clone(), + // None, + // nonces[1].0, + // nonces[2].1.clone(), + // &self.signer.keypair, + // move_reveal_sighash.to_byte_array(), + // ); + + Ok( + move_tx_sig as MuSigPartialSignature, // move_reveal_sig as MuSigPartialSignature, + ) } } From 46c577dc139d052be5937ba8dcdf045167964327 Mon Sep 17 00:00:00 2001 From: ozankaymak Date: Fri, 23 Aug 2024 14:20:47 +0300 Subject: [PATCH 4/8] WIP --- core/src/operator.rs | 11 ++++- core/src/script_builder.rs | 44 +++++++++++++------- core/src/transaction_builder.rs | 74 +++++++++++++++++++++++++++------ core/src/verifier.rs | 19 ++++++--- core/tests/flow.rs | 43 +++++++++++++------ 5 files changed, 142 insertions(+), 49 deletions(-) diff --git a/core/src/operator.rs b/core/src/operator.rs index 856954ca..ec7bd107 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -35,6 +35,7 @@ where signer: Actor, config: BridgeConfig, nofn_xonly_pk: secp256k1::XOnlyPublicKey, + idx: usize, } impl Operator @@ -43,7 +44,7 @@ where { /// Creates a new `Operator`. pub async fn new(config: BridgeConfig, rpc: ExtendedRpc) -> Result { - let num_verifiers = config.verifiers_public_keys.len(); + // let num_verifiers = config.verifiers_public_keys.len(); let signer = Actor::new(config.secret_key, config.network); @@ -53,6 +54,11 @@ where musig2::create_key_agg_ctx(config.verifiers_public_keys.clone(), None)?; let agg_point: Point = key_agg_context.aggregated_pubkey_untweaked(); let nofn_xonly_pk = secp256k1::XOnlyPublicKey::from_slice(&agg_point.serialize_xonly())?; + let idx = config + .operators_xonly_pks + .iter() + .position(|xonly_pk| xonly_pk == &nofn_xonly_pk) + .unwrap(); Ok(Self { rpc, @@ -60,6 +66,7 @@ where signer, config, nofn_xonly_pk, + idx, }) } @@ -243,7 +250,7 @@ where &Message::from_digest_slice(sighash.as_byte_array()).expect("should be hash"), &user_xonly_pk, )?; - let op_return_txout = script_builder::op_return_txout(self..to_be_bytes()); // TODO: Instead of 5u32 use the index of the operator. + let op_return_txout = script_builder::op_return_txout(self.idx.to_be_bytes()); tx.output.push(op_return_txout.clone()); let funded_tx = self .rpc diff --git a/core/src/script_builder.rs b/core/src/script_builder.rs index 66be80cc..4f512879 100644 --- a/core/src/script_builder.rs +++ b/core/src/script_builder.rs @@ -57,28 +57,40 @@ pub fn create_deposit_script( .into_script() } -pub fn create_move_commit_script( +pub fn create_musig2_and_operator_multisig_script( nofn_xonly_pk: &XOnlyPublicKey, - evm_address: &EVMAddress, - kickoff_utxos: &[OutPoint], + operator_xonly_pk: &XOnlyPublicKey, ) -> ScriptBuf { - let citrea: [u8; 6] = "citrea".as_bytes().try_into().unwrap(); - - let builder = Builder::new() + Builder::new() .push_x_only_key(nofn_xonly_pk) + .push_opcode(OP_CHECKSIGVERIFY) + .push_x_only_key(operator_xonly_pk) .push_opcode(OP_CHECKSIG) - .push_opcode(OP_FALSE) - .push_opcode(OP_IF) - .push_slice(citrea) - .push_slice(evm_address.0); + .into_script() +} - let builder = kickoff_utxos.iter().fold(builder, |b, utxo| { - b.push_slice(utxo.txid.to_byte_array()) // TODO: Optimize here - .push_int(utxo.vout as i64) - }); +// pub fn create_move_commit_script( +// nofn_xonly_pk: &XOnlyPublicKey, +// evm_address: &EVMAddress, +// kickoff_utxos: &[OutPoint], +// ) -> ScriptBuf { +// let citrea: [u8; 6] = "citrea".as_bytes().try_into().unwrap(); - builder.push_opcode(OP_ENDIF).into_script() -} +// let builder = Builder::new() +// .push_x_only_key(nofn_xonly_pk) +// .push_opcode(OP_CHECKSIG) +// .push_opcode(OP_FALSE) +// .push_opcode(OP_IF) +// .push_slice(citrea) +// .push_slice(evm_address.0); + +// let builder = kickoff_utxos.iter().fold(builder, |b, utxo| { +// b.push_slice(utxo.txid.to_byte_array()) // TODO: Optimize here +// .push_int(utxo.vout as i64) +// }); + +// builder.push_opcode(OP_ENDIF).into_script() +// } // pub fn create_inscription_script_32_bytes( // public_key: &XOnlyPublicKey, diff --git a/core/src/transaction_builder.rs b/core/src/transaction_builder.rs index 3aa38c7c..a33f4ff0 100644 --- a/core/src/transaction_builder.rs +++ b/core/src/transaction_builder.rs @@ -2,6 +2,7 @@ use crate::{script_builder, utils, EVMAddress, UTXO}; use bitcoin::address::NetworkUnchecked; +use bitcoin::script::PushBytesBuf; use bitcoin::Network; use bitcoin::{ absolute, @@ -9,6 +10,7 @@ use bitcoin::{ Address, Amount, OutPoint, ScriptBuf, TxIn, TxOut, Witness, }; use clementine_circuits::constants::BRIDGE_AMOUNT_SATS; +use hex::ToHex; use secp256k1::PublicKey; use secp256k1::XOnlyPublicKey; @@ -33,6 +35,7 @@ pub struct TransactionBuilder { // pub const MOVE_COMMIT_TX_MIN_RELAY_FEE: u64 = 305; // pub const MOVE_REVEAL_TX_MIN_RELAY_FEE: u64 = 305; pub const MOVE_TX_MIN_RELAY_FEE: u64 = 305; +pub const SLASH_OR_TAKE_TX_MIN_RELAY_FEE: u64 = 305; pub const WITHDRAWAL_TX_MIN_RELAY_FEE: u64 = 305; impl TransactionBuilder { @@ -335,12 +338,22 @@ impl TransactionBuilder { /// Creates the kickoff_tx for the operator. It also returns the change utxo pub fn create_kickoff_tx( - funding_utxo: &UTXO, + funding_utxo: &UTXO, // Make sure this comes from the operator's address. nofn_xonly_pk: &XOnlyPublicKey, operator_xonly_pk: &XOnlyPublicKey, + network: bitcoin::Network, ) -> TxHandler { let tx_ins = TransactionBuilder::create_tx_ins(vec![funding_utxo.outpoint]); - + let musig2_and_operator_script = script_builder::create_musig2_and_operator_multisig_script( + nofn_xonly_pk, + operator_xonly_pk, + ); + let (musig2_and_operator_address, _) = TransactionBuilder::create_taproot_address( + &[musig2_and_operator_script], + None, + network, + ); + let operator_address = Address::p2tr(&utils::SECP, *operator_xonly_pk, None, network); let change_amount = funding_utxo.txout.value - Amount::from_sat(100_000) - script_builder::anyone_can_spend_txout().value; @@ -348,9 +361,9 @@ impl TransactionBuilder { let tx_outs = TransactionBuilder::create_tx_outs(vec![ ( Amount::from_sat(100_000), // TODO: Change this to a constant - address.script_pubkey(), + musig2_and_operator_address.script_pubkey(), ), - (change_amount, address.script_pubkey()), + (change_amount, operator_address.script_pubkey()), ( script_builder::anyone_can_spend_txout().value, script_builder::anyone_can_spend_txout().script_pubkey, @@ -369,33 +382,70 @@ impl TransactionBuilder { } pub fn create_slash_or_take_tx( + deposit_outpoint: OutPoint, kickoff_outpoint: OutPoint, kickoff_txout: TxOut, operator_address: &XOnlyPublicKey, + operator_idx: usize, nofn_xonly_pk: &XOnlyPublicKey, network: bitcoin::Network, ) -> TxHandler { + let musig2_address = Address::p2tr(&utils::SECP, *nofn_xonly_pk, None, network); + let anyone_can_spend_txout = script_builder::anyone_can_spend_txout(); + let move_txins = TransactionBuilder::create_tx_ins(vec![deposit_outpoint]); + let move_txout = TxOut { + value: Amount::from_sat(BRIDGE_AMOUNT_SATS) + - Amount::from_sat(MOVE_TX_MIN_RELAY_FEE) + - anyone_can_spend_txout.value, + script_pubkey: musig2_address.script_pubkey(), + }; + + let move_tx_simple = + TransactionBuilder::create_btc_tx(move_txins, vec![move_txout, anyone_can_spend_txout]); + let move_txid = move_tx_simple.compute_txid(); + let ins = TransactionBuilder::create_tx_ins(vec![kickoff_outpoint]); let relative_timelock_script = script_builder::generate_relative_timelock_script(operator_address, 200); // TODO: Change this 200 to a config constant - - let slash_or_take_address = TransactionBuilder::create_taproot_address( + let (slash_or_take_address, _) = TransactionBuilder::create_taproot_address( &[relative_timelock_script.clone()], Some(*nofn_xonly_pk), network, ); - + let mut op_return_script: Vec = hex::decode(move_txid.to_string()).unwrap(); + let op_return_idx: Vec = if operator_idx < 256 { + vec![operator_idx as u8] // Directly create a Vec for u8 + } else if operator_idx < 65536 { + (operator_idx as u16).to_be_bytes().to_vec() // Convert u16 array to Vec + } else { + (operator_idx as u32).to_be_bytes().to_vec() // Convert u32 array to Vec + }; + op_return_script.extend(op_return_idx); + let mut push_bytes = PushBytesBuf::new(); + push_bytes.extend_from_slice(&op_return_script); + let op_return_txout = script_builder::op_return_txout(push_bytes); let outs = vec![ TxOut { - value: Amount::from_sat(kickoff_txout.value.to_sat() - 330), - script_pubkey: slash_or_take_address.0.script_pubkey(), + value: Amount::from_sat( + kickoff_txout.value.to_sat() - 330 - SLASH_OR_TAKE_TX_MIN_RELAY_FEE, + ), + script_pubkey: slash_or_take_address.script_pubkey(), }, + op_return_txout, script_builder::anyone_can_spend_txout(), ]; let tx = TransactionBuilder::create_btc_tx(ins, outs); - let prevouts = vec![kickoff_txout]; - let scripts = vec![vec![relative_timelock_script]]; - let taproot_spend_infos = vec![slash_or_take_address.1]; + let prevouts = vec![kickoff_txout.clone()]; + let scripts = vec![vec![relative_timelock_script.clone()]]; + let (kickoff_txout_address, kickoff_txout_spend_info) = + TransactionBuilder::create_taproot_address( + &[relative_timelock_script], + Some(*nofn_xonly_pk), + network, + ); + // Sanity check + assert!(kickoff_txout_address.script_pubkey() == kickoff_txout.script_pubkey); + let taproot_spend_infos = vec![kickoff_txout_spend_info]; TxHandler { tx, prevouts, diff --git a/core/src/verifier.rs b/core/src/verifier.rs index c5e6154a..cb1d1743 100644 --- a/core/src/verifier.rs +++ b/core/src/verifier.rs @@ -30,6 +30,7 @@ where db: VerifierDB, config: BridgeConfig, nofn_xonly_pk: secp256k1::XOnlyPublicKey, + idx: usize, operator_xonly_pks: Vec, } @@ -54,6 +55,11 @@ where let agg_point: Point = key_agg_context.aggregated_pubkey_untweaked(); let nofn_xonly_pk = secp256k1::XOnlyPublicKey::from_slice(&agg_point.serialize_xonly())?; let operator_xonly_pks = config.operators_xonly_pks.clone(); + let idx = config + .verifiers_public_keys + .iter() + .position(|&x| x == pk) + .unwrap(); Ok(Verifier { rpc, @@ -61,6 +67,7 @@ where db, config, nofn_xonly_pk, + idx, operator_xonly_pks, }) } @@ -189,10 +196,10 @@ where .await? .ok_or(BridgeError::KickoffOutpointsNotFound)?; - let kickoff_outpoints = kickoff_utxos - .iter() - .map(|utxo| utxo.outpoint) - .collect::>(); + // let kickoff_outpoints = kickoff_utxos + // .iter() + // .map(|utxo| utxo.outpoint) + // .collect::>(); let (recovery_taproot_address, evm_address) = self .db @@ -242,7 +249,7 @@ where /// verify burn txs are signed by verifiers /// sign operator_takes_txs - async fn burn_txs_signed_rpc( + async fn burn_txs_signed( &self, deposit_outpoint: OutPoint, _burn_sigs: Vec, @@ -433,7 +440,7 @@ where deposit_utxo: OutPoint, burn_sigs: Vec, ) -> Result, BridgeError> { - self.burn_txs_signed_rpc(deposit_utxo, burn_sigs).await + self.burn_txs_signed(deposit_utxo, burn_sigs).await } async fn operator_take_txs_signed_rpc( diff --git a/core/tests/flow.rs b/core/tests/flow.rs index 8003811c..e49ef024 100644 --- a/core/tests/flow.rs +++ b/core/tests/flow.rs @@ -36,22 +36,36 @@ async fn test_withdrawal_request() { .await .unwrap(); let secp = bitcoin::secp256k1::Secp256k1::new(); - let (operator_internal_xonly_pk, _) = config.secret_key.public_key(&secp).x_only_public_key(); - let operator_address = Address::p2tr(&secp, operator_internal_xonly_pk, None, config.network); + let user_sk = SecretKey::from_slice(&OsRng.gen::<[u8; 32]>()).unwrap(); + let user = User::new(rpc, user_sk, config.clone()); + let withdrawal_address = Address::p2tr( + &secp, + user_sk.x_only_public_key(&secp).0, + None, + config.network, + ); + let (empty_utxo, withdrawal_tx_out, user_sig) = + user.generate_withdrawal_sig(withdrawal_address).unwrap(); + let withdrawal_provide_txid = operator_client + .new_withdrawal_sig_rpc(0, user_sig, empty_utxo, withdrawal_tx_out) + .await + .unwrap(); + println!("{:?}", withdrawal_provide_txid); +} - let operator_funding_outpoint = rpc - .send_to_address(&operator_address, 2 * BRIDGE_AMOUNT_SATS) +#[tokio::test] +async fn test_honest_operator_takes_refund() { + let mut config = create_test_config_with_thread_name!("test_config_flow.toml"); + let rpc = create_extended_rpc!(config); + + let (operator_client, _operator_handler) = create_operator_server(config.clone(), rpc.clone()) + .await .unwrap(); - let operator_funding_txout = rpc - .get_txout_from_outpoint(&operator_funding_outpoint) + create_verifier_server(config.clone(), rpc.clone()) + .await .unwrap(); - let operator_funding_utxo = UTXO { - outpoint: operator_funding_outpoint, - txout: operator_funding_txout, - }; - let _ = operator_client - .set_operator_funding_utxo_rpc(operator_funding_utxo) - .await; + + let secp = bitcoin::secp256k1::Secp256k1::new(); let user_sk = SecretKey::from_slice(&OsRng.gen::<[u8; 32]>()).unwrap(); let user = User::new(rpc, user_sk, config.clone()); let withdrawal_address = Address::p2tr( @@ -68,3 +82,6 @@ async fn test_withdrawal_request() { .unwrap(); println!("{:?}", withdrawal_provide_txid); } + +#[tokio::test] +async fn test_malicious_operator_gets_slashed() {} From b5971c6a5f0557f15133d339a86c9fd790eec963 Mon Sep 17 00:00:00 2001 From: ozankaymak Date: Fri, 23 Aug 2024 16:21:07 +0300 Subject: [PATCH 5/8] Implement changes --- core/src/actor.rs | 16 ++-- core/src/database/common.rs | 122 +++++++++++++++---------------- core/src/operator.rs | 5 +- core/src/script_builder.rs | 4 +- core/src/traits/rpc.rs | 4 +- core/src/transaction_builder.rs | 36 +++------ core/src/verifier.rs | 126 ++++++++++++++++++++++++-------- scripts/schema.sql | 10 +-- 8 files changed, 189 insertions(+), 134 deletions(-) diff --git a/core/src/actor.rs b/core/src/actor.rs index 02c9e33a..4c01f9f9 100644 --- a/core/src/actor.rs +++ b/core/src/actor.rs @@ -160,7 +160,7 @@ impl Actor { pub fn sign_taproot_script_spend_tx_new_tweaked( &self, - tx: &mut TxHandler, + tx_handler: &mut TxHandler, txin_index: usize, script_index: usize, ) -> Result { @@ -168,12 +168,12 @@ impl Actor { // else create a new one and save it to the TxHandler let mut sighash_cache: SighashCache<&mut bitcoin::Transaction> = - SighashCache::new(&mut tx.tx); + SighashCache::new(&mut tx_handler.tx); let sig_hash = sighash_cache.taproot_script_spend_signature_hash( txin_index, - &bitcoin::sighash::Prevouts::All(&tx.prevouts), + &bitcoin::sighash::Prevouts::All(&tx_handler.prevouts), TapLeafHash::from_script( - &tx.scripts[txin_index][script_index], + &tx_handler.scripts[txin_index][script_index], LeafVersion::TapScript, ), bitcoin::sighash::TapSighashType::Default, @@ -182,17 +182,17 @@ impl Actor { } pub fn convert_tx_to_sighash_script_spend( - tx: &mut TxHandler, + tx_handler: &mut TxHandler, txin_index: usize, script_index: usize, ) -> Result { let mut sighash_cache: SighashCache<&mut bitcoin::Transaction> = - SighashCache::new(&mut tx.tx); + SighashCache::new(&mut tx_handler.tx); let sig_hash = sighash_cache.taproot_script_spend_signature_hash( txin_index, - &bitcoin::sighash::Prevouts::All(&tx.prevouts), + &bitcoin::sighash::Prevouts::All(&tx_handler.prevouts), TapLeafHash::from_script( - &tx.scripts[txin_index][script_index], + &tx_handler.scripts[txin_index][script_index], LeafVersion::TapScript, ), bitcoin::sighash::TapSighashType::Default, diff --git a/core/src/database/common.rs b/core/src/database/common.rs index c2ac707e..a872a31a 100644 --- a/core/src/database/common.rs +++ b/core/src/database/common.rs @@ -443,38 +443,38 @@ impl Database { } } - pub async fn save_kickoff_root( - &self, - deposit_outpoint: OutPoint, - kickoff_root: [u8; 32], - ) -> Result<(), BridgeError> { - sqlx::query( - "INSERT INTO kickoff_roots (deposit_outpoint, kickoff_merkle_root) VALUES ($1, $2);", - ) - .bind(OutPointDB(deposit_outpoint)) - .bind(hex::encode(kickoff_root)) - .execute(&self.connection) - .await?; - - Ok(()) - } - - pub async fn get_kickoff_root( - &self, - deposit_outpoint: OutPoint, - ) -> Result, BridgeError> { - let qr: Option = sqlx::query_scalar( - "SELECT kickoff_merkle_root FROM kickoff_roots WHERE deposit_outpoint = $1;", - ) - .bind(OutPointDB(deposit_outpoint)) - .fetch_optional(&self.connection) - .await?; - - match qr { - Some(root) => Ok(Some(hex::decode(root)?.try_into()?)), - None => Ok(None), - } - } + // pub async fn save_kickoff_root( + // &self, + // deposit_outpoint: OutPoint, + // kickoff_root: [u8; 32], + // ) -> Result<(), BridgeError> { + // sqlx::query( + // "INSERT INTO kickoff_roots (deposit_outpoint, kickoff_merkle_root) VALUES ($1, $2);", + // ) + // .bind(OutPointDB(deposit_outpoint)) + // .bind(hex::encode(kickoff_root)) + // .execute(&self.connection) + // .await?; + + // Ok(()) + // } + + // pub async fn get_kickoff_root( + // &self, + // deposit_outpoint: OutPoint, + // ) -> Result, BridgeError> { + // let qr: Option = sqlx::query_scalar( + // "SELECT kickoff_merkle_root FROM kickoff_roots WHERE deposit_outpoint = $1;", + // ) + // .bind(OutPointDB(deposit_outpoint)) + // .fetch_optional(&self.connection) + // .await?; + + // match qr { + // Some(root) => Ok(Some(hex::decode(root)?.try_into()?)), + // None => Ok(None), + // } + // } } #[cfg(test)] @@ -902,35 +902,35 @@ mod tests { assert!(res.is_none()); } - #[tokio::test] - async fn test_kickoff_root_1() { - let config = create_test_config_with_thread_name!("test_config.toml"); - let db = Database::new(config).await.unwrap(); - - let outpoint = OutPoint { - txid: Txid::from_byte_array([1u8; 32]), - vout: 1, - }; - let root = [1u8; 32]; - db.save_kickoff_root(outpoint, root).await.unwrap(); - let db_root = db.get_kickoff_root(outpoint).await.unwrap().unwrap(); - - // Sanity check - assert_eq!(db_root, root); - } - - #[tokio::test] - async fn test_kickoff_root_2() { - let config = create_test_config_with_thread_name!("test_config.toml"); - let db = Database::new(config).await.unwrap(); - - let outpoint = OutPoint { - txid: Txid::from_byte_array([1u8; 32]), - vout: 1, - }; - let res = db.get_kickoff_root(outpoint).await.unwrap(); - assert!(res.is_none()); - } + // #[tokio::test] + // async fn test_kickoff_root_1() { + // let config = create_test_config_with_thread_name!("test_config.toml"); + // let db = Database::new(config).await.unwrap(); + + // let outpoint = OutPoint { + // txid: Txid::from_byte_array([1u8; 32]), + // vout: 1, + // }; + // let root = [1u8; 32]; + // db.save_kickoff_root(outpoint, root).await.unwrap(); + // let db_root = db.get_kickoff_root(outpoint).await.unwrap().unwrap(); + + // // Sanity check + // assert_eq!(db_root, root); + // } + + // #[tokio::test] + // async fn test_kickoff_root_2() { + // let config = create_test_config_with_thread_name!("test_config.toml"); + // let db = Database::new(config).await.unwrap(); + + // let outpoint = OutPoint { + // txid: Txid::from_byte_array([1u8; 32]), + // vout: 1, + // }; + // let res = db.get_kickoff_root(outpoint).await.unwrap(); + // assert!(res.is_none()); + // } } #[cfg(poc)] diff --git a/core/src/operator.rs b/core/src/operator.rs index ec7bd107..f9106d12 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -57,7 +57,7 @@ where let idx = config .operators_xonly_pks .iter() - .position(|xonly_pk| xonly_pk == &nofn_xonly_pk) + .position(|xonly_pk| xonly_pk == &signer.xonly_public_key) .unwrap(); Ok(Self { @@ -141,10 +141,11 @@ where )); } - let kickoff_tx_handler = TransactionBuilder::create_kickoff_tx( + let kickoff_tx_handler = TransactionBuilder::create_kickoff_utxo_tx( &funding_utxo, &self.nofn_xonly_pk, &self.signer.xonly_public_key, + self.config.network, ); let change_utxo = UTXO { diff --git a/core/src/script_builder.rs b/core/src/script_builder.rs index 4f512879..5783e0c7 100644 --- a/core/src/script_builder.rs +++ b/core/src/script_builder.rs @@ -113,14 +113,14 @@ pub fn create_musig2_and_operator_multisig_script( /// condition is that (`# in the script`) < (`# in the sequence of the tx`) /// < (`# of blocks mined after UTXO`) appears on the chain. pub fn generate_relative_timelock_script( - actor_taproot_address: &XOnlyPublicKey, + actor_taproot_xonly_pk: &XOnlyPublicKey, // This is the tweaked XonlyPublicKey, which appears in the script_pubkey of the address block_count: u32, ) -> ScriptBuf { Builder::new() .push_int(block_count as i64) .push_opcode(OP_CSV) .push_opcode(OP_DROP) - .push_x_only_key(actor_taproot_address) + .push_x_only_key(actor_taproot_xonly_pk) .push_opcode(OP_CHECKSIG) .into_script() } diff --git a/core/src/traits/rpc.rs b/core/src/traits/rpc.rs index 5a55cf47..b8d07bbe 100644 --- a/core/src/traits/rpc.rs +++ b/core/src/traits/rpc.rs @@ -29,7 +29,7 @@ pub trait VerifierRpc { deposit_utxo: OutPoint, kickoff_utxos: Vec, operators_kickoff_sigs: Vec, - agg_nonces: Vec, + agg_nonces: (Vec, Vec), ) -> Result<(Vec, Vec), BridgeError>; #[method(name = "burn_txs_signed")] @@ -50,7 +50,7 @@ pub trait VerifierRpc { &self, deposit_utxo: OutPoint, operator_take_sigs: Vec, - ) -> Result<(MuSigPartialSignature, MuSigPartialSignature), BridgeError>; + ) -> Result; } #[rpc(client, server, namespace = "operator")] diff --git a/core/src/transaction_builder.rs b/core/src/transaction_builder.rs index a33f4ff0..2246836f 100644 --- a/core/src/transaction_builder.rs +++ b/core/src/transaction_builder.rs @@ -337,7 +337,7 @@ impl TransactionBuilder { } /// Creates the kickoff_tx for the operator. It also returns the change utxo - pub fn create_kickoff_tx( + pub fn create_kickoff_utxo_tx( funding_utxo: &UTXO, // Make sure this comes from the operator's address. nofn_xonly_pk: &XOnlyPublicKey, operator_xonly_pk: &XOnlyPublicKey, @@ -383,13 +383,13 @@ impl TransactionBuilder { pub fn create_slash_or_take_tx( deposit_outpoint: OutPoint, - kickoff_outpoint: OutPoint, - kickoff_txout: TxOut, - operator_address: &XOnlyPublicKey, + kickoff_utxo: UTXO, + operator_xonly_pk: &XOnlyPublicKey, operator_idx: usize, nofn_xonly_pk: &XOnlyPublicKey, network: bitcoin::Network, ) -> TxHandler { + // First recreate the move_tx and move_txid. let musig2_address = Address::p2tr(&utils::SECP, *nofn_xonly_pk, None, network); let anyone_can_spend_txout = script_builder::anyone_can_spend_txout(); let move_txins = TransactionBuilder::create_tx_ins(vec![deposit_outpoint]); @@ -404,9 +404,10 @@ impl TransactionBuilder { TransactionBuilder::create_btc_tx(move_txins, vec![move_txout, anyone_can_spend_txout]); let move_txid = move_tx_simple.compute_txid(); - let ins = TransactionBuilder::create_tx_ins(vec![kickoff_outpoint]); + // We assume that the address of the kickoff_utxo will be the same as the operator's taproot address. + let ins = TransactionBuilder::create_tx_ins(vec![kickoff_utxo.outpoint]); let relative_timelock_script = - script_builder::generate_relative_timelock_script(operator_address, 200); // TODO: Change this 200 to a config constant + script_builder::generate_relative_timelock_script(operator_xonly_pk, 200); // TODO: Change this 200 to a config constant let (slash_or_take_address, _) = TransactionBuilder::create_taproot_address( &[relative_timelock_script.clone()], Some(*nofn_xonly_pk), @@ -427,7 +428,7 @@ impl TransactionBuilder { let outs = vec![ TxOut { value: Amount::from_sat( - kickoff_txout.value.to_sat() - 330 - SLASH_OR_TAKE_TX_MIN_RELAY_FEE, + kickoff_utxo.txout.value.to_sat() - 330 - SLASH_OR_TAKE_TX_MIN_RELAY_FEE, ), script_pubkey: slash_or_take_address.script_pubkey(), }, @@ -435,22 +436,13 @@ impl TransactionBuilder { script_builder::anyone_can_spend_txout(), ]; let tx = TransactionBuilder::create_btc_tx(ins, outs); - let prevouts = vec![kickoff_txout.clone()]; + let prevouts = vec![kickoff_utxo.txout.clone()]; let scripts = vec![vec![relative_timelock_script.clone()]]; - let (kickoff_txout_address, kickoff_txout_spend_info) = - TransactionBuilder::create_taproot_address( - &[relative_timelock_script], - Some(*nofn_xonly_pk), - network, - ); - // Sanity check - assert!(kickoff_txout_address.script_pubkey() == kickoff_txout.script_pubkey); - let taproot_spend_infos = vec![kickoff_txout_spend_info]; TxHandler { tx, prevouts, scripts, - taproot_spend_infos, + taproot_spend_infos: vec![], } } @@ -489,9 +481,7 @@ impl TransactionBuilder { TxOut { value: Amount::from_sat(slash_or_take_txout.value.to_sat()) + Amount::from_sat(BRIDGE_AMOUNT_SATS) - - Amount::from_sat(MOVE_COMMIT_TX_MIN_RELAY_FEE) - - Amount::from_sat(MOVE_REVEAL_TX_MIN_RELAY_FEE) - - script_builder::anyone_can_spend_txout().value + - Amount::from_sat(MOVE_TX_MIN_RELAY_FEE) - script_builder::anyone_can_spend_txout().value - script_builder::anyone_can_spend_txout().value, script_pubkey: operator_address.script_pubkey(), @@ -503,9 +493,7 @@ impl TransactionBuilder { TxOut { script_pubkey: musig2_address.script_pubkey(), value: Amount::from_sat(BRIDGE_AMOUNT_SATS) - - Amount::from_sat(MOVE_COMMIT_TX_MIN_RELAY_FEE) - - Amount::from_sat(MOVE_REVEAL_TX_MIN_RELAY_FEE) - - script_builder::anyone_can_spend_txout().value + - Amount::from_sat(MOVE_TX_MIN_RELAY_FEE) - script_builder::anyone_can_spend_txout().value, }, slash_or_take_txout, diff --git a/core/src/verifier.rs b/core/src/verifier.rs index cb1d1743..298d5b56 100644 --- a/core/src/verifier.rs +++ b/core/src/verifier.rs @@ -7,7 +7,7 @@ use crate::merkle::MerkleTree; use crate::musig2::{self, MuSigAggNonce, MuSigPartialSignature, MuSigPubNonce}; use crate::traits::rpc::VerifierRpcServer; use crate::transaction_builder::{TransactionBuilder, TxHandler}; -use crate::{utils, EVMAddress, UTXO}; +use crate::{script_builder, utils, EVMAddress, UTXO}; use ::musig2::secp::Point; use bitcoin::address::NetworkUnchecked; use bitcoin::hashes::Hash; @@ -95,7 +95,7 @@ where self.config.network, )?; - let num_required_nonces = self.operator_xonly_pks.len() + 2; + let num_required_nonces = 3 * self.operator_xonly_pks.len() + 1; // Check if we already have pub_nonces for this deposit_utxo. let pub_nonces_from_db = self.db.get_pub_nonces(deposit_outpoint).await?; @@ -128,20 +128,25 @@ where /// - Verify operators signatures about kickoffs /// - Check the kickoff_utxos /// - Save agg_nonces to a db for future use - /// - for every kickoff_utxo, calculate kickoff2_tx - /// - for every kickoff2_tx, partial sign burn_tx (ommitted for now) - /// - return butn_txs partial signatures (ommitted for now) + /// - for every kickoff_utxo, calculate slash_or_take_tx + /// - for every slash_or_take_tx, partial sign slash_or_take_tx + /// - for every slash_or_take_tx, partial sign burn_tx (omitted for now) + /// - return burn_txs partial signatures (omitted for now) TODO: For this bit, + /// do not forget to add tweak when signing since this address has n_of_n as internal_key + /// and operator_timelock as script. async fn operator_kickoffs_generated( &self, deposit_outpoint: OutPoint, kickoff_utxos: Vec, operators_kickoff_sigs: Vec, // These are not transaction signatures, rather, they are to verify the operator's identity. - agg_nonces: Vec, - ) -> Result, BridgeError> { + agg_nonces: (Vec, Vec), // First vector is for the slash_or_take_txs, the second vector is for the burn_txs. + ) -> Result<(Vec, Vec), BridgeError> { if operators_kickoff_sigs.len() != kickoff_utxos.len() { - return Err(BridgeError::InvalidKickoffUtxo); + return Err(BridgeError::InvalidKickoffUtxo); // TODO: Better error } + let mut slash_or_take_sighashes: Vec<[u8; 32]> = Vec::new(); + for (i, kickoff_utxo) in kickoff_utxos.iter().enumerate() { let value = kickoff_utxo.txout.value; if value.to_sat() < 100_000 { @@ -155,35 +160,91 @@ where kickoff_utxo.outpoint.vout.to_be_bytes() ); + // Check if they are really the operators that sent these kickoff_utxos utils::SECP.verify_schnorr( &operators_kickoff_sigs[i], &secp256k1::Message::from_digest(kickoff_sig_hash), &self.config.operators_xonly_pks[i], )?; + + // Check if for each operator the address of the kickoff_utxo is correct TODO: Maybe handle the possible errors better + let musig2_and_operator_script = + script_builder::create_musig2_and_operator_multisig_script( + &self.nofn_xonly_pk, + &self.config.operators_xonly_pks[i], + ); + let (musig2_and_operator_address, _) = TransactionBuilder::create_taproot_address( + &vec![musig2_and_operator_script], + None, + self.config.network, + ); + assert!( + kickoff_utxo.txout.script_pubkey == musig2_and_operator_address.script_pubkey() + ); + + let mut slash_or_take_tx_handler = TransactionBuilder::create_slash_or_take_tx( + deposit_outpoint, + kickoff_utxo.clone(), + &self.config.operators_xonly_pks[i], + i, + &self.nofn_xonly_pk, + self.config.network, + ); + let slash_or_take_tx_sighash = + Actor::convert_tx_to_sighash_script_spend(&mut slash_or_take_tx_handler, 0, 0)?; + slash_or_take_sighashes.push(slash_or_take_tx_sighash.to_byte_array()); + // let spend_kickoff_utxo_tx_handler = TransactionBuilder::create_slash_or_take_tx(deposit_outpoint, kickoff_outpoint, kickoff_txout, operator_address, operator_idx, nofn_xonly_pk, network) } - let root: bitcoin::hashes::sha256::Hash = bitcoin::merkle_tree::calculate_root( - kickoff_utxos - .iter() - .map(|utxo| Hash::from_byte_array(sha256_hash!(utxo.to_vec().as_slice()))), - ) - .unwrap(); - let root_bytes: [u8; 32] = *root.as_byte_array(); + let nonces = self + .db + .save_sighashes_and_get_nonces( + deposit_outpoint, + self.config.num_operators + 1, + &slash_or_take_sighashes, + ) + .await? + .ok_or(BridgeError::NoncesNotFound)?; + let slash_or_take_partial_sigs = slash_or_take_sighashes + .iter() + .zip(nonces.iter()) + .map(|(sighash, (sec_nonce, agg_nonce))| { + musig2::partial_sign( + self.config.verifiers_public_keys.clone(), + None, + *sec_nonce, + agg_nonce.clone(), + &self.signer.keypair, + *sighash, + ) + }) + .collect::>(); + // let root: bitcoin::hashes::sha256::Hash = bitcoin::merkle_tree::calculate_root( + // kickoff_utxos + // .iter() + // .map(|utxo| Hash::from_byte_array(sha256_hash!(utxo.to_vec().as_slice()))), + // ) + // .unwrap(); + // let root_bytes: [u8; 32] = *root.as_byte_array(); self.db - .save_agg_nonces(deposit_outpoint, &agg_nonces) + .save_agg_nonces(deposit_outpoint, &agg_nonces.0) .await?; self.db - .save_kickoff_utxos(deposit_outpoint, &kickoff_utxos) + .save_agg_nonces(deposit_outpoint, &agg_nonces.1) .await?; self.db - .save_kickoff_root(deposit_outpoint, root_bytes) + .save_kickoff_utxos(deposit_outpoint, &kickoff_utxos) .await?; + // self.db + // .save_kickoff_root(deposit_outpoint, root_bytes) + // .await?; + // TODO: Sign burn txs - Ok(vec![]) + Ok((slash_or_take_partial_sigs, vec![])) } async fn create_deposit_details( @@ -253,6 +314,7 @@ where &self, deposit_outpoint: OutPoint, _burn_sigs: Vec, + _slash_or_take_sigs: Vec, ) -> Result, BridgeError> { // TODO: Verify burn txs are signed by verifiers let (kickoff_utxos, _, bridge_fund_outpoint) = @@ -268,9 +330,10 @@ where self.config.network, ); let slash_or_take_tx = TransactionBuilder::create_slash_or_take_tx( - kickoff_utxo.outpoint, - kickoff_utxo.txout.clone(), + deposit_outpoint, + kickoff_utxo.clone(), &self.operator_xonly_pks[index], + index, &self.nofn_xonly_pk, self.config.network, ); @@ -294,7 +357,7 @@ where let nonces = self .db - .save_sighashes_and_get_nonces(deposit_outpoint, 2, &operator_takes_sighashes) + .save_sighashes_and_get_nonces(deposit_outpoint, 1, &operator_takes_sighashes) .await? .ok_or(BridgeError::NoncesNotFound)?; @@ -318,7 +381,7 @@ where /// verify the operator_take_sigs /// sign move_commit_tx and move_reveal_tx - async fn operator_take_txs_signed_rpc( + async fn operator_take_txs_signed( &self, deposit_outpoint: OutPoint, operator_take_sigs: Vec, @@ -336,9 +399,10 @@ where self.config.network, ); let slash_or_take_tx = TransactionBuilder::create_slash_or_take_tx( - kickoff_utxo.outpoint, - kickoff_utxo.txout.clone(), + deposit_outpoint, + kickoff_utxo.clone(), &self.operator_xonly_pks[index], + index, &self.nofn_xonly_pk, self.config.network, ); @@ -424,8 +488,8 @@ where deposit_utxo: OutPoint, kickoff_utxos: Vec, operators_kickoff_sigs: Vec, - agg_nonces: Vec, - ) -> Result, BridgeError> { + agg_nonces: (Vec, Vec), + ) -> Result<(Vec, Vec), BridgeError> { self.operator_kickoffs_generated( deposit_utxo, kickoff_utxos, @@ -439,16 +503,18 @@ where &self, deposit_utxo: OutPoint, burn_sigs: Vec, + slash_or_take_sigs: Vec, ) -> Result, BridgeError> { - self.burn_txs_signed(deposit_utxo, burn_sigs).await + self.burn_txs_signed(deposit_utxo, burn_sigs, slash_or_take_sigs) + .await } async fn operator_take_txs_signed_rpc( &self, deposit_utxo: OutPoint, operator_take_sigs: Vec, - ) -> Result<(MuSigPartialSignature, MuSigPartialSignature), BridgeError> { - self.operator_take_txs_signed_rpc(deposit_utxo, operator_take_sigs) + ) -> Result { + self.operator_take_txs_signed(deposit_utxo, operator_take_sigs) .await } } diff --git a/scripts/schema.sql b/scripts/schema.sql index 2c070609..f5ada97a 100644 --- a/scripts/schema.sql +++ b/scripts/schema.sql @@ -91,10 +91,10 @@ create table funding_utxos ( ); -- Verifier table for kickoff merkle roots for deposits -create table kickoff_roots ( - deposit_outpoint text primary key not null check (deposit_outpoint ~ '^[a-fA-F0-9]{64}:(0|[1-9][0-9]{0,9})$'), - kickoff_merkle_root text not null check (kickoff_merkle_root ~ '^[a-fA-F0-9]{64}'), - created_at timestamp not null default now() -); +-- create table kickoff_roots ( +-- deposit_outpoint text primary key not null check (deposit_outpoint ~ '^[a-fA-F0-9]{64}:(0|[1-9][0-9]{0,9})$'), +-- kickoff_merkle_root text not null check (kickoff_merkle_root ~ '^[a-fA-F0-9]{64}'), +-- created_at timestamp not null default now() +-- ); COMMIT; From 37eb26d99f2fa2b9cd4854002b7d31ab30ae4cbd Mon Sep 17 00:00:00 2001 From: ozankaymak Date: Fri, 23 Aug 2024 17:47:05 +0300 Subject: [PATCH 6/8] Apply review changes --- core/src/traits/rpc.rs | 2 +- core/src/transaction_builder.rs | 52 +++++++++++++++++++---------- core/src/verifier.rs | 59 +++++++++++++++++---------------- 3 files changed, 67 insertions(+), 46 deletions(-) diff --git a/core/src/traits/rpc.rs b/core/src/traits/rpc.rs index b8d07bbe..4058bfb0 100644 --- a/core/src/traits/rpc.rs +++ b/core/src/traits/rpc.rs @@ -29,7 +29,7 @@ pub trait VerifierRpc { deposit_utxo: OutPoint, kickoff_utxos: Vec, operators_kickoff_sigs: Vec, - agg_nonces: (Vec, Vec), + agg_nonces: Vec, ) -> Result<(Vec, Vec), BridgeError>; #[method(name = "burn_txs_signed")] diff --git a/core/src/transaction_builder.rs b/core/src/transaction_builder.rs index 2246836f..8a66bb9b 100644 --- a/core/src/transaction_builder.rs +++ b/core/src/transaction_builder.rs @@ -170,6 +170,18 @@ impl TransactionBuilder { TransactionBuilder::create_taproot_address(&[], Some(nofn_xonly_pk), network) } + pub fn create_kickoff_address( + nofn_xonly_pk: &XOnlyPublicKey, + operator_xonly_pk: &XOnlyPublicKey, + network: bitcoin::Network, + ) -> CreateAddressOutputs { + let musig2_and_operator_script = script_builder::create_musig2_and_operator_multisig_script( + nofn_xonly_pk, + operator_xonly_pk, + ); + TransactionBuilder::create_taproot_address(&[musig2_and_operator_script], None, network) + } + // TX BUILDERS // pub fn create_move_commit_tx( @@ -389,23 +401,29 @@ impl TransactionBuilder { nofn_xonly_pk: &XOnlyPublicKey, network: bitcoin::Network, ) -> TxHandler { - // First recreate the move_tx and move_txid. - let musig2_address = Address::p2tr(&utils::SECP, *nofn_xonly_pk, None, network); - let anyone_can_spend_txout = script_builder::anyone_can_spend_txout(); - let move_txins = TransactionBuilder::create_tx_ins(vec![deposit_outpoint]); - let move_txout = TxOut { - value: Amount::from_sat(BRIDGE_AMOUNT_SATS) - - Amount::from_sat(MOVE_TX_MIN_RELAY_FEE) - - anyone_can_spend_txout.value, - script_pubkey: musig2_address.script_pubkey(), - }; + // First recreate the move_tx and move_txid. We can give dummy values for some of the parameters since we are only interested in txid. + let move_tx_handler = TransactionBuilder::create_move_tx( + deposit_outpoint, + &EVMAddress([0u8; 20]), + &Address::p2tr( + &utils::SECP, + *utils::UNSPENDABLE_XONLY_PUBKEY, + None, + network, + ) + .as_unchecked(), + 200, + nofn_xonly_pk, + network, + ); + let move_txid = move_tx_handler.tx.compute_txid(); - let move_tx_simple = - TransactionBuilder::create_btc_tx(move_txins, vec![move_txout, anyone_can_spend_txout]); - let move_txid = move_tx_simple.compute_txid(); + let (kickoff_utxo_address, kickoff_utxo_spend_info) = + Self::create_kickoff_address(nofn_xonly_pk, operator_xonly_pk, network); - // We assume that the address of the kickoff_utxo will be the same as the operator's taproot address. - let ins = TransactionBuilder::create_tx_ins(vec![kickoff_utxo.outpoint]); + // Sanity check + assert!(kickoff_utxo_address.script_pubkey() == kickoff_utxo.txout.script_pubkey); + let ins = Self::create_tx_ins(vec![kickoff_utxo.outpoint]); let relative_timelock_script = script_builder::generate_relative_timelock_script(operator_xonly_pk, 200); // TODO: Change this 200 to a config constant let (slash_or_take_address, _) = TransactionBuilder::create_taproot_address( @@ -423,7 +441,7 @@ impl TransactionBuilder { }; op_return_script.extend(op_return_idx); let mut push_bytes = PushBytesBuf::new(); - push_bytes.extend_from_slice(&op_return_script); + push_bytes.extend_from_slice(&op_return_script).unwrap(); let op_return_txout = script_builder::op_return_txout(push_bytes); let outs = vec![ TxOut { @@ -442,7 +460,7 @@ impl TransactionBuilder { tx, prevouts, scripts, - taproot_spend_infos: vec![], + taproot_spend_infos: vec![kickoff_utxo_spend_info], } } diff --git a/core/src/verifier.rs b/core/src/verifier.rs index 298d5b56..4b3d6eb5 100644 --- a/core/src/verifier.rs +++ b/core/src/verifier.rs @@ -95,7 +95,8 @@ where self.config.network, )?; - let num_required_nonces = 3 * self.operator_xonly_pks.len() + 1; + // For now we multiply by 2 since we do not give signatures for burn_txs. // TODO: Change this in future. + let num_required_nonces = 2 * self.operator_xonly_pks.len() + 1; // Check if we already have pub_nonces for this deposit_utxo. let pub_nonces_from_db = self.db.get_pub_nonces(deposit_outpoint).await?; @@ -139,12 +140,16 @@ where deposit_outpoint: OutPoint, kickoff_utxos: Vec, operators_kickoff_sigs: Vec, // These are not transaction signatures, rather, they are to verify the operator's identity. - agg_nonces: (Vec, Vec), // First vector is for the slash_or_take_txs, the second vector is for the burn_txs. + agg_nonces: Vec, // This includes all the agg_nonces for the bridge operations. ) -> Result<(Vec, Vec), BridgeError> { if operators_kickoff_sigs.len() != kickoff_utxos.len() { return Err(BridgeError::InvalidKickoffUtxo); // TODO: Better error } + self.db + .save_agg_nonces(deposit_outpoint, &agg_nonces) + .await?; + let mut slash_or_take_sighashes: Vec<[u8; 32]> = Vec::new(); for (i, kickoff_utxo) in kickoff_utxos.iter().enumerate() { @@ -168,14 +173,9 @@ where )?; // Check if for each operator the address of the kickoff_utxo is correct TODO: Maybe handle the possible errors better - let musig2_and_operator_script = - script_builder::create_musig2_and_operator_multisig_script( - &self.nofn_xonly_pk, - &self.config.operators_xonly_pks[i], - ); - let (musig2_and_operator_address, _) = TransactionBuilder::create_taproot_address( - &vec![musig2_and_operator_script], - None, + let (musig2_and_operator_address, _) = TransactionBuilder::create_kickoff_address( + &self.nofn_xonly_pk, + &self.operator_xonly_pks[i], self.config.network, ); assert!( @@ -227,14 +227,6 @@ where // .unwrap(); // let root_bytes: [u8; 32] = *root.as_byte_array(); - self.db - .save_agg_nonces(deposit_outpoint, &agg_nonces.0) - .await?; - - self.db - .save_agg_nonces(deposit_outpoint, &agg_nonces.1) - .await?; - self.db .save_kickoff_utxos(deposit_outpoint, &kickoff_utxos) .await?; @@ -310,11 +302,12 @@ where /// verify burn txs are signed by verifiers /// sign operator_takes_txs + /// TODO: Change the name of this function. async fn burn_txs_signed( &self, deposit_outpoint: OutPoint, _burn_sigs: Vec, - _slash_or_take_sigs: Vec, + slash_or_take_sigs: Vec, ) -> Result, BridgeError> { // TODO: Verify burn txs are signed by verifiers let (kickoff_utxos, _, bridge_fund_outpoint) = @@ -324,12 +317,7 @@ where .iter() .enumerate() .map(|(index, kickoff_utxo)| { - let (operator_address, _) = TransactionBuilder::create_taproot_address( - &[], - Some(self.operator_xonly_pks[index]), - self.config.network, - ); - let slash_or_take_tx = TransactionBuilder::create_slash_or_take_tx( + let mut slash_or_take_tx_handler = TransactionBuilder::create_slash_or_take_tx( deposit_outpoint, kickoff_utxo.clone(), &self.operator_xonly_pks[index], @@ -337,14 +325,29 @@ where &self.nofn_xonly_pk, self.config.network, ); + let slash_or_take_sighash = + Actor::convert_tx_to_sighash_script_spend(&mut slash_or_take_tx_handler, 0, 0) + .unwrap(); + + utils::SECP.verify_schnorr( + &slash_or_take_sigs[index], + &secp256k1::Message::from_digest(slash_or_take_sighash.to_byte_array()), + &self.nofn_xonly_pk, + ); + + let (operator_address, _) = TransactionBuilder::create_taproot_address( + &[], + Some(self.operator_xonly_pks[index]), + self.config.network, + ); let mut operator_takes_tx = TransactionBuilder::create_operator_takes_tx( bridge_fund_outpoint, OutPoint { - txid: slash_or_take_tx.tx.compute_txid(), + txid: slash_or_take_tx_handler.tx.compute_txid(), vout: 0, }, - slash_or_take_tx.tx.output[0].clone(), + slash_or_take_tx_handler.tx.output[0].clone(), &operator_address, &self.nofn_xonly_pk, self.config.network, @@ -488,7 +491,7 @@ where deposit_utxo: OutPoint, kickoff_utxos: Vec, operators_kickoff_sigs: Vec, - agg_nonces: (Vec, Vec), + agg_nonces: Vec, ) -> Result<(Vec, Vec), BridgeError> { self.operator_kickoffs_generated( deposit_utxo, From faf0326b3099d98ac62e8dd19707a23108f22dcd Mon Sep 17 00:00:00 2001 From: ozankaymak Date: Mon, 26 Aug 2024 11:17:38 +0300 Subject: [PATCH 7/8] Refactor the binaries --- core/Cargo.toml | 4 +- core/src/bin/operator_and_verifiers.rs | 33 ------ core/src/bin/operators_and_verifiers.rs | 41 +++++++ core/src/database/common.rs | 5 +- core/src/servers.rs | 147 +++++++++++++----------- core/tests/flow.rs | 24 ++-- 6 files changed, 132 insertions(+), 122 deletions(-) delete mode 100644 core/src/bin/operator_and_verifiers.rs create mode 100644 core/src/bin/operators_and_verifiers.rs diff --git a/core/Cargo.toml b/core/Cargo.toml index a5ed2304..c44b76c5 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -48,8 +48,8 @@ name = "user_deposit" path = "src/bin/user_deposit.rs" [[bin]] -name = "operator_and_verifiers" -path = "src/bin/operator_and_verifiers.rs" +name = "operators_and_verifiers" +path = "src/bin/operators_and_verifiers.rs" [[bin]] name = "config_generator" diff --git a/core/src/bin/operator_and_verifiers.rs b/core/src/bin/operator_and_verifiers.rs deleted file mode 100644 index 105b1f00..00000000 --- a/core/src/bin/operator_and_verifiers.rs +++ /dev/null @@ -1,33 +0,0 @@ -use clementine_core::{cli, extended_rpc::ExtendedRpc}; - -/// ```bash -/// curl -X POST http://127.0.0.1:3434 -H "Content-Type: application/json" -d '{ -/// "jsonrpc": "2.0", -/// "method": "operator_new_deposit", -/// "params": { -/// "start_utxo": "2964713fecf26d6eec7df4420bed1e09de1bdab2cacd24a1c8c0afd70c8a5371:3", -/// "recovery_taproot_address": "781990d7e2118cc361a93a6fcc54ce611d6df38168d6b1edfb556535f2200c4b", -/// "evm_address": "0101010101010101010101010101010101010101" -/// }, -/// "id": 1 -/// }' -/// ``` -#[tokio::main] -async fn main() { - // let config = cli::get_configuration(); - // let rpc = ExtendedRpc::::new( - // config.bitcoin_rpc_url.clone(), - // config.bitcoin_rpc_user.clone(), - // config.bitcoin_rpc_password.clone(), - // ); - - // let (operator_client, operator_handle, _verifiers) = - // create_operator_and_verifiers(config, rpc).await; - - // println!("Operator server started: {:?}", operator_client); - - // operator_handle.stopped().await; - // for verifier in _verifiers { - // verifier.1.stopped().await; - // } -} diff --git a/core/src/bin/operators_and_verifiers.rs b/core/src/bin/operators_and_verifiers.rs new file mode 100644 index 00000000..50b3aa78 --- /dev/null +++ b/core/src/bin/operators_and_verifiers.rs @@ -0,0 +1,41 @@ +use clementine_core::{cli, extended_rpc::ExtendedRpc, servers::create_operators_and_verifiers}; + +/// ```bash +/// curl -X POST http://127.0.0.1:3434 -H "Content-Type: application/json" -d '{ +/// "jsonrpc": "2.0", +/// "method": "operator_new_deposit", +/// "params": { +/// "start_utxo": "2964713fecf26d6eec7df4420bed1e09de1bdab2cacd24a1c8c0afd70c8a5371:3", +/// "recovery_taproot_address": "781990d7e2118cc361a93a6fcc54ce611d6df38168d6b1edfb556535f2200c4b", +/// "evm_address": "0101010101010101010101010101010101010101" +/// }, +/// "id": 1 +/// }' +/// ``` +#[tokio::main] +async fn main() { + let config = cli::get_configuration(); + let rpc = ExtendedRpc::::new( + config.bitcoin_rpc_url.clone(), + config.bitcoin_rpc_user.clone(), + config.bitcoin_rpc_password.clone(), + ); + + let (operator_clients, verifier_clients) = create_operators_and_verifiers(config, rpc).await; + + println!("Operator servers started: {:?}", operator_clients); + println!("Verifier servers started: {:?}", verifier_clients); + println!("Number of operator clients: {}", operator_clients.len()); + println!("Number of verifier clients: {}", verifier_clients.len()); + + // Stop all servers + for (_, handle, _) in operator_clients { + handle.clone().stopped().await; + } + + for (_, handle, _) in verifier_clients { + handle.clone().stopped().await; + } + + println!("All servers stopped"); +} diff --git a/core/src/database/common.rs b/core/src/database/common.rs index a872a31a..222c51fc 100644 --- a/core/src/database/common.rs +++ b/core/src/database/common.rs @@ -78,16 +78,17 @@ impl Database { config: BridgeConfig, database_name: &str, ) -> Result { + println!("Creating database: {}", database_name); let url = "postgresql://".to_owned() + config.db_user.as_str() + ":" + config.db_password.as_str() + "@" + config.db_host.as_str(); + println!("url: {}", url); let conn = sqlx::PgPool::connect(url.as_str()).await?; - Database::drop_database(config.clone(), database_name).await?; - + println!("Dropped database"); let query = format!( "CREATE DATABASE {} WITH OWNER {}", database_name, config.db_user diff --git a/core/src/servers.rs b/core/src/servers.rs index e7c29e1f..114a9fe7 100644 --- a/core/src/servers.rs +++ b/core/src/servers.rs @@ -4,6 +4,7 @@ use crate::{ config::BridgeConfig, + database::common::Database, errors, extended_rpc::ExtendedRpc, operator, @@ -23,10 +24,11 @@ use traits::rpc::OperatorRpcServer; pub async fn create_verifier_server( config: BridgeConfig, rpc: ExtendedRpc, -) -> Result<(HttpClient, ServerHandle), BridgeError> +) -> Result<(HttpClient, ServerHandle, std::net::SocketAddr), BridgeError> where R: RpcApiWrapper, { + println!("Database created"); let server = match Server::builder() .build(format!("{}:{}", config.host, config.port)) .await @@ -34,10 +36,9 @@ where Ok(s) => s, Err(e) => return Err(BridgeError::ServerError(e)), }; - let verifier = Verifier::new(rpc, config).await?; - let addr = match server.local_addr() { + let addr: std::net::SocketAddr = match server.local_addr() { Ok(a) => a, Err(e) => return Err(BridgeError::ServerError(e)), }; @@ -49,14 +50,14 @@ where tracing::info!("Verifier server started with address: {}", addr); - Ok((client, handle)) + Ok((client, handle, addr)) } /// Starts the server for the operator. pub async fn create_operator_server( config: BridgeConfig, rpc: ExtendedRpc, -) -> Result<(HttpClient, ServerHandle), BridgeError> +) -> Result<(HttpClient, ServerHandle, std::net::SocketAddr), BridgeError> where R: RpcApiWrapper, { @@ -82,70 +83,76 @@ where tracing::info!("Operator server started with address: {}", addr); - Ok((client, handle)) + Ok((client, handle, addr)) } -// / Starts operator and verifiers servers. This function's intended use is for -// / tests. -// / -// / # Returns -// / -// / Returns a tuple, containing `HttpClient` for operator, `ServerHandle` for -// / operator and a vector containing `SocketAddr` and `ServerHandle` for -// / verifiers + operator (operator last). -// / -// / # Panics -// / -// / Panics if there was an error while creating any of the servers. -// pub async fn create_operator_and_verifiers( -// config: BridgeConfig, -// rpc: ExtendedRpc, -// ) -> ( -// Vec<(HttpClient, ServerHandle)>, // Verifier clients -// Vec<(HttpClient, ServerHandle)>, // Operator clients -// ) -// where -// R: RpcApiWrapper, -// { -// let mut all_secret_keys = config.all_secret_keys.clone().unwrap_or_else(|| { -// panic!("All secret keys are required for testing"); -// }); - -// let futures = all_verifiers_secret_keys -// .iter() -// .enumerate() -// .map(|(i, sk)| { -// create_verifier_server( -// BridgeConfig { -// verifiers_public_keys: config.verifiers_public_keys.clone(), -// secret_key: *sk, -// port: 0, // Use the index to calculate the port -// db_name: config.db_name.clone() + &i.to_string(), -// ..config.clone() -// }, -// rpc.clone(), -// ) -// }) -// .collect::>(); -// let mut results = futures::future::try_join_all(futures).await.unwrap(); - -// let verifier_endpoints: Vec = results -// .iter() -// .map(|(socket_addr, _)| format!("http://{}:{}/", socket_addr.ip(), socket_addr.port())) -// .collect(); - -// let (operator_socket_addr, operator_handle) = -// create_operator_server(config, rpc) -// .await -// .unwrap(); -// let operator_client = HttpClientBuilder::default() -// .build(format!( -// "http://{}:{}/", -// operator_socket_addr.ip(), -// operator_socket_addr.port() -// )) -// .unwrap(); -// results.push((operator_socket_addr, operator_handle.clone())); - -// (operator_client, operator_handle, results) -// } +/// Starts operators and verifiers servers. This function's intended use is for +/// tests. +/// +/// # Returns +/// +/// Returns a tuple of vectors of clients, handles, and addresses for the +/// verifiers + operators. +/// +/// # Panics +/// +/// Panics if there was an error while creating any of the servers. +pub async fn create_operators_and_verifiers( + config: BridgeConfig, + rpc: ExtendedRpc, +) -> ( + Vec<(HttpClient, ServerHandle, std::net::SocketAddr)>, // Verifier clients + Vec<(HttpClient, ServerHandle, std::net::SocketAddr)>, // Operator clients +) +where + R: RpcApiWrapper, +{ + let all_verifiers_secret_keys = config.all_verifiers_secret_keys.clone().unwrap_or_else(|| { + panic!("All secret keys of the verifiers are required for testing"); + }); + let verifier_futures = all_verifiers_secret_keys + .iter() + .enumerate() + .map(|(i, sk)| { + create_verifier_server( + BridgeConfig { + secret_key: *sk, + port: 0, // Use the index to calculate the port + db_name: config.db_name.clone() + &"verifier".to_string() + &i.to_string(), + db_user: config.db_user.clone() + &"verifier".to_string() + &i.to_string(), + ..config.clone() + }, + rpc.clone(), + ) + }) + .collect::>(); + let verifier_endpoints = futures::future::try_join_all(verifier_futures) + .await + .unwrap(); + + let all_operators_secret_keys = config.all_operators_secret_keys.clone().unwrap_or_else(|| { + panic!("All secret keys of the verifiers are required for testing"); + }); + + let operator_futures = all_operators_secret_keys + .iter() + .enumerate() + .map(|(i, sk)| { + create_verifier_server( + BridgeConfig { + secret_key: *sk, + port: 0, // Use the index to calculate the port + db_name: config.db_name.clone() + &"operator".to_string() + &i.to_string(), + db_user: config.db_user.clone() + &"operator".to_string() + &i.to_string(), + ..config.clone() + }, + rpc.clone(), + ) + }) + .collect::>(); + let operator_endpoints = futures::future::try_join_all(operator_futures) + .await + .unwrap(); + + (verifier_endpoints, operator_endpoints) +} diff --git a/core/tests/flow.rs b/core/tests/flow.rs index e49ef024..a845af3f 100644 --- a/core/tests/flow.rs +++ b/core/tests/flow.rs @@ -32,9 +32,10 @@ async fn test_withdrawal_request() { let mut config = create_test_config_with_thread_name!("test_config_flow.toml"); let rpc = create_extended_rpc!(config); - let (operator_client, _operator_handler) = create_operator_server(config.clone(), rpc.clone()) - .await - .unwrap(); + let (operator_client, _operator_handler, _operator_addr) = + create_operator_server(config.clone(), rpc.clone()) + .await + .unwrap(); let secp = bitcoin::secp256k1::Secp256k1::new(); let user_sk = SecretKey::from_slice(&OsRng.gen::<[u8; 32]>()).unwrap(); let user = User::new(rpc, user_sk, config.clone()); @@ -58,13 +59,6 @@ async fn test_honest_operator_takes_refund() { let mut config = create_test_config_with_thread_name!("test_config_flow.toml"); let rpc = create_extended_rpc!(config); - let (operator_client, _operator_handler) = create_operator_server(config.clone(), rpc.clone()) - .await - .unwrap(); - create_verifier_server(config.clone(), rpc.clone()) - .await - .unwrap(); - let secp = bitcoin::secp256k1::Secp256k1::new(); let user_sk = SecretKey::from_slice(&OsRng.gen::<[u8; 32]>()).unwrap(); let user = User::new(rpc, user_sk, config.clone()); @@ -76,11 +70,11 @@ async fn test_honest_operator_takes_refund() { ); let (empty_utxo, withdrawal_tx_out, user_sig) = user.generate_withdrawal_sig(withdrawal_address).unwrap(); - let withdrawal_provide_txid = operator_client - .new_withdrawal_sig_rpc(0, user_sig, empty_utxo, withdrawal_tx_out) - .await - .unwrap(); - println!("{:?}", withdrawal_provide_txid); + // let withdrawal_provide_txid = operator_client + // .new_withdrawal_sig_rpc(0, user_sig, empty_utxo, withdrawal_tx_out) + // .await + // .unwrap(); + // println!("{:?}", withdrawal_provide_txid); } #[tokio::test] From 5d80aa4c76d2777627d501293cfac2542d8882fa Mon Sep 17 00:00:00 2001 From: ozankaymak Date: Mon, 26 Aug 2024 11:37:59 +0300 Subject: [PATCH 8/8] Rename, refactor --- core/src/bin/operators_and_verifiers.rs | 4 +- core/src/script_builder.rs | 40 ------- core/src/servers.rs | 4 +- core/src/transaction_builder.rs | 151 ------------------------ core/tests/{flow.rs => withdrawal.rs} | 0 5 files changed, 4 insertions(+), 195 deletions(-) rename core/tests/{flow.rs => withdrawal.rs} (100%) diff --git a/core/src/bin/operators_and_verifiers.rs b/core/src/bin/operators_and_verifiers.rs index 50b3aa78..d7ad7af3 100644 --- a/core/src/bin/operators_and_verifiers.rs +++ b/core/src/bin/operators_and_verifiers.rs @@ -1,4 +1,4 @@ -use clementine_core::{cli, extended_rpc::ExtendedRpc, servers::create_operators_and_verifiers}; +use clementine_core::{cli, extended_rpc::ExtendedRpc, servers::create_verifiers_and_operators}; /// ```bash /// curl -X POST http://127.0.0.1:3434 -H "Content-Type: application/json" -d '{ @@ -21,7 +21,7 @@ async fn main() { config.bitcoin_rpc_password.clone(), ); - let (operator_clients, verifier_clients) = create_operators_and_verifiers(config, rpc).await; + let (operator_clients, verifier_clients) = create_verifiers_and_operators(config, rpc).await; println!("Operator servers started: {:?}", operator_clients); println!("Verifier servers started: {:?}", verifier_clients); diff --git a/core/src/script_builder.rs b/core/src/script_builder.rs index 5783e0c7..31e6e9b3 100644 --- a/core/src/script_builder.rs +++ b/core/src/script_builder.rs @@ -69,46 +69,6 @@ pub fn create_musig2_and_operator_multisig_script( .into_script() } -// pub fn create_move_commit_script( -// nofn_xonly_pk: &XOnlyPublicKey, -// evm_address: &EVMAddress, -// kickoff_utxos: &[OutPoint], -// ) -> ScriptBuf { -// let citrea: [u8; 6] = "citrea".as_bytes().try_into().unwrap(); - -// let builder = Builder::new() -// .push_x_only_key(nofn_xonly_pk) -// .push_opcode(OP_CHECKSIG) -// .push_opcode(OP_FALSE) -// .push_opcode(OP_IF) -// .push_slice(citrea) -// .push_slice(evm_address.0); - -// let builder = kickoff_utxos.iter().fold(builder, |b, utxo| { -// b.push_slice(utxo.txid.to_byte_array()) // TODO: Optimize here -// .push_int(utxo.vout as i64) -// }); - -// builder.push_opcode(OP_ENDIF).into_script() -// } - -// pub fn create_inscription_script_32_bytes( -// public_key: &XOnlyPublicKey, -// data: &Vec<[u8; 32]>, -// ) -> ScriptBuf { -// let mut inscribe_preimage_script_builder = Builder::new() -// .push_x_only_key(public_key) -// .push_opcode(OP_CHECKSIG) -// .push_opcode(OP_FALSE) -// .push_opcode(OP_IF); -// for elem in data { -// inscribe_preimage_script_builder = inscribe_preimage_script_builder.push_slice(elem); -// } -// inscribe_preimage_script_builder = inscribe_preimage_script_builder.push_opcode(OP_ENDIF); - -// inscribe_preimage_script_builder.into_script() -// } - /// ATTENTION: If you want to spend a UTXO using timelock script, the /// condition is that (`# in the script`) < (`# in the sequence of the tx`) /// < (`# of blocks mined after UTXO`) appears on the chain. diff --git a/core/src/servers.rs b/core/src/servers.rs index 114a9fe7..73f7d765 100644 --- a/core/src/servers.rs +++ b/core/src/servers.rs @@ -97,7 +97,7 @@ where /// # Panics /// /// Panics if there was an error while creating any of the servers. -pub async fn create_operators_and_verifiers( +pub async fn create_verifiers_and_operators( config: BridgeConfig, rpc: ExtendedRpc, ) -> ( @@ -131,7 +131,7 @@ where .unwrap(); let all_operators_secret_keys = config.all_operators_secret_keys.clone().unwrap_or_else(|| { - panic!("All secret keys of the verifiers are required for testing"); + panic!("All secret keys of the operators are required for testing"); }); let operator_futures = all_operators_secret_keys diff --git a/core/src/transaction_builder.rs b/core/src/transaction_builder.rs index 8a66bb9b..a0f466cc 100644 --- a/core/src/transaction_builder.rs +++ b/core/src/transaction_builder.rs @@ -130,39 +130,6 @@ impl TransactionBuilder { ) } - // pub fn generate_move_commit_address( - // nofn_xonly_pk: &XOnlyPublicKey, - // recovery_taproot_address: &Address, - // user_evm_address: &EVMAddress, - // kickoff_utxos: &[OutPoint], - // relative_block_height_to_take_after: u32, - // network: bitcoin::Network, - // ) -> CreateAddressOutputs { - // let kickoffs_commit_script = script_builder::create_move_commit_script( - // nofn_xonly_pk, - // user_evm_address, - // kickoff_utxos, - // ); - - // let recovery_script_pubkey = recovery_taproot_address - // .clone() - // .assume_checked() - // .script_pubkey(); - // let recovery_extracted_xonly_pk = - // XOnlyPublicKey::from_slice(&recovery_script_pubkey.as_bytes()[2..34]).unwrap(); - - // let timelock_script = script_builder::generate_relative_timelock_script( - // &recovery_extracted_xonly_pk, - // relative_block_height_to_take_after, - // ); - - // TransactionBuilder::create_taproot_address( - // &[kickoffs_commit_script, timelock_script], - // None, - // network, - // ) - // } - pub fn create_musig2_address( nofn_xonly_pk: XOnlyPublicKey, network: bitcoin::Network, @@ -184,124 +151,6 @@ impl TransactionBuilder { // TX BUILDERS - // pub fn create_move_commit_tx( - // deposit_utxo: OutPoint, - // evm_address: &EVMAddress, - // recovery_taproot_address: &Address, - // deposit_user_takes_after: u32, - // nofn_xonly_pk: &XOnlyPublicKey, - // kickoff_utxos: &[OutPoint], - // relative_block_height_to_take_after: u32, - // network: bitcoin::Network, - // ) -> TxHandler { - // let anyone_can_spend_txout = script_builder::anyone_can_spend_txout(); - // let (move_commit_address, _) = TransactionBuilder::generate_move_commit_address( - // nofn_xonly_pk, - // recovery_taproot_address, - // evm_address, - // kickoff_utxos, - // relative_block_height_to_take_after, - // network, - // ); - - // let (deposit_address, deposit_taproot_spend_info) = - // TransactionBuilder::generate_deposit_address( - // nofn_xonly_pk, - // recovery_taproot_address, - // evm_address, - // BRIDGE_AMOUNT_SATS, - // deposit_user_takes_after, - // network, - // ); - - // let move_commit_txout = TxOut { - // value: Amount::from_sat(BRIDGE_AMOUNT_SATS) - // - Amount::from_sat(MOVE_COMMIT_TX_MIN_RELAY_FEE) - // - anyone_can_spend_txout.value, - // script_pubkey: move_commit_address.script_pubkey(), - // }; - - // let tx_ins = TransactionBuilder::create_tx_ins(vec![deposit_utxo]); - - // let move_commit_tx = TransactionBuilder::create_btc_tx( - // tx_ins, - // vec![move_commit_txout, anyone_can_spend_txout], - // ); - - // let prevouts = vec![TxOut { - // script_pubkey: deposit_address.script_pubkey(), - // value: Amount::from_sat(BRIDGE_AMOUNT_SATS), - // }]; - - // let deposit_script = vec![script_builder::create_deposit_script( - // nofn_xonly_pk, - // evm_address, - // BRIDGE_AMOUNT_SATS, - // )]; - - // TxHandler { - // tx: move_commit_tx, - // prevouts, - // scripts: vec![deposit_script], - // taproot_spend_infos: vec![deposit_taproot_spend_info], - // } - // } - - // pub fn create_move_reveal_tx( - // move_commit_utxo: OutPoint, - // evm_address: &EVMAddress, - // recovery_taproot_address: &Address, - // nofn_xonly_pk: &XOnlyPublicKey, - // kickoff_utxos: &[OutPoint], - // relative_block_height_to_take_after: u32, - // network: Network, - // ) -> TxHandler { - // let (musig2_address, _) = - // TransactionBuilder::create_musig2_address(*nofn_xonly_pk, network); - // let (move_commit_address, move_commit_taproot_spend_info) = - // TransactionBuilder::generate_move_commit_address( - // nofn_xonly_pk, - // recovery_taproot_address, - // evm_address, - // kickoff_utxos, - // relative_block_height_to_take_after, - // network, - // ); - // let move_reveal_txout = TxOut { - // value: Amount::from_sat(BRIDGE_AMOUNT_SATS) - // - Amount::from_sat(MOVE_COMMIT_TX_MIN_RELAY_FEE) - // - Amount::from_sat(MOVE_REVEAL_TX_MIN_RELAY_FEE) - // - script_builder::anyone_can_spend_txout().value - // - script_builder::anyone_can_spend_txout().value, - // script_pubkey: musig2_address.script_pubkey(), - // }; - - // let tx_ins = TransactionBuilder::create_tx_ins(vec![move_commit_utxo]); - - // let move_reveal_tx = TransactionBuilder::create_btc_tx( - // tx_ins, - // vec![move_reveal_txout, script_builder::anyone_can_spend_txout()], - // ); - - // let prevouts = vec![TxOut { - // script_pubkey: move_commit_address.script_pubkey(), - // value: Amount::from_sat(BRIDGE_AMOUNT_SATS), - // }]; - - // let move_commit_script = vec![script_builder::create_move_commit_script( - // nofn_xonly_pk, - // evm_address, - // kickoff_utxos, - // )]; - - // TxHandler { - // tx: move_reveal_tx, - // prevouts, - // scripts: vec![move_commit_script], - // taproot_spend_infos: vec![move_commit_taproot_spend_info], - // } - // } - /// Creates the move_tx to move the deposit. pub fn create_move_tx( deposit_outpoint: OutPoint, diff --git a/core/tests/flow.rs b/core/tests/withdrawal.rs similarity index 100% rename from core/tests/flow.rs rename to core/tests/withdrawal.rs