diff --git a/xmr-btc/src/alice.rs b/xmr-btc/src/alice.rs index 860027fd..e94062f1 100644 --- a/xmr-btc/src/alice.rs +++ b/xmr-btc/src/alice.rs @@ -3,7 +3,7 @@ use crate::{ bitcoin::{BroadcastSignedTransaction, WatchForRawTransaction}, bob, monero, monero::{CreateWalletForOutput, Transfer}, - serde::{bitcoin_amount, cross_curve_dleq_scalar, ecdsa_fun_signature}, + serde::bitcoin_amount, transport::{ReceiveMessage, SendMessage}, }; use anyhow::{anyhow, Result}; @@ -82,7 +82,7 @@ pub async fn next_state< } #[allow(clippy::large_enum_variant)] -#[derive(Debug)] +#[derive(Debug, Deserialize, Serialize)] pub enum State { State0(State0), State1(State1), @@ -134,7 +134,7 @@ impl State { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct State0 { a: bitcoin::SecretKey, - #[serde(with = "cross_curve_dleq_scalar")] + //#[serde(with = "cross_curve_dleq_scalar")] s_a: cross_curve_dleq::Scalar, v_a: monero::PrivateViewKey, #[serde(with = "bitcoin_amount")] @@ -223,7 +223,6 @@ impl State0 { pub struct State1 { a: bitcoin::SecretKey, B: bitcoin::PublicKey, - #[serde(with = "cross_curve_dleq_scalar")] s_a: cross_curve_dleq::Scalar, S_b_monero: monero::PublicKey, S_b_bitcoin: bitcoin::PublicKey, @@ -263,7 +262,6 @@ impl State1 { pub struct State2 { a: bitcoin::SecretKey, B: bitcoin::PublicKey, - #[serde(with = "cross_curve_dleq_scalar")] s_a: cross_curve_dleq::Scalar, S_b_monero: monero::PublicKey, S_b_bitcoin: bitcoin::PublicKey, @@ -340,13 +338,12 @@ impl State2 { pub struct State3 { pub a: bitcoin::SecretKey, pub B: bitcoin::PublicKey, - #[serde(with = "cross_curve_dleq_scalar")] pub s_a: cross_curve_dleq::Scalar, pub S_b_monero: monero::PublicKey, pub S_b_bitcoin: bitcoin::PublicKey, pub v: monero::PrivateViewKey, #[serde(with = "bitcoin_amount")] - btc: bitcoin::Amount, + pub btc: bitcoin::Amount, pub xmr: monero::Amount, pub refund_timelock: u32, pub punish_timelock: u32, @@ -354,9 +351,7 @@ pub struct State3 { pub redeem_address: bitcoin::Address, pub punish_address: bitcoin::Address, pub tx_lock: bitcoin::TxLock, - #[serde(with = "ecdsa_fun_signature")] pub tx_punish_sig_bob: bitcoin::Signature, - #[serde(with = "ecdsa_fun_signature")] pub tx_cancel_sig_bob: bitcoin::Signature, } @@ -397,7 +392,6 @@ impl State3 { pub struct State4 { a: bitcoin::SecretKey, B: bitcoin::PublicKey, - #[serde(with = "cross_curve_dleq_scalar")] s_a: cross_curve_dleq::Scalar, S_b_monero: monero::PublicKey, S_b_bitcoin: bitcoin::PublicKey, @@ -411,9 +405,7 @@ pub struct State4 { redeem_address: bitcoin::Address, punish_address: bitcoin::Address, tx_lock: bitcoin::TxLock, - #[serde(with = "ecdsa_fun_signature")] tx_punish_sig_bob: bitcoin::Signature, - #[serde(with = "ecdsa_fun_signature")] tx_cancel_sig_bob: bitcoin::Signature, } @@ -504,7 +496,6 @@ impl State4 { pub struct State5 { a: bitcoin::SecretKey, B: bitcoin::PublicKey, - #[serde(with = "cross_curve_dleq_scalar")] s_a: cross_curve_dleq::Scalar, S_b_monero: monero::PublicKey, S_b_bitcoin: bitcoin::PublicKey, @@ -519,9 +510,9 @@ pub struct State5 { punish_address: bitcoin::Address, tx_lock: bitcoin::TxLock, tx_lock_proof: monero::TransferProof, - #[serde(with = "ecdsa_fun_signature")] + tx_punish_sig_bob: bitcoin::Signature, - #[serde(with = "ecdsa_fun_signature")] + tx_cancel_sig_bob: bitcoin::Signature, lock_xmr_fee: monero::Amount, } @@ -599,7 +590,6 @@ impl State5 { pub struct State6 { a: bitcoin::SecretKey, B: bitcoin::PublicKey, - #[serde(with = "cross_curve_dleq_scalar")] s_a: cross_curve_dleq::Scalar, S_b_monero: monero::PublicKey, S_b_bitcoin: bitcoin::PublicKey, @@ -613,7 +603,7 @@ pub struct State6 { redeem_address: bitcoin::Address, punish_address: bitcoin::Address, tx_lock: bitcoin::TxLock, - #[serde(with = "ecdsa_fun_signature")] + tx_punish_sig_bob: bitcoin::Signature, tx_redeem_encsig: EncryptedSignature, lock_xmr_fee: monero::Amount, diff --git a/xmr-btc/src/bob.rs b/xmr-btc/src/bob.rs index 1dfb8b81..d2df8558 100644 --- a/xmr-btc/src/bob.rs +++ b/xmr-btc/src/bob.rs @@ -6,7 +6,7 @@ use crate::{ }, monero, monero::{CreateWalletForOutput, WatchForTransfer}, - serde::{bitcoin_amount, cross_curve_dleq_scalar, monero_private_key}, + serde::{bitcoin_amount, monero_private_key}, transport::{ReceiveMessage, SendMessage}, }; use anyhow::{anyhow, Result}; @@ -82,7 +82,7 @@ pub async fn next_state< } } -#[derive(Debug)] +#[derive(Debug, Deserialize, Serialize)] pub enum State { State0(State0), State1(State1), @@ -109,7 +109,6 @@ impl_from_child_enum!(State5, State); #[derive(Debug, Deserialize, Serialize)] pub struct State0 { b: bitcoin::SecretKey, - #[serde(with = "cross_curve_dleq_scalar")] s_b: cross_curve_dleq::Scalar, v_b: monero::PrivateViewKey, #[serde(with = "bitcoin_amount")] @@ -200,7 +199,6 @@ impl State0 { pub struct State1 { A: bitcoin::PublicKey, b: bitcoin::SecretKey, - #[serde(with = "cross_curve_dleq_scalar")] s_b: cross_curve_dleq::Scalar, S_a_monero: monero::PublicKey, S_a_bitcoin: bitcoin::PublicKey, @@ -265,7 +263,6 @@ impl State1 { pub struct State2 { pub A: bitcoin::PublicKey, pub b: bitcoin::SecretKey, - #[serde(with = "cross_curve_dleq_scalar")] pub s_b: cross_curve_dleq::Scalar, pub S_a_monero: monero::PublicKey, pub S_a_bitcoin: bitcoin::PublicKey, @@ -338,7 +335,6 @@ impl State2 { pub struct State3 { A: bitcoin::PublicKey, b: bitcoin::SecretKey, - #[serde(with = "cross_curve_dleq_scalar")] s_b: cross_curve_dleq::Scalar, S_a_monero: monero::PublicKey, S_a_bitcoin: bitcoin::PublicKey, @@ -451,7 +447,6 @@ impl State3 { pub struct State4 { A: bitcoin::PublicKey, b: bitcoin::SecretKey, - #[serde(with = "cross_curve_dleq_scalar")] s_b: cross_curve_dleq::Scalar, S_a_monero: monero::PublicKey, S_a_bitcoin: bitcoin::PublicKey, @@ -522,7 +517,6 @@ pub struct State5 { b: bitcoin::SecretKey, #[serde(with = "monero_private_key")] s_a: monero::PrivateKey, - #[serde(with = "cross_curve_dleq_scalar")] s_b: cross_curve_dleq::Scalar, S_a_monero: monero::PublicKey, S_a_bitcoin: bitcoin::PublicKey, diff --git a/xmr-btc/src/serde.rs b/xmr-btc/src/serde.rs index f8fa4ab9..a9b5a595 100644 --- a/xmr-btc/src/serde.rs +++ b/xmr-btc/src/serde.rs @@ -1,93 +1,3 @@ -pub mod ecdsa_fun_signature { - use serde::{de, de::Visitor, Deserializer, Serializer}; - use std::{convert::TryFrom, fmt}; - - struct Bytes64Visitor; - - impl<'de> Visitor<'de> for Bytes64Visitor { - type Value = ecdsa_fun::Signature; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "a string containing 64 bytes") - } - - fn visit_bytes(self, s: &[u8]) -> Result - where - E: de::Error, - { - if let Ok(value) = <[u8; 64]>::try_from(s) { - let sig = ecdsa_fun::Signature::from_bytes(value) - .expect("bytes represent an integer greater than or equal to the curve order"); - Ok(sig) - } else { - Err(de::Error::invalid_length(s.len(), &self)) - } - } - } - - pub fn serialize(x: &ecdsa_fun::Signature, s: S) -> Result - where - S: Serializer, - { - s.serialize_bytes(&x.to_bytes()) - } - - pub fn deserialize<'de, D>( - deserializer: D, - ) -> Result>::Error> - where - D: Deserializer<'de>, - { - let sig = deserializer.deserialize_bytes(Bytes64Visitor)?; - Ok(sig) - } -} - -pub mod cross_curve_dleq_scalar { - use serde::{de, de::Visitor, Deserializer, Serializer}; - use std::{convert::TryFrom, fmt}; - - struct Bytes32Visitor; - - impl<'de> Visitor<'de> for Bytes32Visitor { - type Value = cross_curve_dleq::Scalar; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "a string containing 32 bytes") - } - - fn visit_bytes(self, s: &[u8]) -> Result - where - E: de::Error, - { - if let Ok(value) = <[u8; 32]>::try_from(s) { - Ok(cross_curve_dleq::Scalar::from(value)) - } else { - Err(de::Error::invalid_length(s.len(), &self)) - } - } - } - - pub fn serialize(x: &cross_curve_dleq::Scalar, s: S) -> Result - where - S: Serializer, - { - // Serialise as ed25519 because the inner bytes are private - // TODO: Open PR in cross_curve_dleq to allow accessing the inner bytes - s.serialize_bytes(&x.into_ed25519().to_bytes()) - } - - pub fn deserialize<'de, D>( - deserializer: D, - ) -> Result>::Error> - where - D: Deserializer<'de>, - { - let dleq = deserializer.deserialize_bytes(Bytes32Visitor)?; - Ok(dleq) - } -} - pub mod monero_private_key { use serde::{de, de::Visitor, Deserializer, Serializer}; use std::fmt; @@ -178,42 +88,16 @@ pub mod monero_amount { #[cfg(test)] mod tests { use super::*; - use ::bitcoin::SigHash; use curve25519_dalek::scalar::Scalar; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; - #[derive(Debug, Serialize, Deserialize, PartialEq)] - pub struct CrossCurveDleqScalar( - #[serde(with = "cross_curve_dleq_scalar")] cross_curve_dleq::Scalar, - ); - - #[derive(Debug, Serialize, Deserialize, PartialEq)] - pub struct ECDSAFunSignature(#[serde(with = "ecdsa_fun_signature")] ecdsa_fun::Signature); - #[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct MoneroPrivateKey(#[serde(with = "monero_private_key")] crate::monero::PrivateKey); #[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct BitcoinAmount(#[serde(with = "bitcoin_amount")] ::bitcoin::Amount); - #[test] - fn serde_cross_curv_dleq_scalar() { - let scalar = CrossCurveDleqScalar(cross_curve_dleq::Scalar::random(&mut OsRng)); - let encoded = serde_cbor::to_vec(&scalar).unwrap(); - let decoded: CrossCurveDleqScalar = serde_cbor::from_slice(&encoded).unwrap(); - assert_eq!(scalar, decoded); - } - - #[test] - fn serde_ecdsa_fun_sig() { - let secret_key = crate::bitcoin::SecretKey::new_random(&mut OsRng); - let sig = ECDSAFunSignature(secret_key.sign(SigHash::default())); - let encoded = serde_cbor::to_vec(&sig).unwrap(); - let decoded: ECDSAFunSignature = serde_cbor::from_slice(&encoded).unwrap(); - assert_eq!(sig, decoded); - } - #[test] fn serde_monero_private_key() { let key = MoneroPrivateKey(monero::PrivateKey::from_scalar(Scalar::random(&mut OsRng))); diff --git a/xmr-btc/tests/e2e.rs b/xmr-btc/tests/e2e.rs index 148dcbe4..98378ee0 100644 --- a/xmr-btc/tests/e2e.rs +++ b/xmr-btc/tests/e2e.rs @@ -11,14 +11,14 @@ mod tests { harness::{ init_bitcoind, init_test, node::{run_alice_until, run_bob_until}, - ALICE_TEST_DB_FOLDER, BOB_TEST_DB_FOLDER, }, }; use futures::future; use monero_harness::Monero; use rand::rngs::OsRng; - use std::{convert::TryInto, path::Path}; + use crate::harness::storage::Database; + use std::convert::TryInto; use testcontainers::clients::Cli; use tracing_subscriber::util::SubscriberInitExt; use xmr_btc::{ @@ -251,8 +251,13 @@ mod tests { let cli = Cli::default(); let (monero, _container) = Monero::new(&cli); let bitcoind = init_bitcoind(&cli).await; - let alice_db = harness::storage::Database::open(Path::new(ALICE_TEST_DB_FOLDER)).unwrap(); - let bob_db = harness::storage::Database::open(Path::new(BOB_TEST_DB_FOLDER)).unwrap(); + + let alice_db_dir = tempfile::tempdir().unwrap(); + let alice_db: Database = + harness::storage::Database::open(alice_db_dir.path()).unwrap(); + let bob_db_dir = tempfile::tempdir().unwrap(); + let bob_db: Database = + harness::storage::Database::open(bob_db_dir.path()).unwrap(); let ( alice_state0, @@ -281,29 +286,26 @@ mod tests { .await .unwrap(); - let alice_state5: alice::State5 = alice_state.try_into().unwrap(); - let bob_state3: bob::State3 = bob_state.try_into().unwrap(); - // save state to db - alice_db.insert_latest_state(&alice_state5).await.unwrap(); - bob_db.insert_latest_state(&bob_state3).await.unwrap(); + alice_db.insert_latest_state(&alice_state).await.unwrap(); + bob_db.insert_latest_state(&bob_state).await.unwrap(); }; let (alice_state6, bob_state5) = { // recover state from db - let alice_state5: alice::State5 = alice_db.get_latest_state().unwrap(); - let bob_state3: bob::State3 = bob_db.get_latest_state().unwrap(); + let alice_state = alice_db.get_latest_state().unwrap(); + let bob_state = bob_db.get_latest_state().unwrap(); let (alice_state, bob_state) = future::try_join( run_alice_until( &mut alice_node, - alice_state5.into(), + alice_state, harness::alice::is_state6, &mut OsRng, ), run_bob_until( &mut bob_node, - bob_state3.into(), + bob_state, harness::bob::is_state5, &mut OsRng, ), diff --git a/xmr-btc/tests/harness/storage.rs b/xmr-btc/tests/harness/storage.rs index 1f2947cb..5fbcc40f 100644 --- a/xmr-btc/tests/harness/storage.rs +++ b/xmr-btc/tests/harness/storage.rs @@ -2,26 +2,32 @@ use anyhow::{anyhow, Context, Result}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::path::Path; -pub struct Database { +pub struct Database +where + T: Serialize + DeserializeOwned, +{ db: sled::Db, + _marker: std::marker::PhantomData, } -impl Database { +impl Database +where + T: Serialize + DeserializeOwned, +{ + // TODO: serialize using lazy/one-time initlisation const LAST_STATE_KEY: &'static str = "latest_state"; pub fn open(path: &Path) -> Result { - let path = path - .to_str() - .ok_or_else(|| anyhow!("The path is not utf-8 valid: {:?}", path))?; - let db = sled::open(path).with_context(|| format!("Could not open the DB at {}", path))?; + let db = + sled::open(path).with_context(|| format!("Could not open the DB at {:?}", path))?; - Ok(Database { db }) + Ok(Database { + db, + _marker: Default::default(), + }) } - pub async fn insert_latest_state(&self, state: &T) -> Result<()> - where - T: Serialize + DeserializeOwned, - { + pub async fn insert_latest_state(&self, state: &T) -> Result<()> { let key = serialize(&Self::LAST_STATE_KEY)?; let new_value = serialize(&state).context("Could not serialize new state value")?; @@ -30,8 +36,9 @@ impl Database { self.db .compare_and_swap(key, old_value, Some(new_value)) .context("Could not write in the DB")? - .context("Stored swap somehow changed, aborting saving")?; // let _ = + .context("Stored swap somehow changed, aborting saving")?; + // TODO: see if this can be done through sled config self.db .flush_async() .await @@ -39,10 +46,7 @@ impl Database { .context("Could not flush db") } - pub fn get_latest_state(&self) -> anyhow::Result - where - T: DeserializeOwned, - { + pub fn get_latest_state(&self) -> anyhow::Result { let key = serialize(&Self::LAST_STATE_KEY)?; let encoded = self @@ -77,15 +81,12 @@ mod tests { use curve25519_dalek::scalar::Scalar; use ecdsa_fun::fun::rand_core::OsRng; use std::str::FromStr; - use xmr_btc::serde::{ - bitcoin_amount, cross_curve_dleq_scalar, ecdsa_fun_signature, monero_private_key, - }; + use xmr_btc::serde::{bitcoin_amount, monero_private_key}; #[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct TestState { A: xmr_btc::bitcoin::PublicKey, a: xmr_btc::bitcoin::SecretKey, - #[serde(with = "cross_curve_dleq_scalar")] s_a: ::cross_curve_dleq::Scalar, #[serde(with = "monero_private_key")] s_b: monero::PrivateKey, @@ -98,13 +99,13 @@ mod tests { refund_timelock: u32, refund_address: ::bitcoin::Address, transaction: ::bitcoin::Transaction, - #[serde(with = "ecdsa_fun_signature")] tx_punish_sig: xmr_btc::bitcoin::Signature, } #[tokio::test] async fn recover_state_from_db() { - let db = Database::open(Path::new("../target/test_recover.db")).unwrap(); + let db_dir = tempfile::tempdir().unwrap(); + let db = Database::open(db_dir.path()).unwrap(); let a = xmr_btc::bitcoin::SecretKey::new_random(&mut OsRng); let s_a = cross_curve_dleq::Scalar::random(&mut OsRng);