From 72523bb52a2292098314f728d6f28b23408a2c15 Mon Sep 17 00:00:00 2001 From: ozankaymak Date: Wed, 11 Sep 2024 18:16:23 +0300 Subject: [PATCH] WIP additional testing with small fixes + db problem --- core/src/database/common.rs | 58 +++++- core/src/errors.rs | 12 ++ core/src/operator.rs | 16 +- core/tests/common.rs | 352 +++++++++++++++++++++++++++++++++--- core/tests/flow.rs | 16 +- 5 files changed, 420 insertions(+), 34 deletions(-) diff --git a/core/src/database/common.rs b/core/src/database/common.rs index 4547eb08..61e74a91 100644 --- a/core/src/database/common.rs +++ b/core/src/database/common.rs @@ -1139,6 +1139,62 @@ mod tests { assert!(db_utxo.is_none()); } + #[tokio::test] + async fn test_deposit_kickoff_generator_tx_0() { + let config = create_test_config_with_thread_name("test_config.toml", None).await; + let db = Database::new(config).await.unwrap(); + + let raw_hex = "02000000000101eb87b1a80d47b7f5bd5082b77653f5ca37e566951742b80c361875ba0e5c478f0a00000000fdffffff0ca086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca3a086010000000000225120b23da6d2e0390018b953f7d74e3582da4da30fd0fd157cc84a2d2753003d1ca35c081777000000002251202a64b1ee3375f3bb4b367b8cb8384a47f73cf231717f827c6c6fbbf5aecf0c364a010000000000002200204ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260014005a41e6f4a4bcfcc5cd3ef602687215f97c18949019a491df56af7413c5dce9292ba3966edc4564a39d9bc0d6c0faae19030f1cedf4d931a6cdc57cc5b83c8ef00000000".to_string(); + let tx: bitcoin::Transaction = + bitcoin::consensus::deserialize(&hex::decode(raw_hex.clone()).unwrap()).unwrap(); + let txid = tx.compute_txid(); + let num_kickoffs = tx.output.len() - 2; + let funding_txid = tx.input[0].previous_output.txid; + db.add_deposit_kickoff_generator_tx( + None, + txid, + raw_hex.clone(), + num_kickoffs, + funding_txid, + ) + .await + .unwrap(); + for i in 0..num_kickoffs - 1 { + let (db_raw_hex, db_num_kickoffs, db_cur_unused_kickoff_index, db_funding_txid) = db + .get_deposit_kickoff_generator_tx(txid) + .await + .unwrap() + .unwrap(); + + // Sanity check + assert_eq!(db_raw_hex, raw_hex); + assert_eq!(db_num_kickoffs, num_kickoffs); + assert_eq!(db_cur_unused_kickoff_index, i + 1); + assert_eq!(db_funding_txid, funding_txid); + + let unused_utxo = db + .get_unused_kickoff_utxo_and_increase_idx(None) + .await + .unwrap() + .unwrap(); + tracing::info!("unused_utxo: {:?}", unused_utxo); + + // Sanity check + assert_eq!(unused_utxo.outpoint.txid, txid); + assert_eq!(unused_utxo.outpoint.vout, i as u32 + 1); + } + } + + #[tokio::test] + async fn test_deposit_kickoff_generator_tx_2() { + let config = create_test_config_with_thread_name("test_config.toml", None).await; + let db = Database::new(config).await.unwrap(); + + let txid = Txid::from_byte_array([1u8; 32]); + let res = db.get_deposit_kickoff_generator_tx(txid).await.unwrap(); + assert!(res.is_none()); + } + #[tokio::test] async fn test_deposit_kickoff_generator_tx_1() { let config = create_test_config_with_thread_name("test_config.toml", None).await; @@ -1190,7 +1246,7 @@ mod tests { } #[tokio::test] - async fn test_deposit_kickoff_generator_tx_2() { + async fn test_deposit_kickoff_generator_tx_3() { let config = create_test_config_with_thread_name("test_config.toml", None).await; let db = Database::new(config).await.unwrap(); diff --git a/core/src/errors.rs b/core/src/errors.rs index b4a96843..2d8243f1 100644 --- a/core/src/errors.rs +++ b/core/src/errors.rs @@ -182,6 +182,18 @@ pub enum BridgeError { #[error("NotEnoughFeeForOperator")] NotEnoughFeeForOperator, + #[error("KickoffGeneratorTxNotFound")] + KickoffGeneratorTxNotFound, + + #[error("KickoffGeneratorTxsTooManyIterations")] + KickoffGeneratorTxsTooManyIterations, + + #[error("OperatorSlashOrTakeSigNotFound")] + OperatorSlashOrTakeSigNotFound, + + #[error("OperatorTakesSigNotFound")] + OperatorTakesSigNotFound, + #[error("Musig2 error: {0}")] Musig2Error(#[from] musig2::secp256k1::Error), } diff --git a/core/src/operator.rs b/core/src/operator.rs index 20859c7b..895d91a8 100644 --- a/core/src/operator.rs +++ b/core/src/operator.rs @@ -93,6 +93,12 @@ where None }; + tracing::debug!( + "Operator idx: {:?}, db created with name: {:?}", + idx, + config.db_name + ); + Ok(Self { rpc, db, @@ -513,7 +519,7 @@ where .get_kickoff_utxo(None, deposit_outpoint) .await? .ok_or(BridgeError::KickoffOutpointsNotFound)?; - tracing::debug!("Kickoff UTXO FOUND: {:?}", kickoff_utxo); + tracing::debug!("Kickoff UTXO FOUND after withdrawal: {:?}", kickoff_utxo); let mut txs_to_be_sent = vec![]; let mut current_searching_txid = kickoff_utxo.outpoint.txid; let mut found_txid = false; @@ -534,7 +540,7 @@ where .db .get_deposit_kickoff_generator_tx(current_searching_txid) .await? - .ok_or(BridgeError::KickoffOutpointsNotFound)?; // TODO: Fix this error + .ok_or(BridgeError::KickoffGeneratorTxNotFound)?; txs_to_be_sent.push(raw_signed_tx); current_searching_txid = funding_txid; @@ -544,7 +550,7 @@ where // Handle the case where no transaction was found in 25 iterations if !found_txid { - return Err(BridgeError::KickoffOutpointsNotFound); // TODO: Fix this error + return Err(BridgeError::KickoffGeneratorTxsTooManyIterations); // TODO: Fix this error } // tracing::debug!("Found txs to be sent: {:?}", txs_to_be_sent); @@ -576,7 +582,7 @@ where .db .get_slash_or_take_sig(deposit_outpoint, kickoff_utxo.clone()) .await? - .ok_or(BridgeError::KickoffOutpointsNotFound)?; // TODO: Fix this error + .ok_or(BridgeError::OperatorSlashOrTakeSigNotFound)?; // tracing::debug!("Found nofn sig: {:?}", nofn_sig); @@ -633,7 +639,7 @@ where .db .get_operator_take_sig(deposit_outpoint, kickoff_utxo) .await? - .ok_or(BridgeError::KickoffOutpointsNotFound)?; // TODO: Fix this error + .ok_or(BridgeError::OperatorTakesSigNotFound)?; tracing::debug!("Operator Found nofn sig: {:?}", operator_takes_nofn_sig); let our_sig = self diff --git a/core/tests/common.rs b/core/tests/common.rs index 9eab7ec0..37da50dc 100644 --- a/core/tests/common.rs +++ b/core/tests/common.rs @@ -1,6 +1,7 @@ //! # Common utilities for tests use bitcoin::consensus::encode::deserialize_hex; +use bitcoin::Address; use bitcoin::OutPoint; use bitcoin::Transaction; use clementine_core::actor::Actor; @@ -16,19 +17,17 @@ use clementine_core::traits::rpc::OperatorRpcClient; use clementine_core::traits::rpc::VerifierRpcClient; use clementine_core::user::User; use clementine_core::EVMAddress; -use clementine_core::UTXO; use jsonrpsee::http_client::HttpClient; use jsonrpsee::server::ServerHandle; use secp256k1::schnorr; use std::net::SocketAddr; -pub async fn run_multiple_deposit( - test_config_name: &str, -) -> Result<(Vec, Vec), BridgeError> { +pub async fn run_multiple_deposits(test_config_name: &str) { let mut config = create_test_config_with_thread_name(test_config_name, None).await; let rpc = create_extended_rpc!(config); - - let (_, operators, _) = create_verifiers_and_operators("test_config.toml").await; + let secp = secp256k1::Secp256k1::new(); + let (verifiers, operators, aggregator) = + create_verifiers_and_operators("test_config.toml").await; // println!("Operators: {:#?}", operators); // println!("Verifiers: {:#?}", verifiers); @@ -43,33 +42,340 @@ pub async fn run_multiple_deposit( let evm_address = EVMAddress([1u8; 20]); let deposit_address = user.get_deposit_address(evm_address).unwrap(); - let deposit_outpoints = (0..config.operator_num_kickoff_utxos_per_tx + 5).map(|_| { - let outpoint = rpc + let mut deposit_outpoints = Vec::new(); + for _ in 0..4 { + let deposit_outpoint = rpc .send_to_address(&deposit_address, config.bridge_amount_sats) .unwrap(); - rpc.mine_blocks(1).unwrap(); - outpoint - }); - for _ in 0..18 { - rpc.mine_blocks(1).unwrap(); - } + rpc.mine_blocks(18).unwrap(); + + // for every verifier, we call new_deposit + // aggregate nonces + let mut pub_nonces = Vec::new(); + + for (client, _, _) in verifiers.iter() { + let musig_pub_nonces = client + .verifier_new_deposit_rpc(deposit_outpoint, signer_address.clone(), evm_address) + .await + .unwrap(); - let mut kickoff_utxos = vec![]; - let mut signatures = vec![]; - for deposit_outpoint in deposit_outpoints { - println!("Deposit outpoint: {:#?}", deposit_outpoint); - let (kickoff_utxo, signature) = operators[0] + // tracing::info!("Musig Pub Nonces: {:?}", musig_pub_nonces); + + pub_nonces.push(musig_pub_nonces); + } + + let agg_nonces = aggregator .0 - .new_deposit_rpc(deposit_outpoint, signer_address.clone(), evm_address) + .aggregate_pub_nonces_rpc(pub_nonces) .await .unwrap(); + // call operators' new_deposit + let mut kickoff_utxos = Vec::new(); + let mut signatures = Vec::new(); - kickoff_utxos.push(kickoff_utxo); - signatures.push(signature); + for (client, _, _) in operators.iter() { + // Create deposit kickoff transaction + let (kickoff_utxo, signature) = client + .new_deposit_rpc(deposit_outpoint, signer_address.clone(), evm_address) + .await + .unwrap(); + + kickoff_utxos.push(kickoff_utxo); + signatures.push(signature); + } + + tracing::debug!("Now the verifiers sequence starts"); + let mut slash_or_take_partial_sigs = Vec::new(); + + for (client, ..) in verifiers.iter() { + let (partial_sigs, _) = client + .operator_kickoffs_generated_rpc( + deposit_outpoint, + kickoff_utxos.clone(), + signatures.clone(), + agg_nonces.clone(), + ) + .await + .unwrap(); + + slash_or_take_partial_sigs.push(partial_sigs); + } + + let slash_or_take_sigs = aggregator + .0 + .aggregate_slash_or_take_sigs_rpc( + deposit_outpoint, + kickoff_utxos.clone(), + agg_nonces[config.num_operators + 1..2 * config.num_operators + 1].to_vec(), + slash_or_take_partial_sigs, + ) + .await + .unwrap(); + + // tracing::debug!("Slash or take sigs: {:#?}", slash_or_take_sigs); + // call burn_txs_signed_rpc + let mut operator_take_partial_sigs: Vec> = Vec::new(); + for (client, ..) in verifiers.iter() { + let partial_sigs = client + .burn_txs_signed_rpc(deposit_outpoint, vec![], slash_or_take_sigs.clone()) + .await + .unwrap(); + operator_take_partial_sigs.push(partial_sigs); + } + // tracing::debug!( + // "Operator take partial sigs: {:#?}", + // operator_take_partial_sigs + // ); + let operator_take_sigs = aggregator + .0 + .aggregate_operator_take_sigs_rpc( + deposit_outpoint, + kickoff_utxos.clone(), + agg_nonces[1..config.num_operators + 1].to_vec(), + operator_take_partial_sigs, + ) + .await + .unwrap(); + // tracing::debug!("Operator take sigs: {:#?}", operator_take_sigs); + // call operator_take_txs_signed_rpc + let mut move_tx_partial_sigs = Vec::new(); + for (client, _, _) in verifiers.iter() { + let move_tx_partial_sig = client + .operator_take_txs_signed_rpc(deposit_outpoint, operator_take_sigs.clone()) + .await + .unwrap(); + move_tx_partial_sigs.push(move_tx_partial_sig); + } + + // tracing::debug!("Move tx partial sigs: {:#?}", move_tx_partial_sigs); + + // aggreagte move_tx_partial_sigs + + let (move_tx, _) = aggregator + .0 + .aggregate_move_tx_sigs_rpc( + deposit_outpoint, + signer_address.clone(), + evm_address, + agg_nonces[0], + move_tx_partial_sigs, + ) + .await + .unwrap(); + let move_tx: Transaction = deserialize_hex(&move_tx).unwrap(); + // tracing::debug!("Move tx: {:#?}", move_tx); + // tracing::debug!("Move tx_hex: {:?}", move_tx_handler.tx.raw_hex()); + tracing::debug!("Move tx weight: {:?}", move_tx.weight()); + let move_txid = rpc.send_raw_transaction(&move_tx).unwrap(); + tracing::debug!("Move txid: {:?}", move_txid); + let deposit_outpoint = rpc + .send_to_address(&deposit_address, config.bridge_amount_sats) + .unwrap(); + + rpc.mine_blocks(18).unwrap(); + + // for every verifier, we call new_deposit + // aggregate nonces + let mut pub_nonces = Vec::new(); + + for (client, _, _) in verifiers.iter() { + let musig_pub_nonces = client + .verifier_new_deposit_rpc(deposit_outpoint, signer_address.clone(), evm_address) + .await + .unwrap(); + + // tracing::info!("Musig Pub Nonces: {:?}", musig_pub_nonces); + + pub_nonces.push(musig_pub_nonces); + } + + let agg_nonces = aggregator + .0 + .aggregate_pub_nonces_rpc(pub_nonces) + .await + .unwrap(); + // call operators' new_deposit + let mut kickoff_utxos = Vec::new(); + let mut signatures = Vec::new(); + + for (client, _, _) in operators.iter() { + // Create deposit kickoff transaction + let (kickoff_utxo, signature) = client + .new_deposit_rpc(deposit_outpoint, signer_address.clone(), evm_address) + .await + .unwrap(); + + kickoff_utxos.push(kickoff_utxo); + signatures.push(signature); + } + + tracing::debug!("Now the verifiers sequence starts"); + let mut slash_or_take_partial_sigs = Vec::new(); + + for (client, ..) in verifiers.iter() { + let (partial_sigs, _) = client + .operator_kickoffs_generated_rpc( + deposit_outpoint, + kickoff_utxos.clone(), + signatures.clone(), + agg_nonces.clone(), + ) + .await + .unwrap(); + + slash_or_take_partial_sigs.push(partial_sigs); + } + + let slash_or_take_sigs = aggregator + .0 + .aggregate_slash_or_take_sigs_rpc( + deposit_outpoint, + kickoff_utxos.clone(), + agg_nonces[config.num_operators + 1..2 * config.num_operators + 1].to_vec(), + slash_or_take_partial_sigs, + ) + .await + .unwrap(); + + // tracing::debug!("Slash or take sigs: {:#?}", slash_or_take_sigs); + // call burn_txs_signed_rpc + let mut operator_take_partial_sigs: Vec> = Vec::new(); + for (client, ..) in verifiers.iter() { + let partial_sigs = client + .burn_txs_signed_rpc(deposit_outpoint, vec![], slash_or_take_sigs.clone()) + .await + .unwrap(); + operator_take_partial_sigs.push(partial_sigs); + } + // tracing::debug!( + // "Operator take partial sigs: {:#?}", + // operator_take_partial_sigs + // ); + let operator_take_sigs = aggregator + .0 + .aggregate_operator_take_sigs_rpc( + deposit_outpoint, + kickoff_utxos.clone(), + agg_nonces[1..config.num_operators + 1].to_vec(), + operator_take_partial_sigs, + ) + .await + .unwrap(); + // tracing::debug!("Operator take sigs: {:#?}", operator_take_sigs); + // call operator_take_txs_signed_rpc + let mut move_tx_partial_sigs = Vec::new(); + for (client, _, _) in verifiers.iter() { + let move_tx_partial_sig = client + .operator_take_txs_signed_rpc(deposit_outpoint, operator_take_sigs.clone()) + .await + .unwrap(); + move_tx_partial_sigs.push(move_tx_partial_sig); + } + + // tracing::debug!("Move tx partial sigs: {:#?}", move_tx_partial_sigs); + + // aggreagte move_tx_partial_sigs + + let (move_tx, _) = aggregator + .0 + .aggregate_move_tx_sigs_rpc( + deposit_outpoint, + signer_address.clone(), + evm_address, + agg_nonces[0], + move_tx_partial_sigs, + ) + .await + .unwrap(); + let move_tx: Transaction = deserialize_hex(&move_tx).unwrap(); + // tracing::debug!("Move tx: {:#?}", move_tx); + // tracing::debug!("Move tx_hex: {:?}", move_tx_handler.tx.raw_hex()); + tracing::debug!("Move tx weight: {:?}", move_tx.weight()); + let move_txid = rpc.send_raw_transaction(&move_tx).unwrap(); + tracing::debug!("Move txid: {:?}", move_txid); + deposit_outpoints.push(deposit_outpoint); } - Ok((kickoff_utxos, signatures)) + let withdrawal_address = Address::p2tr( + &secp, + secret_key.x_only_public_key(&secp).0, + None, + config.network, + ); + let (user_utxo, user_txout, user_sig) = user + .generate_withdrawal_sig( + withdrawal_address.clone(), + config.bridge_amount_sats - 2 * config.operator_withdrawal_fee_sats.unwrap(), + ) + .unwrap(); + let withdrawal_provide_txid = operators[0] + .0 + .new_withdrawal_sig_rpc(0, user_sig, user_utxo, user_txout) + .await + .unwrap(); + tracing::debug!("Withdrawal provide txid: {:?}", withdrawal_provide_txid); + let txs_to_be_sent = operators[0] + .0 + .withdrawal_proved_on_citrea_rpc(0, deposit_outpoints[0]) + .await + .unwrap(); + let (user_utxo, user_txout, user_sig) = user + .generate_withdrawal_sig( + withdrawal_address.clone(), + config.bridge_amount_sats - 2 * config.operator_withdrawal_fee_sats.unwrap(), + ) + .unwrap(); + let withdrawal_provide_txid = operators[0] + .0 + .new_withdrawal_sig_rpc(1, user_sig, user_utxo, user_txout) + .await + .unwrap(); + tracing::debug!("Withdrawal provide txid: {:?}", withdrawal_provide_txid); + let txs_to_be_sent = operators[0] + .0 + .withdrawal_proved_on_citrea_rpc(1, deposit_outpoints[1]) + .await + .unwrap(); + let (user_utxo, user_txout, user_sig) = user + .generate_withdrawal_sig( + withdrawal_address.clone(), + config.bridge_amount_sats - 2 * config.operator_withdrawal_fee_sats.unwrap(), + ) + .unwrap(); + let withdrawal_provide_txid = operators[0] + .0 + .new_withdrawal_sig_rpc(2, user_sig, user_utxo, user_txout) + .await + .unwrap(); + tracing::debug!("Withdrawal provide txid: {:?}", withdrawal_provide_txid); + let txs_to_be_sent = operators[0] + .0 + .withdrawal_proved_on_citrea_rpc(2, deposit_outpoints[2]) + .await + .unwrap(); + let (user_utxo, user_txout, user_sig) = user + .generate_withdrawal_sig( + withdrawal_address.clone(), + config.bridge_amount_sats - 2 * config.operator_withdrawal_fee_sats.unwrap(), + ) + .unwrap(); + let withdrawal_provide_txid = operators[0] + .0 + .new_withdrawal_sig_rpc(3, user_sig, user_utxo, user_txout) + .await + .unwrap(); + tracing::debug!("Withdrawal provide txid: {:?}", withdrawal_provide_txid); + let txs_to_be_sent = operators[0] + .0 + .withdrawal_proved_on_citrea_rpc(3, deposit_outpoints[3]) + .await + .unwrap(); + // let txs_to_be_sent = operators[0].0.withdrawal_proved_on_citrea_rpc(1, deposit_outpoints[1]).await.unwrap(); + // tracing::debug!("txs_to_be_sent.len: {:#?}", txs_to_be_sent.len()); + assert!(false); + // let _ = txs_to_be_sent[0.] } + pub async fn run_single_deposit( test_config_name: &str, ) -> Result< diff --git a/core/tests/flow.rs b/core/tests/flow.rs index 53a07ec2..db3e3064 100644 --- a/core/tests/flow.rs +++ b/core/tests/flow.rs @@ -7,7 +7,7 @@ use clementine_core::extended_rpc::ExtendedRpc; use clementine_core::{ create_extended_rpc, errors::BridgeError, traits::rpc::OperatorRpcClient, user::User, }; -use common::{run_multiple_deposit, run_single_deposit}; +use common::{run_multiple_deposits, run_single_deposit}; use secp256k1::SecretKey; mod common; @@ -46,7 +46,10 @@ async fn test_honest_operator_takes_refund() { ); // We are giving 99_800_000 sats to the user so that the operator can pay the withdrawal and profit. let (empty_utxo, withdrawal_tx_out, user_sig) = user - .generate_withdrawal_sig(withdrawal_address, 99_800_000) + .generate_withdrawal_sig( + withdrawal_address, + config.bridge_amount_sats - 2 * config.operator_withdrawal_fee_sats.unwrap(), + ) .unwrap(); let withdrawal_provide_txid = operators[1] .0 @@ -75,7 +78,10 @@ async fn test_honest_operator_takes_refund() { let operator_take_tx = rpc.get_raw_transaction(&operator_take_txid, None).unwrap(); assert!( - operator_take_tx.output[0].value > bitcoin::Amount::from_sat(99_800_000), + operator_take_tx.output[0].value + > bitcoin::Amount::from_sat( + config.bridge_amount_sats - 2 * config.operator_withdrawal_fee_sats.unwrap() + ), "Expected value to be greater than 99,800,000 satoshis, but it was not." ); assert_eq!( @@ -104,7 +110,7 @@ async fn test_withdrawal_fee_too_low() { ); // We are giving 100_000_000 sats to the user so that the operator cannot pay it because it is not profitable. let (empty_utxo, withdrawal_tx_out, user_sig) = user - .generate_withdrawal_sig(withdrawal_address, 100_000_000) + .generate_withdrawal_sig(withdrawal_address, config.bridge_amount_sats) .unwrap(); let withdrawal_provide_txid = operators[0] .0 @@ -115,5 +121,5 @@ async fn test_withdrawal_fee_too_low() { #[tokio::test] async fn multiple_deposits_for_operator() { - run_multiple_deposit("test_config.toml").await.unwrap(); + run_multiple_deposits("test_config.toml").await; }