Skip to content

Commit

Permalink
Merge withdrawal into ekrem/new-architecture (#234)
Browse files Browse the repository at this point in the history
* WIP

* nits

* Add sig check for withdrawal (#229)

* Add sig check for withdrawal

* Use tx.verify

---------

Co-authored-by: Ekrem BAL <mail.ekrembal@gmail.com>

* Impl operator paying withdrawal

* Merge ozan/withdrawal-endpoint-test into ekrem-new-architecture (#230)

* wip

* WIP: created operators and verifiers

* Add steps for the flow

* Add withdrawal endpoint test,organize configs

* Flaky but ok

* Fix flakiness

* Remove unnecessary serialization

---------

Co-authored-by: lemonpartee <lemonpartey@proton.me>
Co-authored-by: Ekrem BAL <mail.ekrembal@gmail.com>

* Merge ozan/kickoff-root-operations into withdrawal (#231)

* WIP Implement endpoints with db operations and tests

* wip

* WIP

* WIP

* Implement changes

* Apply review changes

* Refactor the binaries

* Rename, refactor

---------

Co-authored-by: Ekrem BAL <mail.ekrembal@gmail.com>

---------

Co-authored-by: Ekrem BAL <mail.ekrembal@gmail.com>
Co-authored-by: lemonpartee <lemonpartey@proton.me>
  • Loading branch information
3 people authored Aug 26, 2024
1 parent 70fa7c3 commit 6efc136
Show file tree
Hide file tree
Showing 22 changed files with 762 additions and 782 deletions.
4 changes: 2 additions & 2 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
23 changes: 14 additions & 9 deletions core/src/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,28 +147,33 @@ impl Actor {
let mut sighash_cache = SighashCache::new(tx);
let sig_hash = sighash_cache.taproot_key_spend_signature_hash(
input_index,
&bitcoin::sighash::Prevouts::All(prevouts),
&match sighash_type {
Some(TapSighashType::SinglePlusAnyoneCanPay) => {
bitcoin::sighash::Prevouts::One(input_index, prevouts[input_index].clone())
}
_ => bitcoin::sighash::Prevouts::All(prevouts),
},
sighash_type.unwrap_or(TapSighashType::Default),
)?;
self.sign_with_tweak(sig_hash, None)
}

pub fn sign_taproot_script_spend_tx_new_tweaked(
&self,
tx: &mut TxHandler,
tx_handler: &mut TxHandler,
txin_index: usize,
script_index: usize,
) -> Result<schnorr::Signature, BridgeError> {
// TODO: if sighash_cache exists in the TxHandler, use it
// 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,
Expand All @@ -177,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<TapSighash, BridgeError> {
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,
Expand Down
3 changes: 1 addition & 2 deletions core/src/bin/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ use clementine_core::{cli, extended_rpc::ExtendedRpc, servers::create_operator_s
#[tokio::main]
async fn main() {
let config = cli::get_configuration();
let verifier_endpoints = config.verifier_endpoints.clone().unwrap();
let rpc = ExtendedRpc::<bitcoincore_rpc::Client>::new(
config.bitcoin_rpc_url.clone(),
config.bitcoin_rpc_user.clone(),
config.bitcoin_rpc_password.clone(),
);

create_operator_server(config, rpc, verifier_endpoints)
create_operator_server(config, rpc)
.await
.unwrap()
.1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use clementine_core::{cli, extended_rpc::ExtendedRpc, servers::create_operator_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 '{
Expand All @@ -21,13 +21,21 @@ async fn main() {
config.bitcoin_rpc_password.clone(),
);

let (operator_client, operator_handle, _verifiers) =
create_operator_and_verifiers(config, rpc).await;
let (operator_clients, verifier_clients) = create_verifiers_and_operators(config, rpc).await;

println!("Operator server started: {:?}", operator_client);
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());

operator_handle.stopped().await;
for verifier in _verifiers {
verifier.1.stopped().await;
// 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");
}
3 changes: 2 additions & 1 deletion core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ pub struct BridgeConfig {
/// Bitcoin RPC user password.
pub bitcoin_rpc_password: String,
/// All Secret keys. Just for testing purposes.
pub all_operators_secret_keys: Option<Vec<secp256k1::SecretKey>>,
pub all_verifiers_secret_keys: Option<Vec<secp256k1::SecretKey>>,
/// All Secret keys. Just for testing purposes.
pub all_operators_secret_keys: Option<Vec<secp256k1::SecretKey>>,
/// Verifier endpoints.
pub verifier_endpoints: Option<Vec<String>>,
/// PostgreSQL database host address.
Expand Down
70 changes: 67 additions & 3 deletions core/src/database/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,17 @@ impl Database {
config: BridgeConfig,
database_name: &str,
) -> Result<BridgeConfig, BridgeError> {
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
Expand Down Expand Up @@ -442,6 +443,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<Option<[u8; 32]>, BridgeError> {
// let qr: Option<String> = 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)]
Expand Down Expand Up @@ -476,7 +510,7 @@ mod tests {

#[tokio::test]
async fn test_valid_connection() {
let config = common::get_test_config("test_config.toml").unwrap();
let config = create_test_config_with_thread_name!("test_config.toml");

Database::new(config).await.unwrap();
}
Expand Down Expand Up @@ -868,6 +902,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)]
Expand Down
28 changes: 23 additions & 5 deletions core/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ pub enum BridgeError {
#[error("TryFromSliceError")]
TryFromSliceError,
/// Returned when bitcoin::Transaction error happens, also returns the error
#[error("BitcoinTransactionError")]
BitcoinTransactionError,
#[error("BitcoinTransactionError: {0}")]
BitcoinConsensusEncodeError(bitcoin::consensus::encode::Error),
/// TxInputNotFound is returned when the input is not found in the transaction
#[error("TxInputNotFound")]
TxInputNotFound,
Expand Down Expand Up @@ -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<ErrorObject<'static>> for BridgeError {
Expand Down Expand Up @@ -190,9 +196,9 @@ impl From<TryFromSliceError> for BridgeError {
}
}

impl From<bitcoin::Transaction> for BridgeError {
fn from(_error: bitcoin::Transaction) -> Self {
BridgeError::BitcoinTransactionError
impl From<bitcoin::consensus::encode::Error> for BridgeError {
fn from(err: bitcoin::consensus::encode::Error) -> Self {
BridgeError::BitcoinConsensusEncodeError(err)
}
}

Expand Down Expand Up @@ -261,3 +267,15 @@ impl From<musig2::errors::VerifyError> for BridgeError {
BridgeError::MuSig2VerifyError(err)
}
}

impl From<hex::FromHexError> for BridgeError {
fn from(err: hex::FromHexError) -> Self {
BridgeError::FromHexError(err)
}
}

impl From<bitcoin::hashes::FromSliceError> for BridgeError {
fn from(err: bitcoin::hashes::FromSliceError) -> Self {
BridgeError::FromSliceError(err)
}
}
14 changes: 12 additions & 2 deletions core/src/extended_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,15 +203,15 @@ where
Ok(block_height)
}

pub fn get_txout_from_utxo(&self, outpoint: &OutPoint) -> Result<TxOut, BridgeError> {
pub fn get_txout_from_outpoint(&self, outpoint: &OutPoint) -> Result<TxOut, BridgeError> {
let tx = self.client.get_raw_transaction(&outpoint.txid, None)?;
let txout = tx.output[outpoint.vout as usize].clone();

Ok(txout)
}

// Following methods are just wrappers around the bitcoincore_rpc::Client methods
pub fn fundrawtransaction(
pub fn fund_raw_transaction(
&self,
tx: &Transaction,
options: Option<&bitcoincore_rpc::json::FundRawTransactionOptions>,
Expand All @@ -220,6 +220,16 @@ where
self.client.fund_raw_transaction(tx, options, is_witness)
}

pub fn sign_raw_transaction_with_wallet<T: bitcoincore_rpc::RawTx>(
&self,
tx: T,
utxos: Option<&[bitcoincore_rpc::json::SignRawTransactionInput]>,
sighash_type: Option<bitcoincore_rpc::json::SigHashType>,
) -> Result<bitcoincore_rpc::json::SignRawTransactionResult, bitcoincore_rpc::Error> {
self.client
.sign_raw_transaction_with_wallet(tx, utxos, sighash_type)
}

pub fn get_blockchain_info(
&self,
) -> Result<bitcoincore_rpc::json::GetBlockchainInfoResult, bitcoincore_rpc::Error> {
Expand Down
9 changes: 9 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ pub struct UTXO {
pub txout: bitcoin::TxOut,
}

impl UTXO {
fn to_vec(&self) -> Vec<u8> {
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]);
Loading

0 comments on commit 6efc136

Please sign in to comment.