diff --git a/Cargo.lock b/Cargo.lock index 147c33f3..a339f0cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1594,6 +1594,7 @@ dependencies = [ "secp256k1-zkp", "serde", "serde_json", + "sha2", "sqlx", "uuid 1.4.1", ] @@ -2422,9 +2423,11 @@ version = "0.1.0" dependencies = [ "anyhow", "electrum-client", + "hex", "mercuryrustlib", "serde", "serde_json", + "sha2", "tokio", "uuid 1.4.1", ] diff --git a/clients/tests/rust/Cargo.toml b/clients/tests/rust/Cargo.toml index 99528b8f..227acc87 100644 --- a/clients/tests/rust/Cargo.toml +++ b/clients/tests/rust/Cargo.toml @@ -13,3 +13,5 @@ serde = { version = "1.0.163", features = ["derive"] } serde_json = "1.0.96" electrum-client = "0.18.0" uuid = { version = "1.3.1", features = ["v4", "serde"] } +sha2 = "0.10.8" +hex = "0.4.3" diff --git a/clients/tests/rust/src/bitcoin_core.rs b/clients/tests/rust/src/bitcoin_core.rs index 9c85d45f..eff64c8c 100644 --- a/clients/tests/rust/src/bitcoin_core.rs +++ b/clients/tests/rust/src/bitcoin_core.rs @@ -1,4 +1,4 @@ -use std::process::Command; +use std::{process::Command, thread}; use anyhow::{anyhow, Result, Ok}; pub fn get_container_id() -> Result { @@ -56,7 +56,12 @@ pub fn generatetoaddress(num_blocks: u32, address: &str) -> Result { "bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass generatetoaddress {} {}", num_blocks, address ); - execute_bitcoin_command(&bitcoin_command) + let res = execute_bitcoin_command(&bitcoin_command); + + // The command may take some time to execute + thread::sleep(std::time::Duration::from_secs(1)); + + res } pub fn getnewaddress() -> Result { diff --git a/clients/tests/rust/src/main.rs b/clients/tests/rust/src/main.rs index 487073d6..e52b3758 100644 --- a/clients/tests/rust/src/main.rs +++ b/clients/tests/rust/src/main.rs @@ -6,6 +6,7 @@ pub mod tb02_transfer_address_reuse; pub mod tb03_simple_atomic_transfer; pub mod tm01_sender_double_spends; pub mod ta01_sign_second_not_called; +pub mod tb04_simple_lightning_latch; use anyhow::{Result, Ok}; #[tokio::main(flavor = "current_thread")] @@ -14,8 +15,9 @@ async fn main() -> Result<()> { tb01_simple_transfer::execute().await?; tb02_transfer_address_reuse::execute().await?; tb03_simple_atomic_transfer::execute().await?; + tb04_simple_lightning_latch::execute().await?; tm01_sender_double_spends::execute().await?; ta01_sign_second_not_called::execute().await?; - + Ok(()) } diff --git a/clients/tests/rust/src/tb03_simple_atomic_transfer.rs b/clients/tests/rust/src/tb03_simple_atomic_transfer.rs index 81a18a56..f63ccef5 100644 --- a/clients/tests/rust/src/tb03_simple_atomic_transfer.rs +++ b/clients/tests/rust/src/tb03_simple_atomic_transfer.rs @@ -131,7 +131,7 @@ pub async fn execute() -> Result<()> { tb03(&client_config, &wallet1, &wallet2, &wallet3, &wallet4).await?; - println!("TB03- Simple Atomic Transfer Test completed successfully"); + println!("TB03 - Simple Atomic Transfer Test completed successfully"); Ok(()) } \ No newline at end of file diff --git a/clients/tests/rust/src/tb04_simple_lightning_latch.rs b/clients/tests/rust/src/tb04_simple_lightning_latch.rs new file mode 100644 index 00000000..f141efa3 --- /dev/null +++ b/clients/tests/rust/src/tb04_simple_lightning_latch.rs @@ -0,0 +1,97 @@ +use std::{env, process::Command, thread, time::Duration}; +use anyhow::{Result, Ok}; +use mercuryrustlib::{client_config::ClientConfig, CoinStatus, Wallet}; + +use crate::{bitcoin_core, electrs}; + +use sha2::{Sha256, Digest}; + +pub async fn tb04(client_config: &ClientConfig, wallet1: &Wallet, wallet2: &Wallet) -> Result<()> { + + let amount = 1000; + + // Create first deposit address + + let token_id = mercuryrustlib::deposit::get_token(client_config).await?; + + let deposit_address = mercuryrustlib::deposit::get_deposit_bitcoin_address(&client_config, &wallet1.name, &token_id, amount).await?; + + let _ = bitcoin_core::sendtoaddress(amount, &deposit_address)?; + + let core_wallet_address = bitcoin_core::getnewaddress()?; + let remaining_blocks = client_config.confirmation_target; + let _ = bitcoin_core::generatetoaddress(remaining_blocks, &core_wallet_address)?; + + // It appears that Electrs takes a few seconds to index the transaction + let mut is_tx_indexed = false; + + while !is_tx_indexed { + is_tx_indexed = electrs::check_address(client_config, &deposit_address, amount).await?; + thread::sleep(Duration::from_secs(1)); + } + + mercuryrustlib::coin_status::update_coins(&client_config, &wallet1.name).await?; + let wallet1: mercuryrustlib::Wallet = mercuryrustlib::sqlite_manager::get_wallet(&client_config.pool, &wallet1.name).await?; + let new_coin = wallet1.coins.iter().find(|&coin| coin.aggregated_address == Some(deposit_address.clone()) && coin.status == CoinStatus::CONFIRMED).unwrap(); + let statechain_id = new_coin.statechain_id.as_ref().unwrap(); + + let response = mercuryrustlib::lightning_latch::create_pre_image(&client_config, &wallet1.name, statechain_id).await?; + + let batch_id = response.batch_id; + let hash = response.hash; + + let wallet2_transfer_adress = mercuryrustlib::transfer_receiver::new_transfer_address(&client_config, &wallet2.name).await?; + + mercuryrustlib::transfer_sender::execute(&client_config, &wallet2_transfer_adress, &wallet1.name, statechain_id, Some(batch_id.clone())).await?; + + let transfer_receive_result = mercuryrustlib::transfer_receiver::execute(&client_config, &wallet2.name).await?; + + assert!(transfer_receive_result.is_there_batch_locked); + assert!(transfer_receive_result.received_statechain_ids.is_empty()); + + mercuryrustlib::lightning_latch::confirm_pending_invoice(&client_config, &wallet1.name, &statechain_id).await?; + + let transfer_receive_result = mercuryrustlib::transfer_receiver::execute(&client_config, &wallet2.name).await?; + + assert!(!transfer_receive_result.is_there_batch_locked); + assert!(!transfer_receive_result.received_statechain_ids.is_empty()); + + let pre_image = mercuryrustlib::lightning_latch::retrieve_pre_image(&client_config, &wallet1.name, &statechain_id, &batch_id).await?; + + let mut hasher = Sha256::new(); + hasher.update(pre_image.as_bytes()); + let result = hasher.finalize(); + + let sha256_pre_image = hex::encode(result); + + assert!(sha256_pre_image == hash); + + Ok(()) +} + +pub async fn execute() -> Result<()> { + + let _ = Command::new("rm").arg("wallet.db").arg("wallet.db-shm").arg("wallet.db-wal").output().expect("failed to execute process"); + + env::set_var("ML_NETWORK", "regtest"); + + let client_config = mercuryrustlib::client_config::load().await; + + let wallet1 = mercuryrustlib::wallet::create_wallet( + "wallet1", + &client_config).await?; + + mercuryrustlib::sqlite_manager::insert_wallet(&client_config.pool, &wallet1).await?; + + let wallet2 = mercuryrustlib::wallet::create_wallet( + "wallet2", + &client_config).await?; + + mercuryrustlib::sqlite_manager::insert_wallet(&client_config.pool, &wallet2).await?; + + tb04(&client_config, &wallet1, &wallet2).await?; + + println!("TB04 - Simple Lightning Latch completed successfully"); + + Ok(()) +} diff --git a/server/Cargo.toml b/server/Cargo.toml index 2e341dd6..e3814d91 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -21,3 +21,4 @@ secp256k1-zkp = { git = "https://github.com/ssantos21/rust-secp256k1-zkp.git", b # secp256k1-zkp = { path = "../ss-rust-secp256k1-zkp", features = [ "rand-std", "bitcoin_hashes", "std" ] } mercurylib = { path = "../lib" } chrono = "0.4.31" +sha2 = "0.10.8" diff --git a/server/src/endpoints/lightning_latch.rs b/server/src/endpoints/lightning_latch.rs index eb72c20c..652c66de 100644 --- a/server/src/endpoints/lightning_latch.rs +++ b/server/src/endpoints/lightning_latch.rs @@ -1,6 +1,5 @@ use std::str::FromStr; -use bitcoin::hashes::Hash; use chrono::Duration; use hex::encode; use mercurylib::transfer::sender::{PaymentHashRequestPayload, PaymentHashResponsePayload, TransferPreimageRequestPayload, TransferPreimageResponsePayload}; @@ -9,6 +8,8 @@ use rocket::{State, serde::json::Json, response::status, http::Status}; use secp256k1_zkp::PublicKey; use serde_json::{json, Value}; +use sha2::{Sha256, Digest}; + use crate::server::StateChainEntity; #[post("/transfer/paymenthash", format = "json", data = "")] @@ -30,7 +31,7 @@ pub async fn paymenthash(statechain_entity: &State, payment_ha let sender_auth_key = super::utils::get_auth_key_by_statechain_id(&statechain_entity.pool, &statechain_id).await.unwrap(); let buffer = rand::thread_rng().gen::<[u8; 32]>(); - let pre_image = encode(&buffer.clone()); + let pre_image = encode(buffer.clone()); let now = chrono::Utc::now(); let expiry_time = Duration::seconds(90000); // 25h @@ -38,9 +39,11 @@ pub async fn paymenthash(statechain_entity: &State, payment_ha crate::database::lightning_latch::insert_paymenthash(&statechain_entity.pool, &statechain_id, &sender_auth_key, &batch_id, &pre_image, &expires_at).await; - let result_hash = bitcoin::hashes::sha256::Hash::hash(&buffer); - let hash_bytes = result_hash.as_byte_array(); - let payment_hash = encode(hash_bytes); + let mut hasher = Sha256::new(); + hasher.update(pre_image.as_bytes()); + let result = hasher.finalize(); + + let payment_hash = hex::encode(result); let payment_hash_response_payload = PaymentHashResponsePayload { hash: payment_hash,