From 9341795eb57d053bbc018557cca88ee5b72d7c21 Mon Sep 17 00:00:00 2001 From: bennyhodl Date: Mon, 7 Oct 2024 20:53:24 -0400 Subject: [PATCH 1/6] feat: use dlc-macros for async dlc-manager --- Cargo.toml | 1 + dlc-macros/Cargo.toml | 21 ++++ dlc-macros/src/lib.rs | 190 ++++++++++++++++++++++++++++++++ dlc-macros/tests/maybe_async.rs | 27 +++++ dlc-macros/tests/sync.rs | 20 ++++ dlc-manager/Cargo.toml | 5 +- dlc-manager/src/lib.rs | 6 + dlc-manager/src/manager.rs | 107 ++++++++++-------- mocks/Cargo.toml | 1 + 9 files changed, 332 insertions(+), 46 deletions(-) create mode 100644 dlc-macros/Cargo.toml create mode 100644 dlc-macros/src/lib.rs create mode 100644 dlc-macros/tests/maybe_async.rs create mode 100644 dlc-macros/tests/sync.rs diff --git a/Cargo.toml b/Cargo.toml index 4843100a..1476941c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "dlc-messages", "dlc-trie", "dlc-manager", + "dlc-macros", "mocks", "sample", "simple-wallet", diff --git a/dlc-macros/Cargo.toml b/dlc-macros/Cargo.toml new file mode 100644 index 00000000..03132d21 --- /dev/null +++ b/dlc-macros/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "dlc-macros" +authors = ["benny b "] +version = "0.1.0" +edition = "2018" +description = "Procedural macros for writing optionally asynchronous code for traits and functions." +homepage = "https://github.com/p2pderivatives/rust-dlc" +license-file = "../LICENSE" +repository = "https://github.com/p2pderivatives/rust-dlc/tree/master/dlc-macros" + +[dependencies] +proc-macro2 = "1.0.87" +quote = "1.0.37" +syn = { version = "2.0.79", features = ["full", "extra-traits"] } +tokio = { version = "1.40.0", features = ["macros", "test-util"] } + +[lib] +proc-macro = true + +[dev-dependencies] +trybuild = "1.0.99" diff --git a/dlc-macros/src/lib.rs b/dlc-macros/src/lib.rs new file mode 100644 index 00000000..e83b3220 --- /dev/null +++ b/dlc-macros/src/lib.rs @@ -0,0 +1,190 @@ +//! Procedural macros for writing optionally asynchronous code for traits and functions. +//! Inspires by [`bdk-macros`](https://github.com/bitcoindevkit/bdk/blob/v0.29.0/macros/src/lib.rs) + +#![crate_name = "dlc_macros"] +// Coding conventions +#![forbid(unsafe_code)] +#![deny(non_upper_case_globals)] +#![deny(non_camel_case_types)] +#![deny(non_snake_case)] +#![deny(unused_mut)] +#![deny(dead_code)] +#![deny(unused_imports)] +#![deny(missing_docs)] + +use proc_macro::TokenStream; +use quote::quote; +use syn::spanned::Spanned; +use syn::{ + parse_macro_input, Attribute, Expr, ImplItem, Item, ItemFn, ItemImpl, ItemTrait, TraitItem, +}; + +// Check if the function attributes contains #[maybe_async]. +// For conditional compilation of member functions. +fn is_maybe_async_attr(attr: &Attribute) -> bool { + // Check if the attribute path is exactly "maybe_async" + if attr.path().is_ident("maybe_async") { + return true; + } + + // Check if the attribute path is of the form "module::maybe_async" + if let Some(last_segment) = attr.path().segments.last() { + return last_segment.ident == "maybe_async"; + } + false +} + +// Add async to a standalone function. +fn add_async_to_fn(mut func: ItemFn) -> TokenStream { + // For standalone functions, we'll always make them potentially async + let sync_version = func.clone(); + func.sig.asyncness = Some(syn::Token![async](func.sig.span())); + + quote! { + #[cfg(not(feature = "async"))] + #sync_version + + #[cfg(feature = "async")] + #func + } + .into() +} + +// Adds the `async_trait` macro to the trait and appends async to all of +// the member functions marked `#[maybe_async]`. +fn add_async_to_trait(mut trait_item: ItemTrait) -> TokenStream { + // Check if the trait itself has the `#[maybe_async]` attribute + let is_trait_async = trait_item.attrs.iter().any(is_maybe_async_attr); + trait_item.attrs.retain(|attr| !is_maybe_async_attr(attr)); // Remove the attribute from the trait + + let mut async_trait_item = trait_item.clone(); + + for item in &mut async_trait_item.items { + if let TraitItem::Fn(method) = item { + if is_trait_async || method.attrs.iter().any(is_maybe_async_attr) { + method.sig.asyncness = Some(syn::Token![async](method.sig.span())); + method.attrs.retain(is_maybe_async_attr); + } + } + } + + quote! { + #[cfg(not(feature = "async"))] + #trait_item + + #[cfg(feature = "async")] + #[async_trait::async_trait] + #async_trait_item + } + .into() +} + +// Adds async to a member of a struct implementation method. +fn add_async_to_impl(impl_item: ItemImpl) -> TokenStream { + let mut async_impl_item = impl_item.clone(); + + for item in &mut async_impl_item.items { + if let ImplItem::Fn(method) = item { + if method.attrs.iter().any(is_maybe_async_attr) { + method.sig.asyncness = Some(syn::Token![async](method.sig.span())); + method.attrs.retain(|attr| !is_maybe_async_attr(attr)); + } + } + } + + quote! { + #[cfg(not(feature = "async"))] + #impl_item + + #[cfg(feature = "async")] + #[async_trait::async_trait] + #async_impl_item + } + .into() +} + +/// Makes a method or every method of a trait `async`, if the `async` feature is enabled. +/// +/// Requires the `async-trait` crate as a dependency whenever this attribute is used on a trait +/// definition or trait implementation. +#[proc_macro_attribute] +pub fn maybe_async(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as Item); + + match input { + Item::Fn(func) => add_async_to_fn(func), + Item::Trait(trait_item) => add_async_to_trait(trait_item), + Item::Impl(impl_item) => add_async_to_impl(impl_item), + Item::Verbatim(verbatim) => { + // This case handles unexpected verbatim content, like doc comments + quote! { + #verbatim + } + .into() + } + other => { + let item_type = format!("{:?}", other); + let error_msg = format!( + "#[maybe_async] can only be used on functions, traits, or impl blocks, not on: {}", + item_type + ); + quote! { + compile_error!(#error_msg); + } + .into() + } + } +} + +/// Awaits, if the `async` feature is enabled. +#[proc_macro] +pub fn maybe_await(input: TokenStream) -> TokenStream { + let expr = parse_macro_input!(input as Expr); + let quoted = quote! { + { + #[cfg(not(feature = "async"))] + { + #expr + } + + #[cfg(feature = "async")] + { + #expr.await + } + } + }; + + quoted.into() +} + +/// Awaits, if the `async` feature is enabled, uses `tokio::Runtime::block_on()` otherwise +/// +/// Requires the `tokio` crate as a dependecy with `rt-core` or `rt-threaded` to build. +#[proc_macro] +pub fn await_or_block(expr: TokenStream) -> TokenStream { + let expr = parse_macro_input!(expr as Expr); + let quoted = quote! { + { + #[cfg(not(feature = "async"))] + { + tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(#expr) + } + + #[cfg(feature = "async")] + { + #expr.await + } + } + }; + + quoted.into() +} + +#[cfg(test)] +mod tests { + #[test] + fn test_async_trait() { + let t = trybuild::TestCases::new(); + t.pass("tests/sync.rs"); + } +} diff --git a/dlc-macros/tests/maybe_async.rs b/dlc-macros/tests/maybe_async.rs new file mode 100644 index 00000000..5d374539 --- /dev/null +++ b/dlc-macros/tests/maybe_async.rs @@ -0,0 +1,27 @@ +use dlc_macros::*; + +#[maybe_async] +trait TestTrait { + fn test_method(&self) -> Result<(), std::io::Error>; +} + +struct TestStruct; + +#[maybe_async] +impl TestTrait for TestStruct { + fn test_method(&self) -> Result<(), std::io::Error> { + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sync_implementation() { + let test_struct = TestStruct; + let test = maybe_await!(test_struct.test_method()); + assert!(test.is_ok()); + } +} diff --git a/dlc-macros/tests/sync.rs b/dlc-macros/tests/sync.rs new file mode 100644 index 00000000..6a7c46a5 --- /dev/null +++ b/dlc-macros/tests/sync.rs @@ -0,0 +1,20 @@ +use dlc_macros::maybe_async; + +/// Documentation +#[maybe_async] +pub trait Example { + /// Documentation + #[maybe_async] + fn example_fn(&self); +} + +struct Test; + +impl Example for Test { + fn example_fn(&self) {} +} + +fn main() { + let test = Test; + test.example_fn(); +} diff --git a/dlc-manager/Cargo.toml b/dlc-manager/Cargo.toml index 15bd6b7c..48cb0101 100644 --- a/dlc-manager/Cargo.toml +++ b/dlc-manager/Cargo.toml @@ -14,19 +14,22 @@ std = ["dlc/std", "dlc-messages/std", "dlc-trie/std", "bitcoin/std", "lightning/ fuzztarget = ["rand_chacha"] parallel = ["dlc-trie/parallel"] use-serde = ["serde", "dlc/use-serde", "dlc-messages/use-serde", "dlc-trie/use-serde"] +async = ["dep:async-trait"] [dependencies] -async-trait = "0.1.50" +async-trait = { version = "0.1.50", optional = true } bitcoin = { version = "0.32.2", default-features = false } dlc = { version = "0.7.0", default-features = false, path = "../dlc" } dlc-messages = { version = "0.7.0", default-features = false, path = "../dlc-messages" } dlc-trie = { version = "0.7.0", default-features = false, path = "../dlc-trie" } +dlc-macros = { version = "0.1.0", path = "../dlc-macros" } hex = { package = "hex-conservative", version = "0.1" } lightning = { version = "0.0.125", default-features = false, features = ["grind_signatures"] } log = "0.4.14" rand_chacha = {version = "0.3.1", optional = true} secp256k1-zkp = {version = "0.11.0"} serde = {version = "1.0", optional = true} +# bdk-macros = "0.6.0" [dev-dependencies] bitcoin-rpc-provider = {path = "../bitcoin-rpc-provider"} diff --git a/dlc-manager/src/lib.rs b/dlc-manager/src/lib.rs index b5250c00..674ba70a 100644 --- a/dlc-manager/src/lib.rs +++ b/dlc-manager/src/lib.rs @@ -12,6 +12,7 @@ #![deny(unused_imports)] #![deny(missing_docs)] +#[cfg(feature = "async")] extern crate async_trait; extern crate bitcoin; extern crate dlc; @@ -44,6 +45,7 @@ use channel::signed_channel::{SignedChannel, SignedChannelStateType}; use channel::Channel; use contract::PreClosedContract; use contract::{offered_contract::OfferedContract, signed_contract::SignedContract, Contract}; +use dlc_macros::maybe_async; use dlc_messages::oracle_msgs::{OracleAnnouncement, OracleAttestation}; use dlc_messages::ser_impls::{read_address, write_address}; use error::Error; @@ -225,13 +227,17 @@ pub trait Storage { fn get_chain_monitor(&self) -> Result, Error>; } +#[allow(missing_docs)] /// Oracle trait provides access to oracle information. +#[maybe_async] pub trait Oracle { /// Returns the public key of the oracle. fn get_public_key(&self) -> XOnlyPublicKey; + #[maybe_async] /// Returns the announcement for the event with the given id if found. fn get_announcement(&self, event_id: &str) -> Result; /// Returns the attestation for the event with the given id if found. + #[maybe_async] fn get_attestation(&self, event_id: &str) -> Result; } diff --git a/dlc-manager/src/manager.rs b/dlc-manager/src/manager.rs index 8662d15f..a100b07c 100644 --- a/dlc-manager/src/manager.rs +++ b/dlc-manager/src/manager.rs @@ -24,6 +24,7 @@ use bitcoin::consensus::encode::serialize_hex; use bitcoin::consensus::Decodable; use bitcoin::Address; use bitcoin::{OutPoint, Transaction}; +use dlc_macros::*; use dlc_messages::channel::{ AcceptChannel, CollaborativeCloseOffer, OfferChannel, Reject, RenewAccept, RenewConfirm, RenewFinalize, RenewOffer, RenewRevoke, SettleAccept, SettleConfirm, SettleFinalize, @@ -269,16 +270,14 @@ where /// and an OfferDlc message returned. /// /// This function will fetch the oracle announcements from the oracle. + #[maybe_async] pub fn send_offer( &self, contract_input: &ContractInput, counter_party: PublicKey, ) -> Result { - let oracle_announcements = contract_input - .contract_infos - .iter() - .map(|x| self.get_oracle_announcements(&x.oracles)) - .collect::, Error>>()?; + let oracle_announcements = + maybe_await!(self.get_oracle_announcements_from_infos(contract_input))?; self.send_offer_with_announcements(contract_input, counter_party, oracle_announcements) } @@ -375,13 +374,14 @@ where /// Function to call to check the state of the currently executing DLCs and /// update them if possible. + #[maybe_async] pub fn periodic_check(&self, check_channels: bool) -> Result<(), Error> { self.check_signed_contracts()?; - self.check_confirmed_contracts()?; + maybe_await!(self.check_confirmed_contracts())?; self.check_preclosed_contracts()?; if check_channels { - self.channel_checks()?; + maybe_await!(self.channel_checks())?; } Ok(()) @@ -470,6 +470,7 @@ where Ok(()) } + #[maybe_async] fn get_oracle_announcements( &self, oracle_inputs: &OracleInput, @@ -480,7 +481,8 @@ where .oracles .get(pubkey) .ok_or_else(|| Error::InvalidParameters("Unknown oracle public key".to_string()))?; - announcements.push(oracle.get_announcement(&oracle_inputs.event_id)?.clone()); + let announcement = maybe_await!(oracle.get_announcement(&oracle_inputs.event_id))?; + announcements.push(announcement); } Ok(announcements) @@ -547,13 +549,14 @@ where Ok(()) } + #[maybe_async] fn check_confirmed_contracts(&self) -> Result<(), Error> { for c in self.store.get_confirmed_contracts()? { // Confirmed contracts from channel are processed in channel specific methods. if c.channel_id.is_some() { continue; } - if let Err(e) = self.check_confirmed_contract(&c) { + if let Err(e) = maybe_await!(self.check_confirmed_contract(&c)) { error!( "Error checking confirmed contract {}: {}", c.accepted_contract.get_contract_id_string(), @@ -565,6 +568,7 @@ where Ok(()) } + #[maybe_async] fn get_closable_contract_info<'a>( &'a self, contract: &'a SignedContract, @@ -580,27 +584,26 @@ where }) .enumerate() .collect(); + if matured.len() >= contract_info.threshold { - let attestations: Vec<_> = matured - .iter() - .filter_map(|(i, announcement)| { - let oracle = self.oracles.get(&announcement.oracle_public_key)?; - let attestation = oracle - .get_attestation(&announcement.oracle_event.event_id) - .ok()?; - attestation - .validate(&self.secp, announcement) - .map_err(|_| { - log::error!( - "Oracle attestation is not valid. pubkey={} event_id={}", - announcement.oracle_public_key, - announcement.oracle_event.event_id - ) - }) + let mut attestations = Vec::new(); + for (i, announcement) in matured { + let oracle = self.oracles.get(&announcement.oracle_public_key)?; + let attestation = + maybe_await!(oracle.get_attestation(&announcement.oracle_event.event_id)) .ok()?; - Some((*i, attestation)) - }) - .collect(); + attestation + .validate(&self.secp, announcement) + .map_err(|_| { + log::error!( + "Oracle attestation is not valid. pubkey={} event_id={}", + announcement.oracle_public_key, + announcement.oracle_event.event_id + ) + }) + .ok()?; + attestations.push((i, attestation)); + } if attestations.len() >= contract_info.threshold { return Some((contract_info, adaptor_info, attestations)); } @@ -609,8 +612,9 @@ where None } + #[maybe_async] fn check_confirmed_contract(&self, contract: &SignedContract) -> Result<(), Error> { - let closable_contract_info = self.get_closable_contract_info(contract); + let closable_contract_info = maybe_await!(self.get_closable_contract_info(contract)); if let Some((contract_info, adaptor_info, attestations)) = closable_contract_info { let offer = &contract.accepted_contract.offered_contract; let signer = self.signer_provider.derive_contract_signer(offer.keys_id)?; @@ -895,6 +899,20 @@ where Ok(contract) } + + #[maybe_async] + fn get_oracle_announcements_from_infos( + &self, + contract_input: &ContractInput, + ) -> Result>, Error> { + let mut oracle_announcements = vec![]; + for contract_info in contract_input.contract_infos.clone() { + let announcement = maybe_await!(self.get_oracle_announcements(&contract_info.oracles))?; + oracle_announcements.push(announcement); + } + + Ok(oracle_announcements) + } } impl @@ -910,16 +928,14 @@ where { /// Create a new channel offer and return the [`dlc_messages::channel::OfferChannel`] /// message to be sent to the `counter_party`. + #[maybe_async] pub fn offer_channel( &self, contract_input: &ContractInput, counter_party: PublicKey, ) -> Result { - let oracle_announcements = contract_input - .contract_infos - .iter() - .map(|x| self.get_oracle_announcements(&x.oracles)) - .collect::, Error>>()?; + let oracle_announcements = + maybe_await!(self.get_oracle_announcements_from_infos(contract_input))?; let (offered_channel, offered_contract) = crate::channel_updater::offer_channel( &self.secp, @@ -1092,6 +1108,7 @@ where /// Returns a [`RenewOffer`] message as well as the [`PublicKey`] of the /// counter party's node to offer the establishment of a new contract in the /// channel. + #[maybe_async] pub fn renew_offer( &self, channel_id: &ChannelId, @@ -1101,11 +1118,8 @@ where let mut signed_channel = get_channel_in_state!(self, channel_id, Signed, None as Option)?; - let oracle_announcements = contract_input - .contract_infos - .iter() - .map(|x| self.get_oracle_announcements(&x.oracles)) - .collect::, Error>>()?; + let oracle_announcements = + maybe_await!(self.get_oracle_announcements_from_infos(contract_input))?; let (msg, offered_contract) = crate::channel_updater::renew_offer( &self.secp, @@ -1300,6 +1314,7 @@ where Ok(()) } + #[maybe_async] fn try_finalize_closing_established_channel( &self, signed_channel: SignedChannel, @@ -1325,11 +1340,12 @@ where let confirmed_contract = get_contract_in_state!(self, &contract_id, Confirmed, None as Option)?; - let (contract_info, adaptor_info, attestations) = self - .get_closable_contract_info(&confirmed_contract) - .ok_or_else(|| { - Error::InvalidState("Could not get information to close contract".to_string()) - })?; + let (contract_info, adaptor_info, attestations) = maybe_await!( + self.get_closable_contract_info(&confirmed_contract) + ) + .ok_or_else(|| { + Error::InvalidState("Could not get information to close contract".to_string()) + })?; let (signed_cet, closed_channel) = crate::channel_updater::finalize_unilateral_close_settled_channel( @@ -2087,13 +2103,14 @@ where Ok(()) } + #[maybe_async] fn channel_checks(&self) -> Result<(), Error> { let established_closing_channels = self .store .get_signed_channels(Some(SignedChannelStateType::Closing))?; for channel in established_closing_channels { - if let Err(e) = self.try_finalize_closing_established_channel(channel) { + if let Err(e) = maybe_await!(self.try_finalize_closing_established_channel(channel)) { error!("Error trying to close established channel: {}", e); } } diff --git a/mocks/Cargo.toml b/mocks/Cargo.toml index b51fd906..7d117e42 100644 --- a/mocks/Cargo.toml +++ b/mocks/Cargo.toml @@ -5,6 +5,7 @@ name = "mocks" version = "0.1.0" [dependencies] +bdk-macros = "0.6.0" bitcoin = "0.32.2" dlc = {path = "../dlc"} dlc-manager = {path = "../dlc-manager"} From 2c05955542f5fd97cdb10fa5b332979563581321 Mon Sep 17 00:00:00 2001 From: bennyhodl Date: Fri, 18 Oct 2024 18:00:27 -0400 Subject: [PATCH 2/6] async for p2p oracle and mock oracle --- mocks/Cargo.toml | 4 ++++ mocks/src/mock_oracle_provider.rs | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/mocks/Cargo.toml b/mocks/Cargo.toml index 7d117e42..f26b8e31 100644 --- a/mocks/Cargo.toml +++ b/mocks/Cargo.toml @@ -4,7 +4,11 @@ edition = "2018" name = "mocks" version = "0.1.0" +[features] +async = ["dep:async-trait", "dlc-manager/async"] + [dependencies] +async-trait = { version = "0.1.83", optional = true } bdk-macros = "0.6.0" bitcoin = "0.32.2" dlc = {path = "../dlc"} diff --git a/mocks/src/mock_oracle_provider.rs b/mocks/src/mock_oracle_provider.rs index 2bc03916..49b5f286 100644 --- a/mocks/src/mock_oracle_provider.rs +++ b/mocks/src/mock_oracle_provider.rs @@ -55,6 +55,7 @@ impl Default for MockOracle { } } +#[cfg(not(feature = "async"))] impl Oracle for MockOracle { fn get_public_key(&self) -> XOnlyPublicKey { XOnlyPublicKey::from_keypair(&self.key_pair).0 @@ -77,6 +78,30 @@ impl Oracle for MockOracle { } } +#[cfg(feature = "async")] +#[async_trait::async_trait] +impl Oracle for MockOracle { + fn get_public_key(&self) -> XOnlyPublicKey { + XOnlyPublicKey::from_keypair(&self.key_pair).0 + } + + async fn get_announcement(&self, event_id: &str) -> Result { + let res = self + .announcements + .get(event_id) + .ok_or_else(|| DaemonError::OracleError("Announcement not found".to_string()))?; + Ok(res.clone()) + } + + async fn get_attestation(&self, event_id: &str) -> Result { + let res = self + .attestations + .get(event_id) + .ok_or_else(|| DaemonError::OracleError("Attestation not found".to_string()))?; + Ok(res.clone()) + } +} + impl MockOracle { fn generate_nonces_for_event( &mut self, From 67971c7f50928edf051f97cc88074ad792de430e Mon Sep 17 00:00:00 2001 From: bennyhodl Date: Fri, 1 Nov 2024 13:17:41 -0400 Subject: [PATCH 3/6] Oracle implementations use async and sync --- mocks/src/mock_oracle_provider.rs | 20 ++++++----- p2pd-oracle-client/Cargo.toml | 5 +++ p2pd-oracle-client/src/lib.rs | 59 +++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/mocks/src/mock_oracle_provider.rs b/mocks/src/mock_oracle_provider.rs index 49b5f286..56fd98fc 100644 --- a/mocks/src/mock_oracle_provider.rs +++ b/mocks/src/mock_oracle_provider.rs @@ -86,18 +86,22 @@ impl Oracle for MockOracle { } async fn get_announcement(&self, event_id: &str) -> Result { - let res = self - .announcements - .get(event_id) - .ok_or_else(|| DaemonError::OracleError("Announcement not found".to_string()))?; + let res = std::future::ready( + self.announcements + .get(event_id) + .ok_or_else(|| DaemonError::OracleError("Announcement not found".to_string()))?, + ) + .await; Ok(res.clone()) } async fn get_attestation(&self, event_id: &str) -> Result { - let res = self - .attestations - .get(event_id) - .ok_or_else(|| DaemonError::OracleError("Attestation not found".to_string()))?; + let res = std::future::ready( + self.attestations + .get(event_id) + .ok_or_else(|| DaemonError::OracleError("Attestation not found".to_string()))?, + ) + .await; Ok(res.clone()) } } diff --git a/p2pd-oracle-client/Cargo.toml b/p2pd-oracle-client/Cargo.toml index f8211c6a..1471dbed 100644 --- a/p2pd-oracle-client/Cargo.toml +++ b/p2pd-oracle-client/Cargo.toml @@ -5,9 +5,14 @@ homepage = "https://github.com/p2pderivatives/rust-dlc" license-file = "../LICENSE" name = "p2pd-oracle-client" repository = "https://github.com/p2pderivatives/rust-dlc/tree/master/p2pd-oracle-client" +edition = "2018" version = "0.1.0" +[features] +async = ["dep:async-trait", "dlc-manager/async"] + [dependencies] +async-trait = { version = "0.1.83", optional = true } chrono = {version = "0.4.19", features = ["serde"]} dlc-manager = {path = "../dlc-manager"} dlc-messages = {path = "../dlc-messages", features = ["use-serde"]} diff --git a/p2pd-oracle-client/src/lib.rs b/p2pd-oracle-client/src/lib.rs index 15038df4..567eaa5e 100644 --- a/p2pd-oracle-client/src/lib.rs +++ b/p2pd-oracle-client/src/lib.rs @@ -144,6 +144,7 @@ fn parse_event_id(event_id: &str) -> Result<(String, DateTime), DlcManagerE Ok((asset_id.to_string(), date_time)) } +#[cfg(not(feature = "async"))] impl Oracle for P2PDOracleClient { fn get_public_key(&self) -> XOnlyPublicKey { self.public_key @@ -177,6 +178,62 @@ impl Oracle for P2PDOracleClient { } } +#[cfg(feature = "async")] +#[async_trait::async_trait] +impl Oracle for P2PDOracleClient { + fn get_public_key(&self) -> XOnlyPublicKey { + self.public_key + } + + async fn get_announcement( + &self, + event_id: &str, + ) -> Result { + let (asset_id, date_time) = parse_event_id(event_id)?; + let path = announcement_path(&self.host, &asset_id, &date_time); + let announcement = reqwest::get(&path) + .await + .map_err(|x| { + dlc_manager::error::Error::IOError( + std::io::Error::new(std::io::ErrorKind::Other, x).into(), + ) + })? + .json::() + .await + .map_err(|e| DlcManagerError::OracleError(e.to_string()))?; + + Ok(announcement) + } + + async fn get_attestation( + &self, + event_id: &str, + ) -> Result { + let (asset_id, date_time) = parse_event_id(event_id)?; + let path = attestation_path(&self.host, &asset_id, &date_time); + let AttestationResponse { + event_id: _, + signatures, + values, + } = reqwest::get(&path) + .await + .map_err(|x| { + dlc_manager::error::Error::IOError( + std::io::Error::new(std::io::ErrorKind::Other, x).into(), + ) + })? + .json::() + .await + .map_err(|e| DlcManagerError::OracleError(e.to_string()))?; + + Ok(OracleAttestation { + oracle_public_key: self.public_key, + signatures, + outcomes: values, + }) + } +} + #[cfg(test)] mod tests { extern crate mockito; @@ -217,6 +274,7 @@ mod tests { } #[test] + #[cfg(not(feature = "async"))] fn get_announcement_test() { let url = &mockito::server_url(); let _pubkey_mock = pubkey_mock(); @@ -237,6 +295,7 @@ mod tests { } #[test] + #[cfg(not(feature = "async"))] fn get_attestation_test() { let url = &mockito::server_url(); let _pubkey_mock = pubkey_mock(); From e646ac605c630447d716499863fee91086a7b2a3 Mon Sep 17 00:00:00 2001 From: bennyhodl Date: Fri, 1 Nov 2024 13:38:03 -0400 Subject: [PATCH 4/6] Run sample only in sync --- sample/Cargo.toml | 3 +++ sample/src/cli.rs | 11 +++++++++++ sample/src/main.rs | 1 + 3 files changed, 15 insertions(+) diff --git a/sample/Cargo.toml b/sample/Cargo.toml index 8219d04c..67980ab9 100644 --- a/sample/Cargo.toml +++ b/sample/Cargo.toml @@ -4,6 +4,9 @@ edition = "2018" name = "sample" version = "0.1.0" +[features] +async = [] + [dependencies] bitcoin = {version = "0.32.2"} bitcoin-rpc-provider = {path = "../bitcoin-rpc-provider"} diff --git a/sample/src/cli.rs b/sample/src/cli.rs index c55b3795..9b654845 100644 --- a/sample/src/cli.rs +++ b/sample/src/cli.rs @@ -85,6 +85,17 @@ macro_rules! read_id_or_continue { }; } +#[cfg(feature = "async")] +pub(crate) async fn poll_for_user_input( + _peer_manager: Arc, + _dlc_message_handler: Arc, + _dlc_manager: Arc>, + _offers_path: &str, +) { + println!("Sample does not run async manager."); + std::process::exit(0) +} +#[cfg(not(feature = "async"))] pub(crate) async fn poll_for_user_input( peer_manager: Arc, dlc_message_handler: Arc, diff --git a/sample/src/main.rs b/sample/src/main.rs index 5bea995f..09cf2e42 100644 --- a/sample/src/main.rs +++ b/sample/src/main.rs @@ -1,3 +1,4 @@ +#[allow(unused_macros, unused_imports, dead_code)] mod cli; mod disk; mod hex_utils; From f778410b311e7a2b93e1a0655569e9b6c0bb0af1 Mon Sep 17 00:00:00 2001 From: bennyhodl Date: Fri, 1 Nov 2024 13:38:49 -0400 Subject: [PATCH 5/6] Only run integration tests in sync --- dlc-manager/tests/channel_execution_tests.rs | 2373 +++++++++--------- dlc-manager/tests/manager_execution_tests.rs | 1605 ++++++------ p2pd-oracle-client/src/lib.rs | 1 + 3 files changed, 2000 insertions(+), 1979 deletions(-) diff --git a/dlc-manager/tests/channel_execution_tests.rs b/dlc-manager/tests/channel_execution_tests.rs index 05da7bb5..f81024de 100644 --- a/dlc-manager/tests/channel_execution_tests.rs +++ b/dlc-manager/tests/channel_execution_tests.rs @@ -1,747 +1,673 @@ #[macro_use] mod test_utils; -use bitcoin::Amount; -use bitcoin_test_utils::rpc_helpers::init_clients; -use bitcoincore_rpc::RpcApi; -use dlc_manager::contract::contract_input::ContractInput; -use dlc_manager::manager::Manager; -use dlc_manager::{ - channel::Channel, contract::Contract, Blockchain, CachedContractSignerProvider, Oracle, - SimpleSigner, Storage, Wallet, -}; -use dlc_manager::{ChannelId, ContractId}; -use dlc_messages::Message; -use electrs_blockchain_provider::ElectrsBlockchainProvider; -use lightning::util::ser::Writeable; -use mocks::memory_storage_provider::MemoryStorage; -use mocks::mock_oracle_provider::MockOracle; -use mocks::mock_time::MockTime; -use secp256k1_zkp::rand::{thread_rng, RngCore}; -use secp256k1_zkp::EcdsaAdaptorSignature; -use simple_wallet::SimpleWallet; -use test_utils::{get_enum_test_params, TestParams}; - -use std::sync::mpsc::{sync_channel, Receiver, Sender}; -use std::thread; - -use std::time::Duration; -use std::{ - collections::HashMap, - sync::{ - atomic::{AtomicBool, Ordering}, - mpsc::channel, - Arc, Mutex, - }, -}; - -use crate::test_utils::{refresh_wallet, EVENT_MATURITY}; - -type DlcParty = Arc< - Mutex< - Manager< - Arc, Arc>>, - Arc< - CachedContractSignerProvider< - Arc, Arc>>, - SimpleSigner, +#[cfg(not(feature = "async"))] +mod sync_tests { + use crate::test_utils::{self, get_enum_test_params, TestParams}; + use bitcoin::Amount; + use bitcoin_test_utils::rpc_helpers::init_clients; + use bitcoincore_rpc::RpcApi; + use dlc_manager::contract::contract_input::ContractInput; + use dlc_manager::manager::Manager; + use dlc_manager::{ + channel::Channel, contract::Contract, Blockchain, CachedContractSignerProvider, Oracle, + SimpleSigner, Storage, Wallet, + }; + use dlc_manager::{ChannelId, ContractId}; + use dlc_messages::Message; + use electrs_blockchain_provider::ElectrsBlockchainProvider; + use lightning::util::ser::Writeable; + use mocks::memory_storage_provider::MemoryStorage; + use mocks::mock_oracle_provider::MockOracle; + use mocks::mock_time::MockTime; + use secp256k1_zkp::rand::{thread_rng, RngCore}; + use secp256k1_zkp::EcdsaAdaptorSignature; + use simple_wallet::SimpleWallet; + + use std::sync::mpsc::{sync_channel, Receiver, Sender}; + use std::thread; + + use std::time::Duration; + use std::{ + collections::HashMap, + sync::{ + atomic::{AtomicBool, Ordering}, + mpsc::channel, + Arc, Mutex, + }, + }; + + use crate::test_utils::{refresh_wallet, EVENT_MATURITY}; + + type DlcParty = Arc< + Mutex< + Manager< + Arc, Arc>>, + Arc< + CachedContractSignerProvider< + Arc, Arc>>, + SimpleSigner, + >, >, + Arc, + Arc, + Arc, + Arc, + Arc, + SimpleSigner, >, - Arc, - Arc, - Arc, - Arc, - Arc, - SimpleSigner, >, - >, ->; - -fn get_established_channel_contract_id(dlc_party: &DlcParty, channel_id: &ChannelId) -> ContractId { - let channel = dlc_party - .lock() - .unwrap() - .get_store() - .get_channel(channel_id) - .unwrap() - .unwrap(); - if let Channel::Signed(s) = channel { - return s.get_contract_id().expect("to have a contract id"); + >; + + fn get_established_channel_contract_id( + dlc_party: &DlcParty, + channel_id: &ChannelId, + ) -> ContractId { + let channel = dlc_party + .lock() + .unwrap() + .get_store() + .get_channel(channel_id) + .unwrap() + .unwrap(); + if let Channel::Signed(s) = channel { + return s.get_contract_id().expect("to have a contract id"); + } + + panic!("Invalid channel state {:?}.", channel); } - panic!("Invalid channel state {:?}.", channel); -} + fn alter_adaptor_sig(input: &EcdsaAdaptorSignature) -> EcdsaAdaptorSignature { + let mut copy = input.as_ref().to_vec(); + let i = + thread_rng().next_u32() as usize % secp256k1_zkp::ffi::ECDSA_ADAPTOR_SIGNATURE_LENGTH; + copy[i] = copy[i].checked_add(1).unwrap_or(0); + EcdsaAdaptorSignature::from_slice(©).expect("to be able to create an adaptor signature") + } -fn alter_adaptor_sig(input: &EcdsaAdaptorSignature) -> EcdsaAdaptorSignature { - let mut copy = input.as_ref().to_vec(); - let i = thread_rng().next_u32() as usize % secp256k1_zkp::ffi::ECDSA_ADAPTOR_SIGNATURE_LENGTH; - copy[i] = copy[i].checked_add(1).unwrap_or(0); - EcdsaAdaptorSignature::from_slice(©).expect("to be able to create an adaptor signature") -} + /// We wrap updating the state of the chain monitor and calling the + /// `Manager::periodic_check` because the latter will only be aware of + /// newly confirmed transactions if the former processes new blocks. + fn periodic_check(dlc_party: DlcParty) { + let dlc_manager = dlc_party.lock().unwrap(); -/// We wrap updating the state of the chain monitor and calling the -/// `Manager::periodic_check` because the latter will only be aware of -/// newly confirmed transactions if the former processes new blocks. -fn periodic_check(dlc_party: DlcParty) { - let dlc_manager = dlc_party.lock().unwrap(); + dlc_manager.periodic_chain_monitor().unwrap(); + dlc_manager.periodic_check(true).unwrap(); + } - dlc_manager.periodic_chain_monitor().unwrap(); - dlc_manager.periodic_check(true).unwrap(); -} + #[derive(Eq, PartialEq, Clone)] + enum TestPath { + Close, + BadAcceptBufferAdaptorSignature, + BadSignBufferAdaptorSignature, + SettleClose, + BufferCheat, + RenewedClose, + SettleCheat, + CollaborativeClose, + SettleRenewSettle, + SettleOfferTimeout, + SettleAcceptTimeout, + SettleConfirmTimeout, + SettleReject, + SettleRace, + RenewOfferTimeout, + RenewAcceptTimeout, + RenewConfirmTimeout, + RenewFinalizeTimeout, + RenewReject, + RenewRace, + RenewEstablishedClose, + CancelOffer, + } -#[derive(Eq, PartialEq, Clone)] -enum TestPath { - Close, - BadAcceptBufferAdaptorSignature, - BadSignBufferAdaptorSignature, - SettleClose, - BufferCheat, - RenewedClose, - SettleCheat, - CollaborativeClose, - SettleRenewSettle, - SettleOfferTimeout, - SettleAcceptTimeout, - SettleConfirmTimeout, - SettleReject, - SettleRace, - RenewOfferTimeout, - RenewAcceptTimeout, - RenewConfirmTimeout, - RenewFinalizeTimeout, - RenewReject, - RenewRace, - RenewEstablishedClose, - CancelOffer, -} + #[test] + #[ignore] + fn channel_established_close_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::Close); + } -#[test] -#[ignore] -fn channel_established_close_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::Close); -} + #[test] + #[ignore] + fn channel_bad_accept_buffer_adaptor_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::BadAcceptBufferAdaptorSignature, + ); + } -#[test] -#[ignore] -fn channel_bad_accept_buffer_adaptor_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::BadAcceptBufferAdaptorSignature, - ); -} + #[test] + #[ignore] + fn channel_bad_sign_buffer_adaptor_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::BadSignBufferAdaptorSignature, + ); + } -#[test] -#[ignore] -fn channel_bad_sign_buffer_adaptor_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::BadSignBufferAdaptorSignature, - ); -} + #[test] + #[ignore] + fn channel_settled_close_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::SettleClose); + } -#[test] -#[ignore] -fn channel_settled_close_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::SettleClose); -} + #[test] + #[ignore] + fn channel_punish_buffer_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::BufferCheat); + } -#[test] -#[ignore] -fn channel_punish_buffer_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::BufferCheat); -} + #[test] + #[ignore] + fn channel_renew_close_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::RenewedClose); + } -#[test] -#[ignore] -fn channel_renew_close_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::RenewedClose); -} + #[test] + #[ignore] + fn channel_renew_established_close_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::RenewEstablishedClose, + ); + } -#[test] -#[ignore] -fn channel_renew_established_close_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::RenewEstablishedClose, - ); -} + #[test] + #[ignore] + fn channel_settle_cheat_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::SettleCheat); + } -#[test] -#[ignore] -fn channel_settle_cheat_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::SettleCheat); -} + #[test] + #[ignore] + fn channel_collaborative_close_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::CollaborativeClose, + ); + } -#[test] -#[ignore] -fn channel_collaborative_close_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::CollaborativeClose, - ); -} + #[test] + #[ignore] + fn channel_settle_renew_settle_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::SettleRenewSettle, + ); + } -#[test] -#[ignore] -fn channel_settle_renew_settle_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::SettleRenewSettle, - ); -} + #[test] + #[ignore] + fn channel_settle_offer_timeout_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::SettleOfferTimeout, + ); + } -#[test] -#[ignore] -fn channel_settle_offer_timeout_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::SettleOfferTimeout, - ); -} + #[test] + #[ignore] + fn channel_settle_accept_timeout_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::SettleAcceptTimeout, + ); + } -#[test] -#[ignore] -fn channel_settle_accept_timeout_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::SettleAcceptTimeout, - ); -} + #[test] + #[ignore] + fn channel_settle_confirm_timeout_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::SettleConfirmTimeout, + ); + } -#[test] -#[ignore] -fn channel_settle_confirm_timeout_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::SettleConfirmTimeout, - ); -} + #[test] + #[ignore] + fn channel_settle_reject_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::SettleReject); + } -#[test] -#[ignore] -fn channel_settle_reject_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::SettleReject); -} + #[test] + #[ignore] + fn channel_settle_race_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::SettleRace); + } -#[test] -#[ignore] -fn channel_settle_race_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::SettleRace); -} + #[test] + #[ignore] + fn channel_renew_offer_timeout_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::RenewOfferTimeout, + ); + } -#[test] -#[ignore] -fn channel_renew_offer_timeout_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::RenewOfferTimeout, - ); -} + #[test] + #[ignore] + fn channel_renew_accept_timeout_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::RenewAcceptTimeout, + ); + } -#[test] -#[ignore] -fn channel_renew_accept_timeout_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::RenewAcceptTimeout, - ); -} + #[test] + #[ignore] + fn channel_renew_confirm_timeout_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::RenewConfirmTimeout, + ); + } -#[test] -#[ignore] -fn channel_renew_confirm_timeout_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::RenewConfirmTimeout, - ); -} + #[test] + #[ignore] + fn channel_renew_finalize_timeout_test() { + channel_execution_test( + get_enum_test_params(1, 1, None), + TestPath::RenewFinalizeTimeout, + ); + } -#[test] -#[ignore] -fn channel_renew_finalize_timeout_test() { - channel_execution_test( - get_enum_test_params(1, 1, None), - TestPath::RenewFinalizeTimeout, - ); -} + #[test] + #[ignore] + fn channel_renew_reject_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::RenewReject); + } -#[test] -#[ignore] -fn channel_renew_reject_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::RenewReject); -} + #[test] + #[ignore] + fn channel_renew_race_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::RenewRace); + } -#[test] -#[ignore] -fn channel_renew_race_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::RenewRace); -} + #[test] + #[ignore] + fn channel_offer_reject_test() { + channel_execution_test(get_enum_test_params(1, 1, None), TestPath::CancelOffer); + } -#[test] -#[ignore] -fn channel_offer_reject_test() { - channel_execution_test(get_enum_test_params(1, 1, None), TestPath::CancelOffer); -} + fn channel_execution_test(test_params: TestParams, path: TestPath) { + env_logger::init(); + let (alice_send, bob_receive) = channel::>(); + let (bob_send, alice_receive) = channel::>(); + let (alice_sync_send, alice_sync_receive) = sync_channel::<()>(0); + let (bob_sync_send, bob_sync_receive) = sync_channel::<()>(0); -fn channel_execution_test(test_params: TestParams, path: TestPath) { - env_logger::init(); - let (alice_send, bob_receive) = channel::>(); - let (bob_send, alice_receive) = channel::>(); - let (alice_sync_send, alice_sync_receive) = sync_channel::<()>(0); - let (bob_sync_send, bob_sync_receive) = sync_channel::<()>(0); + let (_, _, sink_rpc) = init_clients(); - let (_, _, sink_rpc) = init_clients(); + let mut alice_oracles = HashMap::with_capacity(1); + let mut bob_oracles = HashMap::with_capacity(1); - let mut alice_oracles = HashMap::with_capacity(1); - let mut bob_oracles = HashMap::with_capacity(1); + for oracle in test_params.oracles { + let oracle = Arc::new(oracle); + alice_oracles.insert(oracle.get_public_key(), Arc::clone(&oracle)); + bob_oracles.insert(oracle.get_public_key(), Arc::clone(&oracle)); + } - for oracle in test_params.oracles { - let oracle = Arc::new(oracle); - alice_oracles.insert(oracle.get_public_key(), Arc::clone(&oracle)); - bob_oracles.insert(oracle.get_public_key(), Arc::clone(&oracle)); - } + let alice_store = Arc::new(mocks::memory_storage_provider::MemoryStorage::new()); + let bob_store = Arc::new(mocks::memory_storage_provider::MemoryStorage::new()); + let mock_time = Arc::new(mocks::mock_time::MockTime {}); + mocks::mock_time::set_time((EVENT_MATURITY as u64) - 1); + + let electrs = Arc::new(ElectrsBlockchainProvider::new( + "http://localhost:3004/".to_string(), + bitcoin::Network::Regtest, + )); + + let alice_wallet = Arc::new(SimpleWallet::new( + electrs.clone(), + alice_store.clone(), + bitcoin::Network::Regtest, + )); + + let bob_wallet = Arc::new(SimpleWallet::new( + electrs.clone(), + bob_store.clone(), + bitcoin::Network::Regtest, + )); + + let alice_fund_address = alice_wallet.get_new_address().unwrap(); + let bob_fund_address = bob_wallet.get_new_address().unwrap(); - let alice_store = Arc::new(mocks::memory_storage_provider::MemoryStorage::new()); - let bob_store = Arc::new(mocks::memory_storage_provider::MemoryStorage::new()); - let mock_time = Arc::new(mocks::mock_time::MockTime {}); - mocks::mock_time::set_time((EVENT_MATURITY as u64) - 1); - - let electrs = Arc::new(ElectrsBlockchainProvider::new( - "http://localhost:3004/".to_string(), - bitcoin::Network::Regtest, - )); - - let alice_wallet = Arc::new(SimpleWallet::new( - electrs.clone(), - alice_store.clone(), - bitcoin::Network::Regtest, - )); - - let bob_wallet = Arc::new(SimpleWallet::new( - electrs.clone(), - bob_store.clone(), - bitcoin::Network::Regtest, - )); - - let alice_fund_address = alice_wallet.get_new_address().unwrap(); - let bob_fund_address = bob_wallet.get_new_address().unwrap(); - - sink_rpc - .send_to_address( - &alice_fund_address, - Amount::from_btc(2.0).unwrap(), - None, - None, - None, - None, - None, - None, - ) - .unwrap(); - - sink_rpc - .send_to_address( - &bob_fund_address, - Amount::from_btc(2.0).unwrap(), - None, - None, - None, - None, - None, - None, - ) - .unwrap(); - - let generate_blocks = |nb_blocks: u64| { - let prev_blockchain_height = electrs.get_blockchain_height().unwrap(); - - let sink_address = sink_rpc - .get_new_address(None, None) - .expect("RPC Error") - .assume_checked(); sink_rpc - .generate_to_address(nb_blocks, &sink_address) - .expect("RPC Error"); - - // Wait for electrs to have processed the new blocks - let mut cur_blockchain_height = prev_blockchain_height; - while cur_blockchain_height < prev_blockchain_height + nb_blocks { - std::thread::sleep(std::time::Duration::from_millis(200)); - cur_blockchain_height = electrs.get_blockchain_height().unwrap(); - } - }; + .send_to_address( + &alice_fund_address, + Amount::from_btc(2.0).unwrap(), + None, + None, + None, + None, + None, + None, + ) + .unwrap(); + + sink_rpc + .send_to_address( + &bob_fund_address, + Amount::from_btc(2.0).unwrap(), + None, + None, + None, + None, + None, + None, + ) + .unwrap(); - generate_blocks(6); - - refresh_wallet(&alice_wallet, 200000000); - refresh_wallet(&bob_wallet, 200000000); - - let alice_manager = Arc::new(Mutex::new( - Manager::new( - Arc::clone(&alice_wallet), - Arc::clone(&alice_wallet), - Arc::clone(&electrs), - alice_store, - alice_oracles, - Arc::clone(&mock_time), - Arc::clone(&electrs), - ) - .unwrap(), - )); - - let alice_manager_loop = Arc::clone(&alice_manager); - let alice_manager_send = Arc::clone(&alice_manager); - - let bob_manager = Arc::new(Mutex::new( - Manager::new( - Arc::clone(&bob_wallet), - Arc::clone(&bob_wallet), - Arc::clone(&electrs), - Arc::clone(&bob_store), - bob_oracles, - Arc::clone(&mock_time), - Arc::clone(&electrs), - ) - .unwrap(), - )); - - let bob_manager_loop = Arc::clone(&bob_manager); - let bob_manager_send = Arc::clone(&bob_manager); - let alice_send_loop = alice_send.clone(); - let bob_send_loop = bob_send.clone(); - - let alice_expect_error = Arc::new(AtomicBool::new(false)); - let bob_expect_error = Arc::new(AtomicBool::new(false)); - - let alice_expect_error_loop = alice_expect_error.clone(); - let bob_expect_error_loop = bob_expect_error.clone(); - - let path_copy = path.clone(); - let msg_filter = move |msg| { - if let TestPath::SettleAcceptTimeout = path_copy { - if let Message::SettleConfirm(_) = msg { - return None; + let generate_blocks = |nb_blocks: u64| { + let prev_blockchain_height = electrs.get_blockchain_height().unwrap(); + + let sink_address = sink_rpc + .get_new_address(None, None) + .expect("RPC Error") + .assume_checked(); + sink_rpc + .generate_to_address(nb_blocks, &sink_address) + .expect("RPC Error"); + + // Wait for electrs to have processed the new blocks + let mut cur_blockchain_height = prev_blockchain_height; + while cur_blockchain_height < prev_blockchain_height + nb_blocks { + std::thread::sleep(std::time::Duration::from_millis(200)); + cur_blockchain_height = electrs.get_blockchain_height().unwrap(); } - } - if let TestPath::SettleConfirmTimeout = path_copy { - if let Message::SettleFinalize(_) = msg { - return None; + }; + + generate_blocks(6); + + refresh_wallet(&alice_wallet, 200000000); + refresh_wallet(&bob_wallet, 200000000); + + let alice_manager = Arc::new(Mutex::new( + Manager::new( + Arc::clone(&alice_wallet), + Arc::clone(&alice_wallet), + Arc::clone(&electrs), + alice_store, + alice_oracles, + Arc::clone(&mock_time), + Arc::clone(&electrs), + ) + .unwrap(), + )); + + let alice_manager_loop = Arc::clone(&alice_manager); + let alice_manager_send = Arc::clone(&alice_manager); + + let bob_manager = Arc::new(Mutex::new( + Manager::new( + Arc::clone(&bob_wallet), + Arc::clone(&bob_wallet), + Arc::clone(&electrs), + Arc::clone(&bob_store), + bob_oracles, + Arc::clone(&mock_time), + Arc::clone(&electrs), + ) + .unwrap(), + )); + + let bob_manager_loop = Arc::clone(&bob_manager); + let bob_manager_send = Arc::clone(&bob_manager); + let alice_send_loop = alice_send.clone(); + let bob_send_loop = bob_send.clone(); + + let alice_expect_error = Arc::new(AtomicBool::new(false)); + let bob_expect_error = Arc::new(AtomicBool::new(false)); + + let alice_expect_error_loop = alice_expect_error.clone(); + let bob_expect_error_loop = bob_expect_error.clone(); + + let path_copy = path.clone(); + let msg_filter = move |msg| { + if let TestPath::SettleAcceptTimeout = path_copy { + if let Message::SettleConfirm(_) = msg { + return None; + } } - } - if let TestPath::RenewAcceptTimeout = path_copy { - if let Message::RenewConfirm(_) = msg { - return None; + if let TestPath::SettleConfirmTimeout = path_copy { + if let Message::SettleFinalize(_) = msg { + return None; + } } - } - if let TestPath::RenewConfirmTimeout = path_copy { - if let Message::RenewFinalize(_) = msg { - return None; + if let TestPath::RenewAcceptTimeout = path_copy { + if let Message::RenewConfirm(_) = msg { + return None; + } } - } - Some(msg) - }; - - let msg_filter_copy = msg_filter.clone(); - let path_copy = path.clone(); - let alter_sign = move |msg| match msg { - Message::SignChannel(mut sign_channel) => { - if path_copy == TestPath::BadSignBufferAdaptorSignature { - sign_channel.buffer_adaptor_signature = - alter_adaptor_sig(&sign_channel.buffer_adaptor_signature); + if let TestPath::RenewConfirmTimeout = path_copy { + if let Message::RenewFinalize(_) = msg { + return None; + } } - Some(Message::SignChannel(sign_channel)) - } - _ => msg_filter_copy(msg), - }; + Some(msg) + }; + + let msg_filter_copy = msg_filter.clone(); + let path_copy = path.clone(); + let alter_sign = move |msg| match msg { + Message::SignChannel(mut sign_channel) => { + if path_copy == TestPath::BadSignBufferAdaptorSignature { + sign_channel.buffer_adaptor_signature = + alter_adaptor_sig(&sign_channel.buffer_adaptor_signature); + } + Some(Message::SignChannel(sign_channel)) + } + _ => msg_filter_copy(msg), + }; + + let alice_handle = receive_loop!( + alice_receive, + alice_manager_loop, + alice_send_loop, + alice_expect_error_loop, + alice_sync_send, + msg_filter, + |msg| msg + ); + + let bob_handle = receive_loop!( + bob_receive, + bob_manager_loop, + bob_send_loop, + bob_expect_error_loop, + bob_sync_send, + alter_sign, + |msg| msg + ); - let alice_handle = receive_loop!( - alice_receive, - alice_manager_loop, - alice_send_loop, - alice_expect_error_loop, - alice_sync_send, - msg_filter, - |msg| msg - ); - - let bob_handle = receive_loop!( - bob_receive, - bob_manager_loop, - bob_send_loop, - bob_expect_error_loop, - bob_sync_send, - alter_sign, - |msg| msg - ); - - let offer_msg = bob_manager_send - .lock() - .unwrap() - .offer_channel( - &test_params.contract_input, - "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" - .parse() - .unwrap(), - ) - .expect("Send offer error"); - - let temporary_channel_id = offer_msg.temporary_channel_id; - bob_send - .send(Some(Message::OfferChannel(offer_msg))) - .unwrap(); - - assert_channel_state!(bob_manager_send, temporary_channel_id, Offered); - - alice_sync_receive.recv().expect("Error synchronizing"); - - assert_channel_state!(alice_manager_send, temporary_channel_id, Offered); - - if let TestPath::CancelOffer = path { - let (reject_msg, _) = alice_manager_send + let offer_msg = bob_manager_send .lock() .unwrap() - .reject_channel(&temporary_channel_id) - .expect("Error rejecting contract offer"); - assert_channel_state!(alice_manager_send, temporary_channel_id, Cancelled); - alice_send.send(Some(Message::Reject(reject_msg))).unwrap(); - - bob_sync_receive.recv().expect("Error synchronizing"); - assert_channel_state!(bob_manager_send, temporary_channel_id, Cancelled); - return; - } + .offer_channel( + &test_params.contract_input, + "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" + .parse() + .unwrap(), + ) + .expect("Send offer error"); + + let temporary_channel_id = offer_msg.temporary_channel_id; + bob_send + .send(Some(Message::OfferChannel(offer_msg))) + .unwrap(); - let (mut accept_msg, channel_id, contract_id, _) = alice_manager_send - .lock() - .unwrap() - .accept_channel(&temporary_channel_id) - .expect("Error accepting contract offer"); - assert_channel_state!(alice_manager_send, channel_id, Accepted); - - match path { - TestPath::BadAcceptBufferAdaptorSignature => { - accept_msg.buffer_adaptor_signature = - alter_adaptor_sig(&accept_msg.buffer_adaptor_signature); - bob_expect_error.store(true, Ordering::Relaxed); - alice_send - .send(Some(Message::AcceptChannel(accept_msg))) - .unwrap(); - bob_sync_receive.recv().expect("Error synchronizing"); - assert_channel_state!(bob_manager_send, temporary_channel_id, FailedAccept); - } - TestPath::BadSignBufferAdaptorSignature => { - alice_expect_error.store(true, Ordering::Relaxed); - alice_send - .send(Some(Message::AcceptChannel(accept_msg))) - .unwrap(); - // Bob receives accept message - bob_sync_receive.recv().expect("Error synchronizing"); - // Alice receives sign message - alice_sync_receive.recv().expect("Error synchronizing"); - assert_channel_state!(alice_manager_send, channel_id, FailedSign); - } - _ => { - alice_send - .send(Some(Message::AcceptChannel(accept_msg))) - .unwrap(); - bob_sync_receive.recv().expect("Error synchronizing"); + assert_channel_state!(bob_manager_send, temporary_channel_id, Offered); - assert_channel_state!(bob_manager_send, channel_id, Signed, Established); + alice_sync_receive.recv().expect("Error synchronizing"); - alice_sync_receive.recv().expect("Error synchronizing"); + assert_channel_state!(alice_manager_send, temporary_channel_id, Offered); - assert_channel_state!(alice_manager_send, channel_id, Signed, Established); + if let TestPath::CancelOffer = path { + let (reject_msg, _) = alice_manager_send + .lock() + .unwrap() + .reject_channel(&temporary_channel_id) + .expect("Error rejecting contract offer"); + assert_channel_state!(alice_manager_send, temporary_channel_id, Cancelled); + alice_send.send(Some(Message::Reject(reject_msg))).unwrap(); - generate_blocks(6); + bob_sync_receive.recv().expect("Error synchronizing"); + assert_channel_state!(bob_manager_send, temporary_channel_id, Cancelled); + return; + } - mocks::mock_time::set_time((EVENT_MATURITY as u64) + 1); + let (mut accept_msg, channel_id, contract_id, _) = alice_manager_send + .lock() + .unwrap() + .accept_channel(&temporary_channel_id) + .expect("Error accepting contract offer"); + assert_channel_state!(alice_manager_send, channel_id, Accepted); + + match path { + TestPath::BadAcceptBufferAdaptorSignature => { + accept_msg.buffer_adaptor_signature = + alter_adaptor_sig(&accept_msg.buffer_adaptor_signature); + bob_expect_error.store(true, Ordering::Relaxed); + alice_send + .send(Some(Message::AcceptChannel(accept_msg))) + .unwrap(); + bob_sync_receive.recv().expect("Error synchronizing"); + assert_channel_state!(bob_manager_send, temporary_channel_id, FailedAccept); + } + TestPath::BadSignBufferAdaptorSignature => { + alice_expect_error.store(true, Ordering::Relaxed); + alice_send + .send(Some(Message::AcceptChannel(accept_msg))) + .unwrap(); + // Bob receives accept message + bob_sync_receive.recv().expect("Error synchronizing"); + // Alice receives sign message + alice_sync_receive.recv().expect("Error synchronizing"); + assert_channel_state!(alice_manager_send, channel_id, FailedSign); + } + _ => { + alice_send + .send(Some(Message::AcceptChannel(accept_msg))) + .unwrap(); + bob_sync_receive.recv().expect("Error synchronizing"); - periodic_check(alice_manager_send.clone()); + assert_channel_state!(bob_manager_send, channel_id, Signed, Established); - periodic_check(bob_manager_send.clone()); + alice_sync_receive.recv().expect("Error synchronizing"); - assert_contract_state!(alice_manager_send, contract_id, Confirmed); - assert_contract_state!(bob_manager_send, contract_id, Confirmed); + assert_channel_state!(alice_manager_send, channel_id, Signed, Established); - // Select the first one to close or refund randomly - let (first, first_send, first_receive, second, second_send, second_receive) = - if thread_rng().next_u32() % 2 == 0 { - ( - alice_manager_send, - &alice_send, - &alice_sync_receive, - bob_manager_send, - &bob_send, - &bob_sync_receive, - ) - } else { - ( - bob_manager_send, - &bob_send, - &bob_sync_receive, - alice_manager_send, - &alice_send, - &alice_sync_receive, - ) - }; + generate_blocks(6); - match path { - TestPath::Close => { - close_established_channel(first, second, channel_id, &generate_blocks); - } - TestPath::CollaborativeClose => { - collaborative_close( - first, - first_send, - second, - channel_id, - second_receive, - &generate_blocks, - ); - } - TestPath::SettleOfferTimeout - | TestPath::SettleAcceptTimeout - | TestPath::SettleConfirmTimeout => { - settle_timeout( - first, - first_send, - first_receive, - second, - second_send, - second_receive, - channel_id, - path, - ); - } - TestPath::SettleReject => { - settle_reject( - first, - first_send, - first_receive, - second, - second_send, - second_receive, - channel_id, - ); - } - TestPath::SettleRace => { - settle_race( - first, - first_send, - first_receive, - second, - second_send, - second_receive, - channel_id, - ); - } - _ => { - // Shuffle positions - let (first, first_send, first_receive, second, second_send, second_receive) = - if thread_rng().next_u32() % 2 == 0 { - ( - first, - first_send, - first_receive, - second, - second_send, - second_receive, - ) - } else { - ( - second, - second_send, - second_receive, - first, - first_send, - first_receive, - ) - }; + mocks::mock_time::set_time((EVENT_MATURITY as u64) + 1); - first.lock().unwrap().get_store().save(); + periodic_check(alice_manager_send.clone()); - if let TestPath::RenewEstablishedClose = path { + periodic_check(bob_manager_send.clone()); + + assert_contract_state!(alice_manager_send, contract_id, Confirmed); + assert_contract_state!(bob_manager_send, contract_id, Confirmed); + + // Select the first one to close or refund randomly + let (first, first_send, first_receive, second, second_send, second_receive) = + if thread_rng().next_u32() % 2 == 0 { + ( + alice_manager_send, + &alice_send, + &alice_sync_receive, + bob_manager_send, + &bob_send, + &bob_sync_receive, + ) } else { - settle_channel( - first.clone(), + ( + bob_manager_send, + &bob_send, + &bob_sync_receive, + alice_manager_send, + &alice_send, + &alice_sync_receive, + ) + }; + + match path { + TestPath::Close => { + close_established_channel(first, second, channel_id, &generate_blocks); + } + TestPath::CollaborativeClose => { + collaborative_close( + first, + first_send, + second, + channel_id, + second_receive, + &generate_blocks, + ); + } + TestPath::SettleOfferTimeout + | TestPath::SettleAcceptTimeout + | TestPath::SettleConfirmTimeout => { + settle_timeout( + first, first_send, first_receive, - second.clone(), + second, second_send, second_receive, channel_id, + path, ); } - - match path { - TestPath::SettleClose => { - let closer = if thread_rng().next_u32() % 2 == 0 { - first + TestPath::SettleReject => { + settle_reject( + first, + first_send, + first_receive, + second, + second_send, + second_receive, + channel_id, + ); + } + TestPath::SettleRace => { + settle_race( + first, + first_send, + first_receive, + second, + second_send, + second_receive, + channel_id, + ); + } + _ => { + // Shuffle positions + let (first, first_send, first_receive, second, second_send, second_receive) = + if thread_rng().next_u32() % 2 == 0 { + ( + first, + first_send, + first_receive, + second, + second_send, + second_receive, + ) } else { - second + ( + second, + second_send, + second_receive, + first, + first_send, + first_receive, + ) }; - closer - .lock() - .unwrap() - .force_close_channel(&channel_id) - .expect("to be able to unilaterally close the channel."); - } - TestPath::BufferCheat => { - cheat_punish(first, second, channel_id, &generate_blocks, true); - } - TestPath::RenewOfferTimeout - | TestPath::RenewAcceptTimeout - | TestPath::RenewConfirmTimeout => { - renew_timeout( - first, - first_send, - first_receive, - second, - second_send, - second_receive, - channel_id, - &test_params.contract_input, - path, - &generate_blocks, - ); - } - TestPath::RenewReject => { - renew_reject( - first, - first_send, - first_receive, - second, - second_send, - second_receive, - channel_id, - &test_params.contract_input, - ); - } - TestPath::RenewRace => { - renew_race( - first, - first_send, - first_receive, - second, - second_send, - second_receive, - channel_id, - &test_params.contract_input, - ); - } - TestPath::RenewedClose - | TestPath::SettleCheat - | TestPath::RenewEstablishedClose => { - first.lock().unwrap().get_store().save(); - - let check_prev_contract_close = - if let TestPath::RenewEstablishedClose = path { - true - } else { - false - }; + first.lock().unwrap().get_store().save(); - renew_channel( + if let TestPath::RenewEstablishedClose = path { + } else { + settle_channel( first.clone(), first_send, first_receive, @@ -749,625 +675,712 @@ fn channel_execution_test(test_params: TestParams, path: TestPath) { second_send, second_receive, channel_id, - &test_params.contract_input, - check_prev_contract_close, ); + } - if let TestPath::RenewedClose = path { - close_established_channel( + match path { + TestPath::SettleClose => { + let closer = if thread_rng().next_u32() % 2 == 0 { + first + } else { + second + }; + + closer + .lock() + .unwrap() + .force_close_channel(&channel_id) + .expect("to be able to unilaterally close the channel."); + } + TestPath::BufferCheat => { + cheat_punish(first, second, channel_id, &generate_blocks, true); + } + TestPath::RenewOfferTimeout + | TestPath::RenewAcceptTimeout + | TestPath::RenewConfirmTimeout => { + renew_timeout( first, + first_send, + first_receive, second, + second_send, + second_receive, channel_id, + &test_params.contract_input, + path, &generate_blocks, ); - } else if let TestPath::SettleCheat = path { - cheat_punish(first, second, channel_id, &generate_blocks, false); } - } - TestPath::SettleRenewSettle => { - renew_channel( - first.clone(), - first_send, - first_receive, - second.clone(), - second_send, - second_receive, - channel_id, - &test_params.contract_input, - false, - ); + TestPath::RenewReject => { + renew_reject( + first, + first_send, + first_receive, + second, + second_send, + second_receive, + channel_id, + &test_params.contract_input, + ); + } + TestPath::RenewRace => { + renew_race( + first, + first_send, + first_receive, + second, + second_send, + second_receive, + channel_id, + &test_params.contract_input, + ); + } + TestPath::RenewedClose + | TestPath::SettleCheat + | TestPath::RenewEstablishedClose => { + first.lock().unwrap().get_store().save(); + + let check_prev_contract_close = + if let TestPath::RenewEstablishedClose = path { + true + } else { + false + }; + + renew_channel( + first.clone(), + first_send, + first_receive, + second.clone(), + second_send, + second_receive, + channel_id, + &test_params.contract_input, + check_prev_contract_close, + ); - settle_channel( - first, - first_send, - first_receive, - second, - second_send, - second_receive, - channel_id, - ); + if let TestPath::RenewedClose = path { + close_established_channel( + first, + second, + channel_id, + &generate_blocks, + ); + } else if let TestPath::SettleCheat = path { + cheat_punish( + first, + second, + channel_id, + &generate_blocks, + false, + ); + } + } + TestPath::SettleRenewSettle => { + renew_channel( + first.clone(), + first_send, + first_receive, + second.clone(), + second_send, + second_receive, + channel_id, + &test_params.contract_input, + false, + ); + + settle_channel( + first, + first_send, + first_receive, + second, + second_send, + second_receive, + channel_id, + ); + } + _ => (), } - _ => (), } } } } + + alice_send.send(None).unwrap(); + bob_send.send(None).unwrap(); + + alice_handle.join().unwrap(); + bob_handle.join().unwrap(); } - alice_send.send(None).unwrap(); - bob_send.send(None).unwrap(); + fn close_established_channel( + first: DlcParty, + second: DlcParty, + channel_id: ChannelId, + generate_blocks: &F, + ) where + F: Fn(u64), + { + first + .lock() + .unwrap() + .force_close_channel(&channel_id) + .expect("to be able to unilaterally close."); + assert_channel_state!(first, channel_id, Signed, Closing); + + let contract_id = get_established_channel_contract_id(&first, &channel_id); - alice_handle.join().unwrap(); - bob_handle.join().unwrap(); -} + periodic_check(first.clone()); -fn close_established_channel( - first: DlcParty, - second: DlcParty, - channel_id: ChannelId, - generate_blocks: &F, -) where - F: Fn(u64), -{ - first - .lock() - .unwrap() - .force_close_channel(&channel_id) - .expect("to be able to unilaterally close."); - assert_channel_state!(first, channel_id, Signed, Closing); + let wait = dlc_manager::manager::CET_NSEQUENCE; - let contract_id = get_established_channel_contract_id(&first, &channel_id); + generate_blocks(10); - periodic_check(first.clone()); + periodic_check(second.clone()); - let wait = dlc_manager::manager::CET_NSEQUENCE; + assert_channel_state!(second, channel_id, Signed, Closing); - generate_blocks(10); + periodic_check(first.clone()); - periodic_check(second.clone()); + // Should not have changed state before the CET is spendable. + assert_channel_state!(first, channel_id, Signed, Closing); - assert_channel_state!(second, channel_id, Signed, Closing); + generate_blocks(wait as u64 - 9); - periodic_check(first.clone()); + periodic_check(first.clone()); - // Should not have changed state before the CET is spendable. - assert_channel_state!(first, channel_id, Signed, Closing); + assert_channel_state!(first, channel_id, Closed); - generate_blocks(wait as u64 - 9); + assert_contract_state!(first, contract_id, PreClosed); - periodic_check(first.clone()); + generate_blocks(1); - assert_channel_state!(first, channel_id, Closed); + periodic_check(second.clone()); - assert_contract_state!(first, contract_id, PreClosed); + assert_channel_state!(second, channel_id, CounterClosed); + assert_contract_state!(second, contract_id, PreClosed); - generate_blocks(1); + generate_blocks(5); - periodic_check(second.clone()); + periodic_check(first.clone()); + periodic_check(second.clone()); - assert_channel_state!(second, channel_id, CounterClosed); - assert_contract_state!(second, contract_id, PreClosed); + assert_contract_state!(first, contract_id, Closed); + assert_contract_state!(second, contract_id, Closed); + } - generate_blocks(5); + fn cheat_punish( + first: DlcParty, + second: DlcParty, + channel_id: ChannelId, + generate_blocks: &F, + established: bool, + ) { + first.lock().unwrap().get_store().rollback(); + + if established { + first + .lock() + .unwrap() + .force_close_channel(&channel_id) + .expect("the cheater to be able to close on established"); + } else { + first + .lock() + .unwrap() + .force_close_channel(&channel_id) + .expect("the cheater to be able to close on settled"); + } - periodic_check(first.clone()); - periodic_check(second.clone()); + generate_blocks(2); - assert_contract_state!(first, contract_id, Closed); - assert_contract_state!(second, contract_id, Closed); -} + periodic_check(second.clone()); -fn cheat_punish( - first: DlcParty, - second: DlcParty, - channel_id: ChannelId, - generate_blocks: &F, - established: bool, -) { - first.lock().unwrap().get_store().rollback(); + assert_channel_state!(second, channel_id, ClosedPunished); + } - if established { - first + fn settle_channel( + first: DlcParty, + first_send: &Sender>, + first_receive: &Receiver<()>, + second: DlcParty, + second_send: &Sender>, + second_receive: &Receiver<()>, + channel_id: ChannelId, + ) { + let (settle_offer, _) = first .lock() .unwrap() - .force_close_channel(&channel_id) - .expect("the cheater to be able to close on established"); - } else { - first + .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) + .expect("to be able to offer a settlement of the contract."); + + first_send + .send(Some(Message::SettleOffer(settle_offer))) + .unwrap(); + + second_receive.recv().expect("Error synchronizing"); + + assert_channel_state!(first, channel_id, Signed, SettledOffered); + + assert_channel_state!(second, channel_id, Signed, SettledReceived); + + let (settle_accept, _) = second .lock() .unwrap() - .force_close_channel(&channel_id) - .expect("the cheater to be able to close on settled"); - } + .accept_settle_offer(&channel_id) + .expect("to be able to accept a settlement offer"); + + second_send + .send(Some(Message::SettleAccept(settle_accept))) + .unwrap(); + + // Process Accept + first_receive.recv().expect("Error synchronizing"); + // Process Confirm + second_receive.recv().expect("Error synchronizing"); + // Process Finalize + first_receive.recv().expect("Error synchronizing"); - generate_blocks(2); + assert_channel_state!(first, channel_id, Signed, Settled); - periodic_check(second.clone()); + assert_channel_state!(second, channel_id, Signed, Settled); + } - assert_channel_state!(second, channel_id, ClosedPunished); -} + fn settle_reject( + first: DlcParty, + first_send: &Sender>, + first_receive: &Receiver<()>, + second: DlcParty, + second_send: &Sender>, + second_receive: &Receiver<()>, + channel_id: ChannelId, + ) { + let (settle_offer, _) = first + .lock() + .unwrap() + .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) + .expect("to be able to reject a settlement of the contract."); -fn settle_channel( - first: DlcParty, - first_send: &Sender>, - first_receive: &Receiver<()>, - second: DlcParty, - second_send: &Sender>, - second_receive: &Receiver<()>, - channel_id: ChannelId, -) { - let (settle_offer, _) = first - .lock() - .unwrap() - .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) - .expect("to be able to offer a settlement of the contract."); - - first_send - .send(Some(Message::SettleOffer(settle_offer))) - .unwrap(); - - second_receive.recv().expect("Error synchronizing"); - - assert_channel_state!(first, channel_id, Signed, SettledOffered); - - assert_channel_state!(second, channel_id, Signed, SettledReceived); - - let (settle_accept, _) = second - .lock() - .unwrap() - .accept_settle_offer(&channel_id) - .expect("to be able to accept a settlement offer"); - - second_send - .send(Some(Message::SettleAccept(settle_accept))) - .unwrap(); - - // Process Accept - first_receive.recv().expect("Error synchronizing"); - // Process Confirm - second_receive.recv().expect("Error synchronizing"); - // Process Finalize - first_receive.recv().expect("Error synchronizing"); - - assert_channel_state!(first, channel_id, Signed, Settled); - - assert_channel_state!(second, channel_id, Signed, Settled); -} + first_send + .send(Some(Message::SettleOffer(settle_offer))) + .unwrap(); -fn settle_reject( - first: DlcParty, - first_send: &Sender>, - first_receive: &Receiver<()>, - second: DlcParty, - second_send: &Sender>, - second_receive: &Receiver<()>, - channel_id: ChannelId, -) { - let (settle_offer, _) = first - .lock() - .unwrap() - .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) - .expect("to be able to reject a settlement of the contract."); + second_receive.recv().expect("Error synchronizing"); - first_send - .send(Some(Message::SettleOffer(settle_offer))) - .unwrap(); + assert_channel_state!(first, channel_id, Signed, SettledOffered); - second_receive.recv().expect("Error synchronizing"); + assert_channel_state!(second, channel_id, Signed, SettledReceived); - assert_channel_state!(first, channel_id, Signed, SettledOffered); + let (settle_reject, _) = second + .lock() + .unwrap() + .reject_settle_offer(&channel_id) + .expect("to be able to reject a settlement offer"); - assert_channel_state!(second, channel_id, Signed, SettledReceived); + second_send + .send(Some(Message::Reject(settle_reject))) + .unwrap(); - let (settle_reject, _) = second - .lock() - .unwrap() - .reject_settle_offer(&channel_id) - .expect("to be able to reject a settlement offer"); + first_receive.recv().expect("Error synchronizing"); - second_send - .send(Some(Message::Reject(settle_reject))) - .unwrap(); + assert_channel_state!(first, channel_id, Signed, Established); - first_receive.recv().expect("Error synchronizing"); + assert_channel_state!(second, channel_id, Signed, Established); + } - assert_channel_state!(first, channel_id, Signed, Established); + fn settle_race( + first: DlcParty, + first_send: &Sender>, + first_receive: &Receiver<()>, + second: DlcParty, + second_send: &Sender>, + second_receive: &Receiver<()>, + channel_id: ChannelId, + ) { + let (settle_offer, _) = first + .lock() + .unwrap() + .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) + .expect("to be able to offer a settlement of the contract."); - assert_channel_state!(second, channel_id, Signed, Established); -} + let (settle_offer_2, _) = second + .lock() + .unwrap() + .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) + .expect("to be able to offer a settlement of the contract."); -fn settle_race( - first: DlcParty, - first_send: &Sender>, - first_receive: &Receiver<()>, - second: DlcParty, - second_send: &Sender>, - second_receive: &Receiver<()>, - channel_id: ChannelId, -) { - let (settle_offer, _) = first - .lock() - .unwrap() - .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) - .expect("to be able to offer a settlement of the contract."); - - let (settle_offer_2, _) = second - .lock() - .unwrap() - .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) - .expect("to be able to offer a settlement of the contract."); - - first_send - .send(Some(Message::SettleOffer(settle_offer))) - .unwrap(); - - second_send - .send(Some(Message::SettleOffer(settle_offer_2))) - .unwrap(); - - // Process 2 offers + 2 rejects - first_receive - .recv_timeout(Duration::from_secs(2)) - .expect("Error synchronizing 1"); - second_receive - .recv_timeout(Duration::from_secs(2)) - .expect("Error synchronizing 2"); - first_receive - .recv_timeout(Duration::from_secs(2)) - .expect("Error synchronizing 3"); - second_receive - .recv_timeout(Duration::from_secs(2)) - .expect("Error synchronizing 4"); - - assert_channel_state!(first, channel_id, Signed, Established); - - assert_channel_state!(second, channel_id, Signed, Established); -} + first_send + .send(Some(Message::SettleOffer(settle_offer))) + .unwrap(); -fn renew_channel( - first: DlcParty, - first_send: &Sender>, - first_receive: &Receiver<()>, - second: DlcParty, - second_send: &Sender>, - second_receive: &Receiver<()>, - channel_id: ChannelId, - contract_input: &ContractInput, - check_prev_contract_close: bool, -) { - let prev_contract_id = if check_prev_contract_close { - Some(get_established_channel_contract_id(&first, &channel_id)) - } else { - None - }; + second_send + .send(Some(Message::SettleOffer(settle_offer_2))) + .unwrap(); - let (renew_offer, _) = first - .lock() - .unwrap() - .renew_offer(&channel_id, test_utils::ACCEPT_COLLATERAL, contract_input) - .expect("to be able to renew channel contract"); - - first_send - .send(Some(Message::RenewOffer(renew_offer))) - .expect("to be able to send the renew offer"); - - // Process Renew Offer - second_receive.recv().expect("Error synchronizing"); - - assert_channel_state!(first, channel_id, Signed, RenewOffered); - assert_channel_state!(second, channel_id, Signed, RenewOffered); - - let (accept_renew, _) = second - .lock() - .unwrap() - .accept_renew_offer(&channel_id) - .expect("to be able to accept the renewal"); - - second_send - .send(Some(Message::RenewAccept(accept_renew))) - .expect("to be able to send the accept renew"); - - // Process Renew Accept - first_receive.recv().expect("Error synchronizing"); - assert_channel_state!(first, channel_id, Signed, RenewConfirmed); - // Process Renew Confirm - second_receive.recv().expect("Error synchronizing"); - // Process Renew Finalize - first_receive.recv().expect("Error synchronizing"); - // Process Renew Revoke - second_receive.recv().expect("Error synchronizing"); - - if let Some(prev_contract_id) = prev_contract_id { - assert_contract_state!(first, prev_contract_id, Closed); - assert_contract_state!(second, prev_contract_id, Closed); + // Process 2 offers + 2 rejects + first_receive + .recv_timeout(Duration::from_secs(2)) + .expect("Error synchronizing 1"); + second_receive + .recv_timeout(Duration::from_secs(2)) + .expect("Error synchronizing 2"); + first_receive + .recv_timeout(Duration::from_secs(2)) + .expect("Error synchronizing 3"); + second_receive + .recv_timeout(Duration::from_secs(2)) + .expect("Error synchronizing 4"); + + assert_channel_state!(first, channel_id, Signed, Established); + + assert_channel_state!(second, channel_id, Signed, Established); } - let new_contract_id = get_established_channel_contract_id(&first, &channel_id); + fn renew_channel( + first: DlcParty, + first_send: &Sender>, + first_receive: &Receiver<()>, + second: DlcParty, + second_send: &Sender>, + second_receive: &Receiver<()>, + channel_id: ChannelId, + contract_input: &ContractInput, + check_prev_contract_close: bool, + ) { + let prev_contract_id = if check_prev_contract_close { + Some(get_established_channel_contract_id(&first, &channel_id)) + } else { + None + }; - assert_channel_state!(first, channel_id, Signed, Established); - assert_contract_state!(first, new_contract_id, Confirmed); - assert_channel_state!(second, channel_id, Signed, Established); - assert_contract_state!(second, new_contract_id, Confirmed); -} + let (renew_offer, _) = first + .lock() + .unwrap() + .renew_offer(&channel_id, test_utils::ACCEPT_COLLATERAL, contract_input) + .expect("to be able to renew channel contract"); -fn renew_reject( - first: DlcParty, - first_send: &Sender>, - first_receive: &Receiver<()>, - second: DlcParty, - second_send: &Sender>, - second_receive: &Receiver<()>, - channel_id: ChannelId, - contract_input: &ContractInput, -) { - let (renew_offer, _) = first - .lock() - .unwrap() - .renew_offer(&channel_id, test_utils::ACCEPT_COLLATERAL, contract_input) - .expect("to be able to renew channel contract"); - - first_send - .send(Some(Message::RenewOffer(renew_offer))) - .expect("to be able to send the renew offer"); - - // Process Renew Offer - second_receive.recv().expect("Error synchronizing"); - - assert_channel_state!(first, channel_id, Signed, RenewOffered); - assert_channel_state!(second, channel_id, Signed, RenewOffered); - - let (renew_reject, _) = second - .lock() - .unwrap() - .reject_renew_offer(&channel_id) - .expect("to be able to reject the renewal"); - - second_send - .send(Some(Message::Reject(renew_reject))) - .expect("to be able to send the renew reject"); - - // Process Renew Reject - first_receive.recv().expect("Error synchronizing"); - assert_channel_state!(first, channel_id, Signed, Settled); - assert_channel_state!(second, channel_id, Signed, Settled); -} + first_send + .send(Some(Message::RenewOffer(renew_offer))) + .expect("to be able to send the renew offer"); -fn renew_race( - first: DlcParty, - first_send: &Sender>, - first_receive: &Receiver<()>, - second: DlcParty, - second_send: &Sender>, - second_receive: &Receiver<()>, - channel_id: ChannelId, - contract_input: &ContractInput, -) { - let (renew_offer, _) = first - .lock() - .unwrap() - .renew_offer(&channel_id, test_utils::OFFER_COLLATERAL, contract_input) - .expect("to be able to renew channel contract"); - - let mut contract_input_2 = contract_input.clone(); - contract_input_2.accept_collateral = contract_input.offer_collateral; - contract_input_2.offer_collateral = contract_input.accept_collateral; - - let (renew_offer_2, _) = second - .lock() - .unwrap() - .renew_offer(&channel_id, test_utils::OFFER_COLLATERAL, &contract_input_2) - .expect("to be able to renew channel contract"); - - first_send - .send(Some(Message::RenewOffer(renew_offer))) - .expect("to be able to send the renew offer"); - - second_send - .send(Some(Message::RenewOffer(renew_offer_2))) - .expect("to be able to send the renew offer"); - - // Process 2 offers + 2 rejects - first_receive - .recv_timeout(Duration::from_secs(2)) - .expect("Error synchronizing 1"); - second_receive - .recv_timeout(Duration::from_secs(2)) - .expect("Error synchronizing 2"); - first_receive - .recv_timeout(Duration::from_secs(2)) - .expect("Error synchronizing 3"); - second_receive - .recv_timeout(Duration::from_secs(2)) - .expect("Error synchronizing 4"); - - assert_channel_state!(first, channel_id, Signed, Settled); - assert_channel_state!(second, channel_id, Signed, Settled); -} + // Process Renew Offer + second_receive.recv().expect("Error synchronizing"); -fn collaborative_close( - first: DlcParty, - first_send: &Sender>, - second: DlcParty, - channel_id: ChannelId, - sync_receive: &Receiver<()>, - generate_blocks: &F, -) { - let contract_id = get_established_channel_contract_id(&first, &channel_id); - let close_offer = first - .lock() - .unwrap() - .offer_collaborative_close(&channel_id, 100000000) - .expect("to be able to propose a collaborative close"); - first_send - .send(Some(Message::CollaborativeCloseOffer(close_offer))) - .expect("to be able to send collaborative close"); - sync_receive.recv().expect("Error synchronizing"); - - assert_channel_state!(first, channel_id, Signed, CollaborativeCloseOffered); - assert_channel_state!(second, channel_id, Signed, CollaborativeCloseOffered); - - second - .lock() - .unwrap() - .accept_collaborative_close(&channel_id) - .expect("to be able to accept a collaborative close"); - - assert_channel_state!(second, channel_id, CollaborativelyClosed); - assert_contract_state!(second, contract_id, Closed); - - generate_blocks(2); - - periodic_check(first.clone()); - - assert_channel_state!(first, channel_id, CollaborativelyClosed); - assert_contract_state!(first, contract_id, Closed); -} + assert_channel_state!(first, channel_id, Signed, RenewOffered); + assert_channel_state!(second, channel_id, Signed, RenewOffered); -fn renew_timeout( - first: DlcParty, - first_send: &Sender>, - first_receive: &Receiver<()>, - second: DlcParty, - second_send: &Sender>, - second_receive: &Receiver<()>, - channel_id: ChannelId, - contract_input: &ContractInput, - path: TestPath, - generate_blocks: &F, -) { - { + let (accept_renew, _) = second + .lock() + .unwrap() + .accept_renew_offer(&channel_id) + .expect("to be able to accept the renewal"); + + second_send + .send(Some(Message::RenewAccept(accept_renew))) + .expect("to be able to send the accept renew"); + + // Process Renew Accept + first_receive.recv().expect("Error synchronizing"); + assert_channel_state!(first, channel_id, Signed, RenewConfirmed); + // Process Renew Confirm + second_receive.recv().expect("Error synchronizing"); + // Process Renew Finalize + first_receive.recv().expect("Error synchronizing"); + // Process Renew Revoke + second_receive.recv().expect("Error synchronizing"); + + if let Some(prev_contract_id) = prev_contract_id { + assert_contract_state!(first, prev_contract_id, Closed); + assert_contract_state!(second, prev_contract_id, Closed); + } + + let new_contract_id = get_established_channel_contract_id(&first, &channel_id); + + assert_channel_state!(first, channel_id, Signed, Established); + assert_contract_state!(first, new_contract_id, Confirmed); + assert_channel_state!(second, channel_id, Signed, Established); + assert_contract_state!(second, new_contract_id, Confirmed); + } + + fn renew_reject( + first: DlcParty, + first_send: &Sender>, + first_receive: &Receiver<()>, + second: DlcParty, + second_send: &Sender>, + second_receive: &Receiver<()>, + channel_id: ChannelId, + contract_input: &ContractInput, + ) { let (renew_offer, _) = first .lock() .unwrap() .renew_offer(&channel_id, test_utils::ACCEPT_COLLATERAL, contract_input) - .expect("to be able to offer a settlement of the contract."); + .expect("to be able to renew channel contract"); first_send .send(Some(Message::RenewOffer(renew_offer))) - .unwrap(); + .expect("to be able to send the renew offer"); + // Process Renew Offer second_receive.recv().expect("Error synchronizing"); - if let TestPath::RenewOfferTimeout = path { - mocks::mock_time::set_time( - (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, - ); - periodic_check(first.clone()); + assert_channel_state!(first, channel_id, Signed, RenewOffered); + assert_channel_state!(second, channel_id, Signed, RenewOffered); - assert_channel_state!(first, channel_id, Closed); - } else { - let (renew_accept, _) = second + let (renew_reject, _) = second + .lock() + .unwrap() + .reject_renew_offer(&channel_id) + .expect("to be able to reject the renewal"); + + second_send + .send(Some(Message::Reject(renew_reject))) + .expect("to be able to send the renew reject"); + + // Process Renew Reject + first_receive.recv().expect("Error synchronizing"); + assert_channel_state!(first, channel_id, Signed, Settled); + assert_channel_state!(second, channel_id, Signed, Settled); + } + + fn renew_race( + first: DlcParty, + first_send: &Sender>, + first_receive: &Receiver<()>, + second: DlcParty, + second_send: &Sender>, + second_receive: &Receiver<()>, + channel_id: ChannelId, + contract_input: &ContractInput, + ) { + let (renew_offer, _) = first + .lock() + .unwrap() + .renew_offer(&channel_id, test_utils::OFFER_COLLATERAL, contract_input) + .expect("to be able to renew channel contract"); + + let mut contract_input_2 = contract_input.clone(); + contract_input_2.accept_collateral = contract_input.offer_collateral; + contract_input_2.offer_collateral = contract_input.accept_collateral; + + let (renew_offer_2, _) = second + .lock() + .unwrap() + .renew_offer(&channel_id, test_utils::OFFER_COLLATERAL, &contract_input_2) + .expect("to be able to renew channel contract"); + + first_send + .send(Some(Message::RenewOffer(renew_offer))) + .expect("to be able to send the renew offer"); + + second_send + .send(Some(Message::RenewOffer(renew_offer_2))) + .expect("to be able to send the renew offer"); + + // Process 2 offers + 2 rejects + first_receive + .recv_timeout(Duration::from_secs(2)) + .expect("Error synchronizing 1"); + second_receive + .recv_timeout(Duration::from_secs(2)) + .expect("Error synchronizing 2"); + first_receive + .recv_timeout(Duration::from_secs(2)) + .expect("Error synchronizing 3"); + second_receive + .recv_timeout(Duration::from_secs(2)) + .expect("Error synchronizing 4"); + + assert_channel_state!(first, channel_id, Signed, Settled); + assert_channel_state!(second, channel_id, Signed, Settled); + } + + fn collaborative_close( + first: DlcParty, + first_send: &Sender>, + second: DlcParty, + channel_id: ChannelId, + sync_receive: &Receiver<()>, + generate_blocks: &F, + ) { + let contract_id = get_established_channel_contract_id(&first, &channel_id); + let close_offer = first + .lock() + .unwrap() + .offer_collaborative_close(&channel_id, 100000000) + .expect("to be able to propose a collaborative close"); + first_send + .send(Some(Message::CollaborativeCloseOffer(close_offer))) + .expect("to be able to send collaborative close"); + sync_receive.recv().expect("Error synchronizing"); + + assert_channel_state!(first, channel_id, Signed, CollaborativeCloseOffered); + assert_channel_state!(second, channel_id, Signed, CollaborativeCloseOffered); + + second + .lock() + .unwrap() + .accept_collaborative_close(&channel_id) + .expect("to be able to accept a collaborative close"); + + assert_channel_state!(second, channel_id, CollaborativelyClosed); + assert_contract_state!(second, contract_id, Closed); + + generate_blocks(2); + + periodic_check(first.clone()); + + assert_channel_state!(first, channel_id, CollaborativelyClosed); + assert_contract_state!(first, contract_id, Closed); + } + + fn renew_timeout( + first: DlcParty, + first_send: &Sender>, + first_receive: &Receiver<()>, + second: DlcParty, + second_send: &Sender>, + second_receive: &Receiver<()>, + channel_id: ChannelId, + contract_input: &ContractInput, + path: TestPath, + generate_blocks: &F, + ) { + { + let (renew_offer, _) = first .lock() .unwrap() - .accept_renew_offer(&channel_id) - .expect("to be able to accept a settlement offer"); + .renew_offer(&channel_id, test_utils::ACCEPT_COLLATERAL, contract_input) + .expect("to be able to offer a settlement of the contract."); - second_send - .send(Some(Message::RenewAccept(renew_accept))) + first_send + .send(Some(Message::RenewOffer(renew_offer))) .unwrap(); - // Process Accept - first_receive.recv().expect("Error synchronizing"); - - if let TestPath::RenewAcceptTimeout = path { - mocks::mock_time::set_time( - (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, - ); - periodic_check(second.clone()); + second_receive.recv().expect("Error synchronizing"); - assert_channel_state!(second, channel_id, Closed); - } else if let TestPath::RenewConfirmTimeout = path { - // Process Confirm - second_receive.recv().expect("Error synchronizing"); + if let TestPath::RenewOfferTimeout = path { mocks::mock_time::set_time( (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, ); periodic_check(first.clone()); assert_channel_state!(first, channel_id, Closed); - } else if let TestPath::RenewFinalizeTimeout = path { - //Process confirm - second_receive.recv().expect("Error synchronizing"); - // Process Finalize + } else { + let (renew_accept, _) = second + .lock() + .unwrap() + .accept_renew_offer(&channel_id) + .expect("to be able to accept a settlement offer"); + + second_send + .send(Some(Message::RenewAccept(renew_accept))) + .unwrap(); + + // Process Accept first_receive.recv().expect("Error synchronizing"); - mocks::mock_time::set_time( - (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, - ); - periodic_check(second.clone()); - generate_blocks(289); - periodic_check(second.clone()); - assert_channel_state!(second, channel_id, Closed); + if let TestPath::RenewAcceptTimeout = path { + mocks::mock_time::set_time( + (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, + ); + periodic_check(second.clone()); + + assert_channel_state!(second, channel_id, Closed); + } else if let TestPath::RenewConfirmTimeout = path { + // Process Confirm + second_receive.recv().expect("Error synchronizing"); + mocks::mock_time::set_time( + (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, + ); + periodic_check(first.clone()); + + assert_channel_state!(first, channel_id, Closed); + } else if let TestPath::RenewFinalizeTimeout = path { + //Process confirm + second_receive.recv().expect("Error synchronizing"); + // Process Finalize + first_receive.recv().expect("Error synchronizing"); + mocks::mock_time::set_time( + (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, + ); + periodic_check(second.clone()); + generate_blocks(289); + periodic_check(second.clone()); + + assert_channel_state!(second, channel_id, Closed); + } } } } -} -fn settle_timeout( - first: DlcParty, - first_send: &Sender>, - first_receive: &Receiver<()>, - second: DlcParty, - second_send: &Sender>, - second_receive: &Receiver<()>, - channel_id: ChannelId, - path: TestPath, -) { - let (settle_offer, _) = first - .lock() - .unwrap() - .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) - .expect("to be able to offer a settlement of the contract."); - - first_send - .send(Some(Message::SettleOffer(settle_offer))) - .unwrap(); - - second_receive.recv().expect("Error synchronizing"); - - if let TestPath::SettleOfferTimeout = path { - mocks::mock_time::set_time( - (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, - ); - periodic_check(first.clone()); - - assert_channel_state!(first, channel_id, Signed, Closing); - } else { - let (settle_accept, _) = second + fn settle_timeout( + first: DlcParty, + first_send: &Sender>, + first_receive: &Receiver<()>, + second: DlcParty, + second_send: &Sender>, + second_receive: &Receiver<()>, + channel_id: ChannelId, + path: TestPath, + ) { + let (settle_offer, _) = first .lock() .unwrap() - .accept_settle_offer(&channel_id) - .expect("to be able to accept a settlement offer"); + .settle_offer(&channel_id, test_utils::ACCEPT_COLLATERAL) + .expect("to be able to offer a settlement of the contract."); - second_send - .send(Some(Message::SettleAccept(settle_accept))) + first_send + .send(Some(Message::SettleOffer(settle_offer))) .unwrap(); - // Process Accept - first_receive.recv().expect("Error synchronizing"); + second_receive.recv().expect("Error synchronizing"); - if let TestPath::SettleAcceptTimeout = path { + if let TestPath::SettleOfferTimeout = path { mocks::mock_time::set_time( (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, ); - periodic_check(second.clone()); + periodic_check(first.clone()); - second + assert_channel_state!(first, channel_id, Signed, Closing); + } else { + let (settle_accept, _) = second .lock() .unwrap() - .get_store() - .get_channel(&channel_id) + .accept_settle_offer(&channel_id) + .expect("to be able to accept a settlement offer"); + + second_send + .send(Some(Message::SettleAccept(settle_accept))) .unwrap(); - assert_channel_state!(second, channel_id, Signed, Closing); - } else if let TestPath::SettleConfirmTimeout = path { - // Process Confirm - second_receive.recv().expect("Error synchronizing"); - mocks::mock_time::set_time( - (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, - ); - periodic_check(first.clone()); - assert_channel_state!(first, channel_id, Signed, Closing); + // Process Accept + first_receive.recv().expect("Error synchronizing"); + + if let TestPath::SettleAcceptTimeout = path { + mocks::mock_time::set_time( + (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, + ); + periodic_check(second.clone()); + + second + .lock() + .unwrap() + .get_store() + .get_channel(&channel_id) + .unwrap(); + assert_channel_state!(second, channel_id, Signed, Closing); + } else if let TestPath::SettleConfirmTimeout = path { + // Process Confirm + second_receive.recv().expect("Error synchronizing"); + mocks::mock_time::set_time( + (EVENT_MATURITY as u64) + dlc_manager::manager::PEER_TIMEOUT + 2, + ); + periodic_check(first.clone()); + + assert_channel_state!(first, channel_id, Signed, Closing); + } } } } diff --git a/dlc-manager/tests/manager_execution_tests.rs b/dlc-manager/tests/manager_execution_tests.rs index cc2743e1..d8e29d69 100644 --- a/dlc-manager/tests/manager_execution_tests.rs +++ b/dlc-manager/tests/manager_execution_tests.rs @@ -8,902 +8,909 @@ extern crate dlc_manager; #[allow(dead_code)] mod test_utils; -use bitcoin::Amount; -use dlc_manager::payout_curve::PayoutFunctionPiece; -use electrs_blockchain_provider::ElectrsBlockchainProvider; -use simple_wallet::SimpleWallet; -use test_utils::*; - -use bitcoin_test_utils::rpc_helpers::init_clients; -use bitcoincore_rpc::RpcApi; -use dlc_manager::contract::{numerical_descriptor::DifferenceParams, Contract}; -use dlc_manager::manager::Manager; -use dlc_manager::{Blockchain, Oracle, Storage, Wallet}; -use dlc_messages::oracle_msgs::OracleAttestation; -use dlc_messages::{AcceptDlc, OfferDlc, SignDlc}; -use dlc_messages::{CetAdaptorSignatures, Message}; -use lightning::ln::wire::Type; -use lightning::util::ser::Writeable; -use secp256k1_zkp::rand::{thread_rng, RngCore}; -use secp256k1_zkp::{ecdsa::Signature, EcdsaAdaptorSignature}; -use serde_json::{from_str, to_writer_pretty}; -use std::collections::HashMap; -use std::sync::{ - atomic::{AtomicBool, Ordering}, - mpsc::channel, - Arc, Mutex, -}; -use std::thread; - -#[derive(serde::Serialize, serde::Deserialize)] -struct TestVectorPart { - message: T, - #[cfg_attr( - feature = "use-serde", - serde( - serialize_with = "dlc_messages::serde_utils::serialize_hex", - deserialize_with = "dlc_messages::serde_utils::deserialize_hex_string" - ) - )] - serialized: Vec, -} - -#[derive(serde::Serialize, serde::Deserialize)] -struct TestVector { - offer_message: TestVectorPart, - accept_message: TestVectorPart, - sign_message: TestVectorPart, -} +#[cfg(not(feature = "async"))] +mod sync_tests { + + use crate::test_utils::*; + use bitcoin::Amount; + use dlc_manager::payout_curve::PayoutFunctionPiece; + use electrs_blockchain_provider::ElectrsBlockchainProvider; + use simple_wallet::SimpleWallet; + + use bitcoin_test_utils::rpc_helpers::init_clients; + use bitcoincore_rpc::RpcApi; + use dlc_manager::contract::{numerical_descriptor::DifferenceParams, Contract}; + use dlc_manager::manager::Manager; + use dlc_manager::{Blockchain, Oracle, Storage, Wallet}; + use dlc_messages::oracle_msgs::OracleAttestation; + use dlc_messages::{AcceptDlc, OfferDlc, SignDlc}; + use dlc_messages::{CetAdaptorSignatures, Message}; + use lightning::ln::wire::Type; + use lightning::util::ser::Writeable; + use secp256k1_zkp::rand::{thread_rng, RngCore}; + use secp256k1_zkp::{ecdsa::Signature, EcdsaAdaptorSignature}; + use serde_json::{from_str, to_writer_pretty}; + use std::collections::HashMap; + use std::sync::{ + atomic::{AtomicBool, Ordering}, + mpsc::channel, + Arc, Mutex, + }; + use std::thread; + + #[derive(serde::Serialize, serde::Deserialize)] + struct TestVectorPart { + message: T, + #[cfg_attr( + feature = "use-serde", + serde( + serialize_with = "dlc_messages::serde_utils::serialize_hex", + deserialize_with = "dlc_messages::serde_utils::deserialize_hex_string" + ) + )] + serialized: Vec, + } -fn write_message(msg_name: &str, s: T) { - if std::env::var("GENERATE_TEST_VECTOR").is_ok() { - let mut buf = Vec::new(); - s.type_id().write(&mut buf).unwrap(); - s.write(&mut buf).unwrap(); - let t = TestVectorPart { - message: s, - serialized: buf, - }; - to_writer_pretty( - &std::fs::File::create(format!("{}.json", msg_name)).unwrap(), - &t, - ) - .unwrap(); + #[derive(serde::Serialize, serde::Deserialize)] + struct TestVector { + offer_message: TestVectorPart, + accept_message: TestVectorPart, + sign_message: TestVectorPart, } -} -fn create_test_vector() { - if std::env::var("GENERATE_TEST_VECTOR").is_ok() { - let test_vector = TestVector { - offer_message: from_str(&std::fs::read_to_string("offer_message.json").unwrap()) - .unwrap(), - accept_message: from_str(&std::fs::read_to_string("accept_message.json").unwrap()) - .unwrap(), - sign_message: from_str(&std::fs::read_to_string("sign_message.json").unwrap()).unwrap(), - }; - let file_name = std::env::var("TEST_VECTOR_OUTPUT_NAME") - .unwrap_or_else(|_| "test_vector.json".to_string()); - to_writer_pretty(std::fs::File::create(file_name).unwrap(), &test_vector).unwrap(); + fn write_message(msg_name: &str, s: T) { + if std::env::var("GENERATE_TEST_VECTOR").is_ok() { + let mut buf = Vec::new(); + s.type_id().write(&mut buf).unwrap(); + s.write(&mut buf).unwrap(); + let t = TestVectorPart { + message: s, + serialized: buf, + }; + to_writer_pretty( + &std::fs::File::create(format!("{}.json", msg_name)).unwrap(), + &t, + ) + .unwrap(); + } } -} -macro_rules! periodic_check { - ($d:expr, $id:expr, $p:ident) => { - $d.lock() - .unwrap() - .periodic_check(true) - .expect("Periodic check error"); + fn create_test_vector() { + if std::env::var("GENERATE_TEST_VECTOR").is_ok() { + let test_vector = TestVector { + offer_message: from_str(&std::fs::read_to_string("offer_message.json").unwrap()) + .unwrap(), + accept_message: from_str(&std::fs::read_to_string("accept_message.json").unwrap()) + .unwrap(), + sign_message: from_str(&std::fs::read_to_string("sign_message.json").unwrap()) + .unwrap(), + }; + let file_name = std::env::var("TEST_VECTOR_OUTPUT_NAME") + .unwrap_or_else(|_| "test_vector.json".to_string()); + to_writer_pretty(std::fs::File::create(file_name).unwrap(), &test_vector).unwrap(); + } + } - assert_contract_state!($d, $id, $p); - }; -} + macro_rules! periodic_check { + ($d:expr, $id:expr, $p:ident) => { + $d.lock() + .unwrap() + .periodic_check(true) + .expect("Periodic check error"); -fn numerical_common( - nb_oracles: usize, - threshold: usize, - payout_function_pieces_cb: F, - difference_params: Option, - manual_close: bool, -) where - F: Fn(usize) -> Vec, -{ - let oracle_numeric_infos = get_same_num_digits_oracle_numeric_infos(nb_oracles); - let with_diff = difference_params.is_some(); - let contract_descriptor = get_numerical_contract_descriptor( - oracle_numeric_infos.clone(), - payout_function_pieces_cb(*oracle_numeric_infos.nb_digits.iter().min().unwrap()), - difference_params, - ); - manager_execution_test( - get_numerical_test_params( - &oracle_numeric_infos, - threshold, - with_diff, - contract_descriptor, - false, - ), - TestPath::Close, - manual_close, - ); -} + assert_contract_state!($d, $id, $p); + }; + } -fn numerical_polynomial_common( - nb_oracles: usize, - threshold: usize, - difference_params: Option, - manual_close: bool, -) { - numerical_common( - nb_oracles, - threshold, - get_polynomial_payout_curve_pieces, - difference_params, - manual_close, - ); -} + fn numerical_common( + nb_oracles: usize, + threshold: usize, + payout_function_pieces_cb: F, + difference_params: Option, + manual_close: bool, + ) where + F: Fn(usize) -> Vec, + { + let oracle_numeric_infos = get_same_num_digits_oracle_numeric_infos(nb_oracles); + let with_diff = difference_params.is_some(); + let contract_descriptor = get_numerical_contract_descriptor( + oracle_numeric_infos.clone(), + payout_function_pieces_cb(*oracle_numeric_infos.nb_digits.iter().min().unwrap()), + difference_params, + ); + manager_execution_test( + get_numerical_test_params( + &oracle_numeric_infos, + threshold, + with_diff, + contract_descriptor, + false, + ), + TestPath::Close, + manual_close, + ); + } -fn numerical_common_diff_nb_digits( - nb_oracles: usize, - threshold: usize, - difference_params: Option, - use_max_value: bool, - manual_close: bool, -) { - let with_diff = difference_params.is_some(); - let oracle_numeric_infos = get_variable_oracle_numeric_infos( - &(0..nb_oracles) - .map(|_| (NB_DIGITS + (thread_rng().next_u32() % 6)) as usize) - .collect::>(), - ); - let contract_descriptor = get_numerical_contract_descriptor( - oracle_numeric_infos.clone(), - get_polynomial_payout_curve_pieces(oracle_numeric_infos.get_min_nb_digits()), - difference_params, - ); - - manager_execution_test( - get_numerical_test_params( - &oracle_numeric_infos, + fn numerical_polynomial_common( + nb_oracles: usize, + threshold: usize, + difference_params: Option, + manual_close: bool, + ) { + numerical_common( + nb_oracles, threshold, - with_diff, - contract_descriptor, - use_max_value, - ), - TestPath::Close, - manual_close, - ); -} + get_polynomial_payout_curve_pieces, + difference_params, + manual_close, + ); + } -#[derive(Eq, PartialEq, Clone)] -enum TestPath { - Close, - Refund, - BadAcceptCetSignature, - BadAcceptRefundSignature, - BadSignCetSignature, - BadSignRefundSignature, -} + fn numerical_common_diff_nb_digits( + nb_oracles: usize, + threshold: usize, + difference_params: Option, + use_max_value: bool, + manual_close: bool, + ) { + let with_diff = difference_params.is_some(); + let oracle_numeric_infos = get_variable_oracle_numeric_infos( + &(0..nb_oracles) + .map(|_| (NB_DIGITS + (thread_rng().next_u32() % 6)) as usize) + .collect::>(), + ); + let contract_descriptor = get_numerical_contract_descriptor( + oracle_numeric_infos.clone(), + get_polynomial_payout_curve_pieces(oracle_numeric_infos.get_min_nb_digits()), + difference_params, + ); + + manager_execution_test( + get_numerical_test_params( + &oracle_numeric_infos, + threshold, + with_diff, + contract_descriptor, + use_max_value, + ), + TestPath::Close, + manual_close, + ); + } -#[test] -#[ignore] -fn single_oracle_numerical_test() { - numerical_polynomial_common(1, 1, None, false); -} + #[derive(Eq, PartialEq, Clone)] + enum TestPath { + Close, + Refund, + BadAcceptCetSignature, + BadAcceptRefundSignature, + BadSignCetSignature, + BadSignRefundSignature, + } -#[test] -#[ignore] -fn single_oracle_numerical_manual_test() { - numerical_polynomial_common(1, 1, None, true); -} + #[test] + #[ignore] + fn single_oracle_numerical_test() { + numerical_polynomial_common(1, 1, None, false); + } -#[test] -#[ignore] -fn single_oracle_numerical_hyperbola_test() { - numerical_common(1, 1, get_hyperbola_payout_curve_pieces, None, false); -} + #[test] + #[ignore] + fn single_oracle_numerical_manual_test() { + numerical_polynomial_common(1, 1, None, true); + } -#[test] -#[ignore] -fn three_of_three_oracle_numerical_test() { - numerical_polynomial_common(3, 3, None, false); -} + #[test] + #[ignore] + fn single_oracle_numerical_hyperbola_test() { + numerical_common(1, 1, get_hyperbola_payout_curve_pieces, None, false); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_test() { - numerical_polynomial_common(5, 2, None, false); -} + #[test] + #[ignore] + fn three_of_three_oracle_numerical_test() { + numerical_polynomial_common(3, 3, None, false); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_manual_test() { - numerical_polynomial_common(5, 2, None, true); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_test() { + numerical_polynomial_common(5, 2, None, false); + } -#[test] -#[ignore] -fn three_of_three_oracle_numerical_with_diff_test() { - numerical_polynomial_common(3, 3, Some(get_difference_params()), false); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_manual_test() { + numerical_polynomial_common(5, 2, None, true); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_with_diff_test() { - numerical_polynomial_common(5, 2, Some(get_difference_params()), false); -} + #[test] + #[ignore] + fn three_of_three_oracle_numerical_with_diff_test() { + numerical_polynomial_common(3, 3, Some(get_difference_params()), false); + } -#[test] -#[ignore] -fn three_of_five_oracle_numerical_with_diff_test() { - numerical_polynomial_common(5, 3, Some(get_difference_params()), false); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_with_diff_test() { + numerical_polynomial_common(5, 2, Some(get_difference_params()), false); + } -#[test] -#[ignore] -fn three_of_five_oracle_numerical_with_diff_manual_test() { - numerical_polynomial_common(5, 3, Some(get_difference_params()), true); -} + #[test] + #[ignore] + fn three_of_five_oracle_numerical_with_diff_test() { + numerical_polynomial_common(5, 3, Some(get_difference_params()), false); + } -#[test] -#[ignore] -fn enum_single_oracle_test() { - manager_execution_test(get_enum_test_params(1, 1, None), TestPath::Close, false); -} + #[test] + #[ignore] + fn three_of_five_oracle_numerical_with_diff_manual_test() { + numerical_polynomial_common(5, 3, Some(get_difference_params()), true); + } -#[test] -#[ignore] -fn enum_single_oracle_manual_test() { - manager_execution_test(get_enum_test_params(1, 1, None), TestPath::Close, true); -} + #[test] + #[ignore] + fn enum_single_oracle_test() { + manager_execution_test(get_enum_test_params(1, 1, None), TestPath::Close, false); + } -#[test] -#[ignore] -fn enum_3_of_3_test() { - manager_execution_test(get_enum_test_params(3, 3, None), TestPath::Close, false); -} + #[test] + #[ignore] + fn enum_single_oracle_manual_test() { + manager_execution_test(get_enum_test_params(1, 1, None), TestPath::Close, true); + } -#[test] -#[ignore] -fn enum_3_of_3_manual_test() { - manager_execution_test(get_enum_test_params(3, 3, None), TestPath::Close, true); -} + #[test] + #[ignore] + fn enum_3_of_3_test() { + manager_execution_test(get_enum_test_params(3, 3, None), TestPath::Close, false); + } -#[test] -#[ignore] -fn enum_3_of_5_test() { - manager_execution_test(get_enum_test_params(5, 3, None), TestPath::Close, false); -} + #[test] + #[ignore] + fn enum_3_of_3_manual_test() { + manager_execution_test(get_enum_test_params(3, 3, None), TestPath::Close, true); + } -#[test] -#[ignore] -fn enum_3_of_5_manual_test() { - manager_execution_test(get_enum_test_params(5, 3, None), TestPath::Close, true); -} + #[test] + #[ignore] + fn enum_3_of_5_test() { + manager_execution_test(get_enum_test_params(5, 3, None), TestPath::Close, false); + } -#[test] -#[ignore] -fn enum_and_numerical_with_diff_3_of_5_test() { - manager_execution_test( - get_enum_and_numerical_test_params(5, 3, true, Some(get_difference_params())), - TestPath::Close, - false, - ); -} + #[test] + #[ignore] + fn enum_3_of_5_manual_test() { + manager_execution_test(get_enum_test_params(5, 3, None), TestPath::Close, true); + } -#[test] -#[ignore] -fn enum_and_numerical_with_diff_3_of_5_manual_test() { - manager_execution_test( - get_enum_and_numerical_test_params(5, 3, true, Some(get_difference_params())), - TestPath::Close, - true, - ); -} + #[test] + #[ignore] + fn enum_and_numerical_with_diff_3_of_5_test() { + manager_execution_test( + get_enum_and_numerical_test_params(5, 3, true, Some(get_difference_params())), + TestPath::Close, + false, + ); + } -#[test] -#[ignore] -fn enum_and_numerical_with_diff_5_of_5_test() { - manager_execution_test( - get_enum_and_numerical_test_params(5, 5, true, Some(get_difference_params())), - TestPath::Close, - false, - ); -} + #[test] + #[ignore] + fn enum_and_numerical_with_diff_3_of_5_manual_test() { + manager_execution_test( + get_enum_and_numerical_test_params(5, 3, true, Some(get_difference_params())), + TestPath::Close, + true, + ); + } -#[test] -#[ignore] -fn enum_and_numerical_with_diff_5_of_5_manual_test() { - manager_execution_test( - get_enum_and_numerical_test_params(5, 5, true, Some(get_difference_params())), - TestPath::Close, - true, - ); -} + #[test] + #[ignore] + fn enum_and_numerical_with_diff_5_of_5_test() { + manager_execution_test( + get_enum_and_numerical_test_params(5, 5, true, Some(get_difference_params())), + TestPath::Close, + false, + ); + } -#[test] -#[ignore] -fn enum_and_numerical_3_of_5_test() { - manager_execution_test( - get_enum_and_numerical_test_params(5, 3, false, None), - TestPath::Close, - false, - ); -} + #[test] + #[ignore] + fn enum_and_numerical_with_diff_5_of_5_manual_test() { + manager_execution_test( + get_enum_and_numerical_test_params(5, 5, true, Some(get_difference_params())), + TestPath::Close, + true, + ); + } -#[test] -#[ignore] -fn enum_and_numerical_3_of_5_manual_test() { - manager_execution_test( - get_enum_and_numerical_test_params(5, 3, false, None), - TestPath::Close, - true, - ); -} + #[test] + #[ignore] + fn enum_and_numerical_3_of_5_test() { + manager_execution_test( + get_enum_and_numerical_test_params(5, 3, false, None), + TestPath::Close, + false, + ); + } -#[test] -#[ignore] -fn enum_and_numerical_5_of_5_test() { - manager_execution_test( - get_enum_and_numerical_test_params(5, 5, false, None), - TestPath::Close, - false, - ); -} + #[test] + #[ignore] + fn enum_and_numerical_3_of_5_manual_test() { + manager_execution_test( + get_enum_and_numerical_test_params(5, 3, false, None), + TestPath::Close, + true, + ); + } -#[test] -#[ignore] -fn enum_and_numerical_5_of_5_manual_test() { - manager_execution_test( - get_enum_and_numerical_test_params(5, 5, false, None), - TestPath::Close, - true, - ); -} + #[test] + #[ignore] + fn enum_and_numerical_5_of_5_test() { + manager_execution_test( + get_enum_and_numerical_test_params(5, 5, false, None), + TestPath::Close, + false, + ); + } -#[test] -#[ignore] -fn enum_single_oracle_refund_test() { - manager_execution_test( - get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), - TestPath::Refund, - false, - ); -} + #[test] + #[ignore] + fn enum_and_numerical_5_of_5_manual_test() { + manager_execution_test( + get_enum_and_numerical_test_params(5, 5, false, None), + TestPath::Close, + true, + ); + } -#[test] -#[ignore] -fn enum_single_oracle_refund_manual_test() { - manager_execution_test( - get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), - TestPath::Refund, - true, - ); -} + #[test] + #[ignore] + fn enum_single_oracle_refund_test() { + manager_execution_test( + get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), + TestPath::Refund, + false, + ); + } -#[test] -#[ignore] -fn enum_single_oracle_bad_accept_cet_sig_test() { - manager_execution_test( - get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), - TestPath::BadAcceptCetSignature, - false, - ); -} + #[test] + #[ignore] + fn enum_single_oracle_refund_manual_test() { + manager_execution_test( + get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), + TestPath::Refund, + true, + ); + } -#[test] -#[ignore] -fn enum_single_oracle_bad_accept_refund_sig_test() { - manager_execution_test( - get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), - TestPath::BadAcceptRefundSignature, - false, - ); -} + #[test] + #[ignore] + fn enum_single_oracle_bad_accept_cet_sig_test() { + manager_execution_test( + get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), + TestPath::BadAcceptCetSignature, + false, + ); + } -#[test] -#[ignore] -fn enum_single_oracle_bad_sign_cet_sig_test() { - manager_execution_test( - get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), - TestPath::BadSignCetSignature, - false, - ); -} + #[test] + #[ignore] + fn enum_single_oracle_bad_accept_refund_sig_test() { + manager_execution_test( + get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), + TestPath::BadAcceptRefundSignature, + false, + ); + } -#[test] -#[ignore] -fn enum_single_oracle_bad_sign_refund_sig_test() { - manager_execution_test( - get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), - TestPath::BadSignRefundSignature, - false, - ); -} + #[test] + #[ignore] + fn enum_single_oracle_bad_sign_cet_sig_test() { + manager_execution_test( + get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), + TestPath::BadSignCetSignature, + false, + ); + } -#[test] -#[ignore] -fn two_of_two_oracle_numerical_diff_nb_digits_test() { - numerical_common_diff_nb_digits(2, 2, None, false, false); -} + #[test] + #[ignore] + fn enum_single_oracle_bad_sign_refund_sig_test() { + manager_execution_test( + get_enum_test_params(1, 1, Some(get_enum_oracles(1, 0))), + TestPath::BadSignRefundSignature, + false, + ); + } -#[test] -#[ignore] -fn two_of_two_oracle_numerical_diff_nb_digits_manual_test() { - numerical_common_diff_nb_digits(2, 2, None, false, true); -} + #[test] + #[ignore] + fn two_of_two_oracle_numerical_diff_nb_digits_test() { + numerical_common_diff_nb_digits(2, 2, None, false, false); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_diff_nb_digits_test() { - numerical_common_diff_nb_digits(5, 2, None, false, false); -} + #[test] + #[ignore] + fn two_of_two_oracle_numerical_diff_nb_digits_manual_test() { + numerical_common_diff_nb_digits(2, 2, None, false, true); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_diff_nb_digits_manual_test() { - numerical_common_diff_nb_digits(5, 2, None, false, true); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_diff_nb_digits_test() { + numerical_common_diff_nb_digits(5, 2, None, false, false); + } -#[test] -#[ignore] -fn two_of_two_oracle_numerical_with_diff_diff_nb_digits_test() { - numerical_common_diff_nb_digits(2, 2, Some(get_difference_params()), false, false); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_diff_nb_digits_manual_test() { + numerical_common_diff_nb_digits(5, 2, None, false, true); + } -#[test] -#[ignore] -fn three_of_three_oracle_numerical_with_diff_diff_nb_digits_test() { - numerical_common_diff_nb_digits(3, 3, Some(get_difference_params()), false, false); -} + #[test] + #[ignore] + fn two_of_two_oracle_numerical_with_diff_diff_nb_digits_test() { + numerical_common_diff_nb_digits(2, 2, Some(get_difference_params()), false, false); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_with_diff_diff_nb_digits_test() { - numerical_common_diff_nb_digits(5, 2, Some(get_difference_params()), false, false); -} + #[test] + #[ignore] + fn three_of_three_oracle_numerical_with_diff_diff_nb_digits_test() { + numerical_common_diff_nb_digits(3, 3, Some(get_difference_params()), false, false); + } -#[test] -#[ignore] -fn two_of_two_oracle_numerical_with_diff_diff_nb_digits_max_value_test() { - numerical_common_diff_nb_digits(2, 2, Some(get_difference_params()), true, false); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_with_diff_diff_nb_digits_test() { + numerical_common_diff_nb_digits(5, 2, Some(get_difference_params()), false, false); + } -#[test] -#[ignore] -fn two_of_three_oracle_numerical_with_diff_diff_nb_digits_max_value_test() { - numerical_common_diff_nb_digits(3, 2, Some(get_difference_params()), true, false); -} + #[test] + #[ignore] + fn two_of_two_oracle_numerical_with_diff_diff_nb_digits_max_value_test() { + numerical_common_diff_nb_digits(2, 2, Some(get_difference_params()), true, false); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_with_diff_diff_nb_digits_max_value_test() { - numerical_common_diff_nb_digits(5, 2, Some(get_difference_params()), true, false); -} + #[test] + #[ignore] + fn two_of_three_oracle_numerical_with_diff_diff_nb_digits_max_value_test() { + numerical_common_diff_nb_digits(3, 2, Some(get_difference_params()), true, false); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_with_diff_diff_nb_digits_max_value_manual_test() { - numerical_common_diff_nb_digits(5, 2, Some(get_difference_params()), true, true); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_with_diff_diff_nb_digits_max_value_test() { + numerical_common_diff_nb_digits(5, 2, Some(get_difference_params()), true, false); + } -#[test] -#[ignore] -fn two_of_two_oracle_numerical_diff_nb_digits_max_value_test() { - numerical_common_diff_nb_digits(2, 2, None, true, false); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_with_diff_diff_nb_digits_max_value_manual_test() { + numerical_common_diff_nb_digits(5, 2, Some(get_difference_params()), true, true); + } -#[test] -#[ignore] -fn two_of_three_oracle_numerical_diff_nb_digits_max_value_test() { - numerical_common_diff_nb_digits(3, 2, None, true, false); -} + #[test] + #[ignore] + fn two_of_two_oracle_numerical_diff_nb_digits_max_value_test() { + numerical_common_diff_nb_digits(2, 2, None, true, false); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_diff_nb_digits_max_value_test() { - numerical_common_diff_nb_digits(5, 2, None, true, false); -} + #[test] + #[ignore] + fn two_of_three_oracle_numerical_diff_nb_digits_max_value_test() { + numerical_common_diff_nb_digits(3, 2, None, true, false); + } -#[test] -#[ignore] -fn two_of_five_oracle_numerical_diff_nb_digits_max_value_manual_test() { - numerical_common_diff_nb_digits(5, 2, None, true, true); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_diff_nb_digits_max_value_test() { + numerical_common_diff_nb_digits(5, 2, None, true, false); + } -fn alter_adaptor_sig(input: &mut CetAdaptorSignatures) { - let sig_index = thread_rng().next_u32() as usize % input.ecdsa_adaptor_signatures.len(); - - let mut copy = input.ecdsa_adaptor_signatures[sig_index] - .signature - .as_ref() - .to_vec(); - let i = thread_rng().next_u32() as usize % secp256k1_zkp::ffi::ECDSA_ADAPTOR_SIGNATURE_LENGTH; - copy[i] = copy[i].checked_add(1).unwrap_or(0); - input.ecdsa_adaptor_signatures[sig_index].signature = - EcdsaAdaptorSignature::from_slice(©).unwrap(); -} + #[test] + #[ignore] + fn two_of_five_oracle_numerical_diff_nb_digits_max_value_manual_test() { + numerical_common_diff_nb_digits(5, 2, None, true, true); + } -fn alter_refund_sig(refund_signature: &Signature) -> Signature { - let mut copy = refund_signature.serialize_compact(); - let i = thread_rng().next_u32() as usize % secp256k1_zkp::constants::COMPACT_SIGNATURE_SIZE; - copy[i] = copy[i].checked_add(1).unwrap_or(0); - Signature::from_compact(©).unwrap() -} + fn alter_adaptor_sig(input: &mut CetAdaptorSignatures) { + let sig_index = thread_rng().next_u32() as usize % input.ecdsa_adaptor_signatures.len(); + + let mut copy = input.ecdsa_adaptor_signatures[sig_index] + .signature + .as_ref() + .to_vec(); + let i = + thread_rng().next_u32() as usize % secp256k1_zkp::ffi::ECDSA_ADAPTOR_SIGNATURE_LENGTH; + copy[i] = copy[i].checked_add(1).unwrap_or(0); + input.ecdsa_adaptor_signatures[sig_index].signature = + EcdsaAdaptorSignature::from_slice(©).unwrap(); + } -fn get_attestations(test_params: &TestParams) -> Vec<(usize, OracleAttestation)> { - for contract_info in test_params.contract_input.contract_infos.iter() { - let attestations: Vec<_> = contract_info - .oracles - .public_keys - .iter() - .enumerate() - .filter_map(|(i, pk)| { - let oracle = test_params - .oracles - .iter() - .find(|x| x.get_public_key() == *pk); - - oracle - .and_then(|o| o.get_attestation(&contract_info.oracles.event_id).ok()) - .map(|a| (i, a)) - }) - .collect(); - if attestations.len() >= contract_info.oracles.threshold as usize { - return attestations; + fn alter_refund_sig(refund_signature: &Signature) -> Signature { + let mut copy = refund_signature.serialize_compact(); + let i = thread_rng().next_u32() as usize % secp256k1_zkp::constants::COMPACT_SIGNATURE_SIZE; + copy[i] = copy[i].checked_add(1).unwrap_or(0); + Signature::from_compact(©).unwrap() + } + + fn get_attestations(test_params: &TestParams) -> Vec<(usize, OracleAttestation)> { + for contract_info in test_params.contract_input.contract_infos.iter() { + let attestations: Vec<_> = contract_info + .oracles + .public_keys + .iter() + .enumerate() + .filter_map(|(i, pk)| { + let oracle = test_params + .oracles + .iter() + .find(|x| x.get_public_key() == *pk); + + oracle + .and_then(|o| o.get_attestation(&contract_info.oracles.event_id).ok()) + .map(|a| (i, a)) + }) + .collect(); + if attestations.len() >= contract_info.oracles.threshold as usize { + return attestations; + } } + + panic!("No attestations found"); } - panic!("No attestations found"); -} + fn manager_execution_test(test_params: TestParams, path: TestPath, manual_close: bool) { + env_logger::try_init().ok(); + let (alice_send, bob_receive) = channel::>(); + let (bob_send, alice_receive) = channel::>(); + let (sync_send, sync_receive) = channel::<()>(); + let alice_sync_send = sync_send.clone(); + let bob_sync_send = sync_send; + let (_, _, sink_rpc) = init_clients(); + + let mut alice_oracles = HashMap::with_capacity(1); + let mut bob_oracles = HashMap::with_capacity(1); + + for oracle in test_params.oracles.clone() { + let oracle = Arc::new(oracle); + alice_oracles.insert(oracle.get_public_key(), Arc::clone(&oracle)); + bob_oracles.insert(oracle.get_public_key(), Arc::clone(&oracle)); + } + + let alice_store = Arc::new(mocks::memory_storage_provider::MemoryStorage::new()); + let bob_store = Arc::new(mocks::memory_storage_provider::MemoryStorage::new()); + let mock_time = Arc::new(mocks::mock_time::MockTime {}); + mocks::mock_time::set_time((EVENT_MATURITY as u64) - 1); + + let electrs = Arc::new(ElectrsBlockchainProvider::new( + "http://localhost:3004/".to_string(), + bitcoin::Network::Regtest, + )); + + let alice_wallet = Arc::new(SimpleWallet::new( + electrs.clone(), + alice_store.clone(), + bitcoin::Network::Regtest, + )); + + let bob_wallet = Arc::new(SimpleWallet::new( + electrs.clone(), + bob_store.clone(), + bitcoin::Network::Regtest, + )); + + let alice_fund_address = alice_wallet.get_new_address().unwrap(); + let bob_fund_address = bob_wallet.get_new_address().unwrap(); -fn manager_execution_test(test_params: TestParams, path: TestPath, manual_close: bool) { - env_logger::try_init().ok(); - let (alice_send, bob_receive) = channel::>(); - let (bob_send, alice_receive) = channel::>(); - let (sync_send, sync_receive) = channel::<()>(); - let alice_sync_send = sync_send.clone(); - let bob_sync_send = sync_send; - let (_, _, sink_rpc) = init_clients(); - - let mut alice_oracles = HashMap::with_capacity(1); - let mut bob_oracles = HashMap::with_capacity(1); - - for oracle in test_params.oracles.clone() { - let oracle = Arc::new(oracle); - alice_oracles.insert(oracle.get_public_key(), Arc::clone(&oracle)); - bob_oracles.insert(oracle.get_public_key(), Arc::clone(&oracle)); - } - - let alice_store = Arc::new(mocks::memory_storage_provider::MemoryStorage::new()); - let bob_store = Arc::new(mocks::memory_storage_provider::MemoryStorage::new()); - let mock_time = Arc::new(mocks::mock_time::MockTime {}); - mocks::mock_time::set_time((EVENT_MATURITY as u64) - 1); - - let electrs = Arc::new(ElectrsBlockchainProvider::new( - "http://localhost:3004/".to_string(), - bitcoin::Network::Regtest, - )); - - let alice_wallet = Arc::new(SimpleWallet::new( - electrs.clone(), - alice_store.clone(), - bitcoin::Network::Regtest, - )); - - let bob_wallet = Arc::new(SimpleWallet::new( - electrs.clone(), - bob_store.clone(), - bitcoin::Network::Regtest, - )); - - let alice_fund_address = alice_wallet.get_new_address().unwrap(); - let bob_fund_address = bob_wallet.get_new_address().unwrap(); - - sink_rpc - .send_to_address( - &alice_fund_address, - Amount::from_btc(2.0).unwrap(), - None, - None, - None, - None, - None, - None, - ) - .unwrap(); - - sink_rpc - .send_to_address( - &bob_fund_address, - Amount::from_btc(2.0).unwrap(), - None, - None, - None, - None, - None, - None, - ) - .unwrap(); - - let generate_blocks = |nb_blocks: u64| { - let prev_blockchain_height = electrs.get_blockchain_height().unwrap(); - - let sink_address = sink_rpc - .get_new_address(None, None) - .expect("RPC Error") - .assume_checked(); sink_rpc - .generate_to_address(nb_blocks, &sink_address) - .expect("RPC Error"); - - // Wait for electrs to have processed the new blocks - let mut cur_blockchain_height = prev_blockchain_height; - while cur_blockchain_height < prev_blockchain_height + nb_blocks { - std::thread::sleep(std::time::Duration::from_millis(200)); - cur_blockchain_height = electrs.get_blockchain_height().unwrap(); - } - }; + .send_to_address( + &alice_fund_address, + Amount::from_btc(2.0).unwrap(), + None, + None, + None, + None, + None, + None, + ) + .unwrap(); - generate_blocks(6); - - refresh_wallet(&alice_wallet, 200000000); - refresh_wallet(&bob_wallet, 200000000); - - let alice_manager = Arc::new(Mutex::new( - Manager::new( - Arc::clone(&alice_wallet), - Arc::clone(&alice_wallet), - Arc::clone(&electrs), - alice_store, - alice_oracles, - Arc::clone(&mock_time), - Arc::clone(&electrs), - ) - .unwrap(), - )); - - let alice_manager_loop = Arc::clone(&alice_manager); - let alice_manager_send = Arc::clone(&alice_manager); - - let bob_manager = Arc::new(Mutex::new( - Manager::new( - Arc::clone(&bob_wallet), - Arc::clone(&bob_wallet), - Arc::clone(&electrs), - bob_store, - bob_oracles, - Arc::clone(&mock_time), - Arc::clone(&electrs), - ) - .unwrap(), - )); - - let bob_manager_loop = Arc::clone(&bob_manager); - let bob_manager_send = Arc::clone(&bob_manager); - let alice_send_loop = alice_send.clone(); - let bob_send_loop = bob_send.clone(); - - let alice_expect_error = Arc::new(AtomicBool::new(false)); - let bob_expect_error = Arc::new(AtomicBool::new(false)); - - let alice_expect_error_loop = alice_expect_error.clone(); - let bob_expect_error_loop = bob_expect_error.clone(); - - let path_copy = path.clone(); - let alter_sign = move |msg| match msg { - Message::Sign(mut sign_dlc) => { - match path_copy { - TestPath::BadSignCetSignature => { - alter_adaptor_sig(&mut sign_dlc.cet_adaptor_signatures) - } - TestPath::BadSignRefundSignature => { - sign_dlc.refund_signature = alter_refund_sig(&sign_dlc.refund_signature); + sink_rpc + .send_to_address( + &bob_fund_address, + Amount::from_btc(2.0).unwrap(), + None, + None, + None, + None, + None, + None, + ) + .unwrap(); + + let generate_blocks = |nb_blocks: u64| { + let prev_blockchain_height = electrs.get_blockchain_height().unwrap(); + + let sink_address = sink_rpc + .get_new_address(None, None) + .expect("RPC Error") + .assume_checked(); + sink_rpc + .generate_to_address(nb_blocks, &sink_address) + .expect("RPC Error"); + + // Wait for electrs to have processed the new blocks + let mut cur_blockchain_height = prev_blockchain_height; + while cur_blockchain_height < prev_blockchain_height + nb_blocks { + std::thread::sleep(std::time::Duration::from_millis(200)); + cur_blockchain_height = electrs.get_blockchain_height().unwrap(); + } + }; + + generate_blocks(6); + + refresh_wallet(&alice_wallet, 200000000); + refresh_wallet(&bob_wallet, 200000000); + + let alice_manager = Arc::new(Mutex::new( + Manager::new( + Arc::clone(&alice_wallet), + Arc::clone(&alice_wallet), + Arc::clone(&electrs), + alice_store, + alice_oracles, + Arc::clone(&mock_time), + Arc::clone(&electrs), + ) + .unwrap(), + )); + + let alice_manager_loop = Arc::clone(&alice_manager); + let alice_manager_send = Arc::clone(&alice_manager); + + let bob_manager = Arc::new(Mutex::new( + Manager::new( + Arc::clone(&bob_wallet), + Arc::clone(&bob_wallet), + Arc::clone(&electrs), + bob_store, + bob_oracles, + Arc::clone(&mock_time), + Arc::clone(&electrs), + ) + .unwrap(), + )); + + let bob_manager_loop = Arc::clone(&bob_manager); + let bob_manager_send = Arc::clone(&bob_manager); + let alice_send_loop = alice_send.clone(); + let bob_send_loop = bob_send.clone(); + + let alice_expect_error = Arc::new(AtomicBool::new(false)); + let bob_expect_error = Arc::new(AtomicBool::new(false)); + + let alice_expect_error_loop = alice_expect_error.clone(); + let bob_expect_error_loop = bob_expect_error.clone(); + + let path_copy = path.clone(); + let alter_sign = move |msg| match msg { + Message::Sign(mut sign_dlc) => { + match path_copy { + TestPath::BadSignCetSignature => { + alter_adaptor_sig(&mut sign_dlc.cet_adaptor_signatures) + } + TestPath::BadSignRefundSignature => { + sign_dlc.refund_signature = alter_refund_sig(&sign_dlc.refund_signature); + } + _ => {} } - _ => {} + Some(Message::Sign(sign_dlc)) } - Some(Message::Sign(sign_dlc)) - } - _ => Some(msg), - }; + _ => Some(msg), + }; - let msg_callback = |msg: &Message| { - if let Message::Sign(s) = msg { - write_message("sign_message", s.clone()); - } - }; + let msg_callback = |msg: &Message| { + if let Message::Sign(s) = msg { + write_message("sign_message", s.clone()); + } + }; - let alice_handle = receive_loop!( - alice_receive, - alice_manager_loop, - alice_send_loop, - alice_expect_error_loop, - alice_sync_send, - Some, - msg_callback - ); - - let bob_handle = receive_loop!( - bob_receive, - bob_manager_loop, - bob_send_loop, - bob_expect_error_loop, - bob_sync_send, - alter_sign, - msg_callback - ); - - let offer_msg = bob_manager_send - .lock() - .unwrap() - .send_offer( - &test_params.contract_input, - "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" - .parse() - .unwrap(), - ) - .expect("Send offer error"); - - write_message("offer_message", offer_msg.clone()); - let temporary_contract_id = offer_msg.temporary_contract_id; - bob_send.send(Some(Message::Offer(offer_msg))).unwrap(); - - assert_contract_state!(bob_manager_send, temporary_contract_id, Offered); - - sync_receive.recv().expect("Error synchronizing"); - - assert_contract_state!(alice_manager_send, temporary_contract_id, Offered); - - let (contract_id, _, mut accept_msg) = alice_manager_send - .lock() - .unwrap() - .accept_contract_offer(&temporary_contract_id) - .expect("Error accepting contract offer"); - - write_message("accept_message", accept_msg.clone()); - - assert_contract_state!(alice_manager_send, contract_id, Accepted); - - match path { - TestPath::BadAcceptCetSignature | TestPath::BadAcceptRefundSignature => { - match path { - TestPath::BadAcceptCetSignature => { - alter_adaptor_sig(&mut accept_msg.cet_adaptor_signatures) - } - TestPath::BadAcceptRefundSignature => { - accept_msg.refund_signature = alter_refund_sig(&accept_msg.refund_signature); - } - _ => {} - }; - bob_expect_error.store(true, Ordering::Relaxed); - alice_send.send(Some(Message::Accept(accept_msg))).unwrap(); - sync_receive.recv().expect("Error synchronizing"); - assert_contract_state!(bob_manager_send, temporary_contract_id, FailedAccept); - } - TestPath::BadSignCetSignature | TestPath::BadSignRefundSignature => { - alice_expect_error.store(true, Ordering::Relaxed); - alice_send.send(Some(Message::Accept(accept_msg))).unwrap(); - // Bob receives accept message - sync_receive.recv().expect("Error synchronizing"); - // Alice receives sign message - sync_receive.recv().expect("Error synchronizing"); - assert_contract_state!(alice_manager_send, contract_id, FailedSign); - } - TestPath::Close | TestPath::Refund => { - alice_send.send(Some(Message::Accept(accept_msg))).unwrap(); - sync_receive.recv().expect("Error synchronizing"); + let alice_handle = receive_loop!( + alice_receive, + alice_manager_loop, + alice_send_loop, + alice_expect_error_loop, + alice_sync_send, + Some, + msg_callback + ); + + let bob_handle = receive_loop!( + bob_receive, + bob_manager_loop, + bob_send_loop, + bob_expect_error_loop, + bob_sync_send, + alter_sign, + msg_callback + ); + + let offer_msg = bob_manager_send + .lock() + .unwrap() + .send_offer( + &test_params.contract_input, + "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166" + .parse() + .unwrap(), + ) + .expect("Send offer error"); - assert_contract_state!(bob_manager_send, contract_id, Signed); + write_message("offer_message", offer_msg.clone()); + let temporary_contract_id = offer_msg.temporary_contract_id; + bob_send.send(Some(Message::Offer(offer_msg))).unwrap(); - // Should not change state and should not error - periodic_check!(bob_manager_send, contract_id, Signed); + assert_contract_state!(bob_manager_send, temporary_contract_id, Offered); - sync_receive.recv().expect("Error synchronizing"); + sync_receive.recv().expect("Error synchronizing"); - assert_contract_state!(alice_manager_send, contract_id, Signed); + assert_contract_state!(alice_manager_send, temporary_contract_id, Offered); - generate_blocks(6); + let (contract_id, _, mut accept_msg) = alice_manager_send + .lock() + .unwrap() + .accept_contract_offer(&temporary_contract_id) + .expect("Error accepting contract offer"); + + write_message("accept_message", accept_msg.clone()); - periodic_check!(alice_manager_send, contract_id, Confirmed); - periodic_check!(bob_manager_send, contract_id, Confirmed); + assert_contract_state!(alice_manager_send, contract_id, Accepted); - if !manual_close { - mocks::mock_time::set_time((EVENT_MATURITY as u64) + 1); + match path { + TestPath::BadAcceptCetSignature | TestPath::BadAcceptRefundSignature => { + match path { + TestPath::BadAcceptCetSignature => { + alter_adaptor_sig(&mut accept_msg.cet_adaptor_signatures) + } + TestPath::BadAcceptRefundSignature => { + accept_msg.refund_signature = + alter_refund_sig(&accept_msg.refund_signature); + } + _ => {} + }; + bob_expect_error.store(true, Ordering::Relaxed); + alice_send.send(Some(Message::Accept(accept_msg))).unwrap(); + sync_receive.recv().expect("Error synchronizing"); + assert_contract_state!(bob_manager_send, temporary_contract_id, FailedAccept); + } + TestPath::BadSignCetSignature | TestPath::BadSignRefundSignature => { + alice_expect_error.store(true, Ordering::Relaxed); + alice_send.send(Some(Message::Accept(accept_msg))).unwrap(); + // Bob receives accept message + sync_receive.recv().expect("Error synchronizing"); + // Alice receives sign message + sync_receive.recv().expect("Error synchronizing"); + assert_contract_state!(alice_manager_send, contract_id, FailedSign); } + TestPath::Close | TestPath::Refund => { + alice_send.send(Some(Message::Accept(accept_msg))).unwrap(); + sync_receive.recv().expect("Error synchronizing"); - // Select the first one to close or refund randomly - let (first, second) = if thread_rng().next_u32() % 2 == 0 { - (alice_manager_send, bob_manager_send) - } else { - (bob_manager_send, alice_manager_send) - }; + assert_contract_state!(bob_manager_send, contract_id, Signed); - match path { - TestPath::Close => { - let case = thread_rng().next_u64() % 3; - let blocks: Option = if case == 2 { - Some(6) - } else if case == 1 { - Some(1) - } else { - None - }; - - if manual_close { - periodic_check!(first, contract_id, Confirmed); + // Should not change state and should not error + periodic_check!(bob_manager_send, contract_id, Signed); + + sync_receive.recv().expect("Error synchronizing"); + + assert_contract_state!(alice_manager_send, contract_id, Signed); - let attestations = get_attestations(&test_params); - - let f = first.lock().unwrap(); - let contract = f - .close_confirmed_contract(&contract_id, attestations) - .expect("Error closing contract"); - - if let Contract::PreClosed(contract) = contract { - let mut s = second.lock().unwrap(); - let second_contract = - s.get_store().get_contract(&contract_id).unwrap().unwrap(); - if let Contract::Confirmed(signed) = second_contract { - s.on_counterparty_close( - &signed, - contract.signed_cet, - blocks.unwrap_or(0), - ) - .expect("Error registering counterparty close"); + generate_blocks(6); + + periodic_check!(alice_manager_send, contract_id, Confirmed); + periodic_check!(bob_manager_send, contract_id, Confirmed); + + if !manual_close { + mocks::mock_time::set_time((EVENT_MATURITY as u64) + 1); + } + + // Select the first one to close or refund randomly + let (first, second) = if thread_rng().next_u32() % 2 == 0 { + (alice_manager_send, bob_manager_send) + } else { + (bob_manager_send, alice_manager_send) + }; + + match path { + TestPath::Close => { + let case = thread_rng().next_u64() % 3; + let blocks: Option = if case == 2 { + Some(6) + } else if case == 1 { + Some(1) + } else { + None + }; + + if manual_close { + periodic_check!(first, contract_id, Confirmed); + + let attestations = get_attestations(&test_params); + + let f = first.lock().unwrap(); + let contract = f + .close_confirmed_contract(&contract_id, attestations) + .expect("Error closing contract"); + + if let Contract::PreClosed(contract) = contract { + let mut s = second.lock().unwrap(); + let second_contract = + s.get_store().get_contract(&contract_id).unwrap().unwrap(); + if let Contract::Confirmed(signed) = second_contract { + s.on_counterparty_close( + &signed, + contract.signed_cet, + blocks.unwrap_or(0), + ) + .expect("Error registering counterparty close"); + } else { + panic!("Invalid contract state: {:?}", second_contract); + } } else { - panic!("Invalid contract state: {:?}", second_contract); + panic!("Invalid contract state {:?}", contract); } } else { - panic!("Invalid contract state {:?}", contract); + periodic_check!(first, contract_id, PreClosed); } - } else { - periodic_check!(first, contract_id, PreClosed); - } - // mine blocks for the CET to be confirmed - if let Some(b) = blocks { - generate_blocks(b as u64); - } + // mine blocks for the CET to be confirmed + if let Some(b) = blocks { + generate_blocks(b as u64); + } - // Randomly check with or without having the CET mined - if case == 2 { - // cet becomes fully confirmed to blockchain - periodic_check!(first, contract_id, Closed); - periodic_check!(second, contract_id, Closed); - } else { - periodic_check!(first, contract_id, PreClosed); - periodic_check!(second, contract_id, PreClosed); + // Randomly check with or without having the CET mined + if case == 2 { + // cet becomes fully confirmed to blockchain + periodic_check!(first, contract_id, Closed); + periodic_check!(second, contract_id, Closed); + } else { + periodic_check!(first, contract_id, PreClosed); + periodic_check!(second, contract_id, PreClosed); + } } - } - TestPath::Refund => { - periodic_check!(first, contract_id, Confirmed); + TestPath::Refund => { + periodic_check!(first, contract_id, Confirmed); - periodic_check!(second, contract_id, Confirmed); + periodic_check!(second, contract_id, Confirmed); - mocks::mock_time::set_time( - ((EVENT_MATURITY + dlc_manager::manager::REFUND_DELAY) as u64) + 1, - ); + mocks::mock_time::set_time( + ((EVENT_MATURITY + dlc_manager::manager::REFUND_DELAY) as u64) + 1, + ); - generate_blocks(10); + generate_blocks(10); - periodic_check!(first, contract_id, Refunded); + periodic_check!(first, contract_id, Refunded); - // Randomly check with or without having the Refund mined. - if thread_rng().next_u32() % 2 == 0 { - generate_blocks(1); - } + // Randomly check with or without having the Refund mined. + if thread_rng().next_u32() % 2 == 0 { + generate_blocks(1); + } - periodic_check!(second, contract_id, Refunded); + periodic_check!(second, contract_id, Refunded); + } + _ => unreachable!(), } - _ => unreachable!(), } } - } - alice_send.send(None).unwrap(); - bob_send.send(None).unwrap(); + alice_send.send(None).unwrap(); + bob_send.send(None).unwrap(); - alice_handle.join().unwrap(); - bob_handle.join().unwrap(); + alice_handle.join().unwrap(); + bob_handle.join().unwrap(); - create_test_vector(); + create_test_vector(); + } } diff --git a/p2pd-oracle-client/src/lib.rs b/p2pd-oracle-client/src/lib.rs index 567eaa5e..5211293d 100644 --- a/p2pd-oracle-client/src/lib.rs +++ b/p2pd-oracle-client/src/lib.rs @@ -227,6 +227,7 @@ impl Oracle for P2PDOracleClient { .map_err(|e| DlcManagerError::OracleError(e.to_string()))?; Ok(OracleAttestation { + event_id: event_id.to_string(), oracle_public_key: self.public_key, signatures, outcomes: values, From 2ba6b52b9b66a13c0fc3e9169c15af5d0108ae88 Mon Sep 17 00:00:00 2001 From: bennyhodl Date: Fri, 1 Nov 2024 15:13:52 -0400 Subject: [PATCH 6/6] fix: get attestations correctly for closable info --- dlc-manager/src/manager.rs | 44 ++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/dlc-manager/src/manager.rs b/dlc-manager/src/manager.rs index a100b07c..a49b4725 100644 --- a/dlc-manager/src/manager.rs +++ b/dlc-manager/src/manager.rs @@ -584,24 +584,40 @@ where }) .enumerate() .collect(); - if matured.len() >= contract_info.threshold { let mut attestations = Vec::new(); for (i, announcement) in matured { - let oracle = self.oracles.get(&announcement.oracle_public_key)?; - let attestation = + let oracle = match self.oracles.get(&announcement.oracle_public_key) { + Some(o) => o, + None => { + log::warn!( + "No oracle found with pubkey. pubkey={}", + announcement.oracle_public_key + ); + continue; + } + }; + let Ok(attestation) = maybe_await!(oracle.get_attestation(&announcement.oracle_event.event_id)) - .ok()?; - attestation - .validate(&self.secp, announcement) - .map_err(|_| { - log::error!( - "Oracle attestation is not valid. pubkey={} event_id={}", - announcement.oracle_public_key, - announcement.oracle_event.event_id - ) - }) - .ok()?; + else { + log::warn!( + "Failed to get attestation. oracle={} event_id={}", + announcement.oracle_public_key, + announcement.oracle_event.event_id + ); + continue; + }; + + if let Err(error) = attestation.validate(&self.secp, announcement) { + log::warn!( + "Oracle attestation is invalid. error={} pubkey={} event_id={}", + error, + announcement.oracle_public_key, + announcement.oracle_event.event_id + ); + continue; + } + attestations.push((i, attestation)); } if attestations.len() >= contract_info.threshold {