From 02f816d6e139eeebf73603cf8dc9838e44c5e185 Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Fri, 9 Jun 2023 09:40:49 +0900 Subject: [PATCH 01/12] Fix fee computation --- dlc-manager/src/contract/offered_contract.rs | 3 +- dlc-manager/src/contract_updater.rs | 37 +++ dlc-manager/src/manager.rs | 7 +- dlc-manager/src/utils.rs | 18 +- dlc-manager/test_inputs/offer_contract.json | 2 +- dlc/src/util.rs | 9 +- mocks/Cargo.toml | 2 +- mocks/src/mock_blockchain.rs | 34 ++- mocks/src/mock_wallet.rs | 10 +- simple-wallet/Cargo.toml | 2 +- simple-wallet/src/lib.rs | 229 +++++++++++++++++-- 11 files changed, 306 insertions(+), 47 deletions(-) diff --git a/dlc-manager/src/contract/offered_contract.rs b/dlc-manager/src/contract/offered_contract.rs index b9e18a31..159cc246 100644 --- a/dlc-manager/src/contract/offered_contract.rs +++ b/dlc-manager/src/contract/offered_contract.rs @@ -116,7 +116,8 @@ impl OfferedContract { } } - pub(crate) fn try_from_offer_dlc( + /// Convert an [`OfferDlc`] message to an [`OfferedContract`]. + pub fn try_from_offer_dlc( offer_dlc: &OfferDlc, counter_party: PublicKey, ) -> Result { diff --git a/dlc-manager/src/contract_updater.rs b/dlc-manager/src/contract_updater.rs index 055d7337..4fefb8c2 100644 --- a/dlc-manager/src/contract_updater.rs +++ b/dlc-manager/src/contract_updater.rs @@ -734,3 +734,40 @@ where )?; Ok(refund) } + +#[cfg(test)] +mod tests { + use std::rc::Rc; + + use mocks::dlc_manager::contract::offered_contract::OfferedContract; + use secp256k1_zkp::PublicKey; + + #[test] + fn accept_contract_test() { + let offer_dlc = + serde_json::from_str(include_str!("../test_inputs/offer_contract.json")).unwrap(); + let dummy_pubkey: PublicKey = + "02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443" + .parse() + .unwrap(); + let offered_contract = + OfferedContract::try_from_offer_dlc(&offer_dlc, dummy_pubkey).unwrap(); + let blockchain = Rc::new(mocks::mock_blockchain::MockBlockchain::new()); + let fee_rate: u64 = offered_contract.fee_rate_per_vb; + let utxo_value: u64 = offered_contract.total_collateral + - offered_contract.offer_params.collateral + + crate::utils::get_half_common_fee(fee_rate).unwrap(); + let wallet = Rc::new(mocks::mock_wallet::MockWallet::new( + &blockchain, + &[utxo_value, 10000], + )); + + mocks::dlc_manager::contract_updater::accept_contract( + secp256k1_zkp::SECP256K1, + &offered_contract, + &wallet, + &blockchain, + ) + .expect("Not to fail"); + } +} diff --git a/dlc-manager/src/manager.rs b/dlc-manager/src/manager.rs index 8ef4bbcd..0d98cec5 100644 --- a/dlc-manager/src/manager.rs +++ b/dlc-manager/src/manager.rs @@ -2209,9 +2209,12 @@ mod test { >; fn get_manager() -> TestManager { - let blockchain = Rc::new(MockBlockchain {}); + let blockchain = Rc::new(MockBlockchain::new()); let store = Rc::new(MemoryStorage::new()); - let wallet = Rc::new(MockWallet::new(&blockchain, 100)); + let wallet = Rc::new(MockWallet::new( + &blockchain, + &(0..100).map(|x| x as u64 * 1000000).collect::>(), + )); let oracle_list = (0..5).map(|_| MockOracle::new()).collect::>(); let oracles: HashMap = oracle_list diff --git a/dlc-manager/src/utils.rs b/dlc-manager/src/utils.rs index 9f9d5ff0..6066a764 100644 --- a/dlc-manager/src/utils.rs +++ b/dlc-manager/src/utils.rs @@ -1,3 +1,4 @@ +//! #Utils use std::ops::Deref; use bitcoin::{consensus::Encodable, Txid}; @@ -18,13 +19,6 @@ use crate::{ Blockchain, Wallet, }; -const APPROXIMATE_CET_VBYTES: u64 = 190; -const APPROXIMATE_CLOSING_VBYTES: u64 = 168; - -pub fn get_common_fee(fee_rate: u64) -> u64 { - (APPROXIMATE_CET_VBYTES + APPROXIMATE_CLOSING_VBYTES) * fee_rate -} - #[cfg(not(feature = "fuzztarget"))] pub(crate) fn get_new_serial_id() -> u64 { thread_rng().next_u64() @@ -86,7 +80,9 @@ where let change_spk = change_addr.script_pubkey(); let change_serial_id = get_new_serial_id(); - let appr_required_amount = own_collateral + get_half_common_fee(fee_rate); + // Add base cost of fund tx + CET / 2 and a CET output to the collateral. + let appr_required_amount = + own_collateral + get_half_common_fee(fee_rate)? + dlc::util::weight_to_fee(124, fee_rate)?; let utxos = wallet.get_utxos_for_amount(appr_required_amount, Some(fee_rate), true)?; let mut funding_inputs_info: Vec = Vec::new(); @@ -145,9 +141,9 @@ where }) } -fn get_half_common_fee(fee_rate: u64) -> u64 { - let common_fee = get_common_fee(fee_rate); - (common_fee as f64 / 2_f64).ceil() as u64 +pub(crate) fn get_half_common_fee(fee_rate: u64) -> Result { + let common_fee = dlc::util::get_common_fee(fee_rate)?; + Ok((common_fee as f64 / 2_f64).ceil() as u64) } pub(crate) fn get_range_info_and_oracle_sigs( diff --git a/dlc-manager/test_inputs/offer_contract.json b/dlc-manager/test_inputs/offer_contract.json index abde8532..389e9236 100644 --- a/dlc-manager/test_inputs/offer_contract.json +++ b/dlc-manager/test_inputs/offer_contract.json @@ -1 +1 @@ -{"protocolVersion":1,"contractFlags":0,"chainHash":"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f","temporaryContractId":"f6a1b2841c93db06e94200b227bb4bdea83068efa557d68e14775237cbaab56a","contractInfo":{"singleContractInfo":{"totalCollateral":101000000,"contractInfo":{"contractDescriptor":{"numericOutcomeContractDescriptor":{"numDigits":10,"payoutFunction":{"payoutFunctionPieces":[{"endPoint":{"eventOutcome":0,"outcomePayout":0,"extraPrecision":0},"payoutCurvePiece":{"polynomialPayoutCurvePiece":{"payoutPoints":[{"eventOutcome":3,"outcomePayout":90000000,"extraPrecision":0}]}}},{"endPoint":{"eventOutcome":5,"outcomePayout":101000000,"extraPrecision":0},"payoutCurvePiece":{"polynomialPayoutCurvePiece":{"payoutPoints":[]}}}],"lastEndpoint":{"eventOutcome":1023,"outcomePayout":101000000,"extraPrecision":0}},"roundingIntervals":{"intervals":[{"beginInterval":0,"roundingMod":1}]}}},"oracleInfo":{"single":{"oracleAnnouncement":{"announcementSignature":"18e18de8b3547e210addd32589db9520286f55c0c18510c67bb6f8ea66b05154b84c6ec0075e3623f886b7e2bc623b7df25e1bc25d1cc87c622b28f0ae526664","oraclePublicKey":"1d524d2753a36ebe340af67370f78219b4dbb6f56d2f96b3b21eaabec6f4a114","oracleEvent":{"oracleNonces":["bc927a2c8bf43c9d208e679848ffaf95d178fdbd2e29d1c66668f21dd75149e8","9ed74e19c1d532f5127829b7d9f183e0738ad084485428b53a7fe0c50f2efe5e","f44733d1129d0cd9253124749f8cff2c7e7eecd79888a4a015d3e3ad153ef282","f4f39e5733bfc5ca18530eb444419b31d9dc0ec938502615c33f2b0b7c05ac71","930991374fbf6b9a49e5e16fa3c5c39638af58f5a4c55682a93b2b940502e7bf","e3af3b59907c349d627e3f4f20125bdc1e979cac41ee82ef0a184000c79e904b","0b95d4335713752329a1791b963d526c0a49873bbbfcad9e1c03881508b2a801","48776cc1e3b8f3ff7fd6226ea2df5607787913468a1c0faad4ff315b7cf3b41d","0b39b0e1a14f5f50cb05f0a6d8e7c082f75e9fe386006727af933ce4d273a76f","479a38e13c1622bfd53299ee67680d7a0edd3fed92223e3a878c8d010fcc1a2d"],"eventMaturityEpoch":1623133104,"eventDescriptor":{"digitDecompositionEvent":{"base":2,"isSigned":false,"unit":"sats/sec","precision":0,"nbDigits":10}},"eventId":"Test"}}}}}}},"fundingPubkey":"02556021f6abda2ae7a74d38a4e4a3b00c1dd648db96397dcd8642c3d0b0b139d1","payoutSpk":"0014430af74f2f9dc88729fd02eaeb946fc161e2be1e","payoutSerialId":8165863461276958928,"offerCollateral":90000000,"fundingInputs":[{"inputSerialId":11632658032743242199,"prevTx":"02000000000101e79f7a30bb35206060eb09a99b6956bcdc7a1767b310c8dfde3595c69246a60e0000000000feffffff0200c2eb0b000000001600142a416c1e5f5e78bc6c518294fd1dd86b40eed2d77caf953e000000001600148e56705661334df89b2c1c7c4e41da9cef9eb38e0247304402201491f05ebe196b333420cbab3e7e7f3e431bfe91a42730cef9c6e64b0e8ff62302202c5fc79abbdb0a1c8ad422dbb97a54693feedc580f0cb7a62bdadaecbfc4f9430121035f57172a38f35f29f4357dcc2d24ea8e72638cf43190e4fdcb3f0ace215cfd5602020000","prevTxVout":0,"sequence":4294967295,"maxWitnessLen":107,"redeemScript":""}],"changeSpk":"001441ca183be469eab996f34ed31197a96b57f6050e","changeSerialId":16919534260907952016,"fundOutputSerialId":5054305248376932341,"feeRatePerVb":2,"cetLocktime":1623133103,"refundLocktime":1623737904} \ No newline at end of file +{"protocolVersion":1,"contractFlags":0,"chainHash":"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f","temporaryContractId":"f6a1b2841c93db06e94200b227bb4bdea83068efa557d68e14775237cbaab56a","contractInfo":{"singleContractInfo":{"totalCollateral":101000000,"contractInfo":{"contractDescriptor":{"numericOutcomeContractDescriptor":{"numDigits":10,"payoutFunction":{"payoutFunctionPieces":[{"endPoint":{"eventOutcome":0,"outcomePayout":0,"extraPrecision":0},"payoutCurvePiece":{"polynomialPayoutCurvePiece":{"payoutPoints":[{"eventOutcome":3,"outcomePayout":90000000,"extraPrecision":0}]}}},{"endPoint":{"eventOutcome":5,"outcomePayout":101000000,"extraPrecision":0},"payoutCurvePiece":{"polynomialPayoutCurvePiece":{"payoutPoints":[]}}}],"lastEndpoint":{"eventOutcome":1023,"outcomePayout":101000000,"extraPrecision":0}},"roundingIntervals":{"intervals":[{"beginInterval":0,"roundingMod":1}]}}},"oracleInfo":{"single":{"oracleAnnouncement":{"announcementSignature":"18e18de8b3547e210addd32589db9520286f55c0c18510c67bb6f8ea66b05154b84c6ec0075e3623f886b7e2bc623b7df25e1bc25d1cc87c622b28f0ae526664","oraclePublicKey":"1d524d2753a36ebe340af67370f78219b4dbb6f56d2f96b3b21eaabec6f4a114","oracleEvent":{"oracleNonces":["bc927a2c8bf43c9d208e679848ffaf95d178fdbd2e29d1c66668f21dd75149e8","9ed74e19c1d532f5127829b7d9f183e0738ad084485428b53a7fe0c50f2efe5e","f44733d1129d0cd9253124749f8cff2c7e7eecd79888a4a015d3e3ad153ef282","f4f39e5733bfc5ca18530eb444419b31d9dc0ec938502615c33f2b0b7c05ac71","930991374fbf6b9a49e5e16fa3c5c39638af58f5a4c55682a93b2b940502e7bf","e3af3b59907c349d627e3f4f20125bdc1e979cac41ee82ef0a184000c79e904b","0b95d4335713752329a1791b963d526c0a49873bbbfcad9e1c03881508b2a801","48776cc1e3b8f3ff7fd6226ea2df5607787913468a1c0faad4ff315b7cf3b41d","0b39b0e1a14f5f50cb05f0a6d8e7c082f75e9fe386006727af933ce4d273a76f","479a38e13c1622bfd53299ee67680d7a0edd3fed92223e3a878c8d010fcc1a2d"],"eventMaturityEpoch":1623133104,"eventDescriptor":{"digitDecompositionEvent":{"base":2,"isSigned":false,"unit":"sats/sec","precision":0,"nbDigits":10}},"eventId":"Test"}}}}}}},"fundingPubkey":"02556021f6abda2ae7a74d38a4e4a3b00c1dd648db96397dcd8642c3d0b0b139d1","payoutSpk":"0014430af74f2f9dc88729fd02eaeb946fc161e2be1e","payoutSerialId":8165863461276958928,"offerCollateral":90000000,"fundingInputs":[{"inputSerialId":11632658032743242199,"prevTx":"02000000000101e79f7a30bb35206060eb09a99b6956bcdc7a1767b310c8dfde3595c69246a60e0000000000feffffff0200c2eb0b000000001600142a416c1e5f5e78bc6c518294fd1dd86b40eed2d77caf953e000000001600148e56705661334df89b2c1c7c4e41da9cef9eb38e0247304402201491f05ebe196b333420cbab3e7e7f3e431bfe91a42730cef9c6e64b0e8ff62302202c5fc79abbdb0a1c8ad422dbb97a54693feedc580f0cb7a62bdadaecbfc4f9430121035f57172a38f35f29f4357dcc2d24ea8e72638cf43190e4fdcb3f0ace215cfd5602020000","prevTxVout":0,"sequence":4294967295,"maxWitnessLen":107,"redeemScript":""}],"changeSpk":"001441ca183be469eab996f34ed31197a96b57f6050e","changeSerialId":16919534260907952016,"fundOutputSerialId":5054305248376932341,"feeRatePerVb":2,"cetLocktime":1623133103,"refundLocktime":1623737904} diff --git a/dlc/src/util.rs b/dlc/src/util.rs index f15e70a4..297da47e 100644 --- a/dlc/src/util.rs +++ b/dlc/src/util.rs @@ -94,12 +94,19 @@ pub fn get_sig_for_p2wpkh_input( ) } -pub(crate) fn weight_to_fee(weight: usize, fee_rate: u64) -> Result { +/// Returns the fee for the given weight at given fee rate. +pub fn weight_to_fee(weight: usize, fee_rate: u64) -> Result { (f64::ceil((weight as f64) / 4.0) as u64) .checked_mul(fee_rate) .ok_or(Error::InvalidArgument) } +/// Return the common base fee for a DLC for the given fee rate. +pub fn get_common_fee(fee_rate: u64) -> Result { + let base_weight = crate::FUND_TX_BASE_WEIGHT + crate::CET_BASE_WEIGHT; + weight_to_fee(base_weight, fee_rate) +} + fn get_pkh_script_pubkey_from_sk(secp: &Secp256k1, sk: &SecretKey) -> Script { use bitcoin::hashes::*; let pk = bitcoin::PublicKey { diff --git a/mocks/Cargo.toml b/mocks/Cargo.toml index a584da34..d6416dda 100644 --- a/mocks/Cargo.toml +++ b/mocks/Cargo.toml @@ -7,7 +7,7 @@ version = "0.1.0" [dependencies] bitcoin = "0.29" dlc = {path = "../dlc"} -dlc-manager = {path = "../dlc-manager"} +dlc-manager = {path = "../dlc-manager", features = ["use-serde"]} dlc-messages = {path = "../dlc-messages"} lightning = {version = "0.0.113"} secp256k1-zkp = {version = "0.7.0", features = ["bitcoin_hashes", "global-context", "rand", "rand-std"]} diff --git a/mocks/src/mock_blockchain.rs b/mocks/src/mock_blockchain.rs index 682d2fd6..f1e7d109 100644 --- a/mocks/src/mock_blockchain.rs +++ b/mocks/src/mock_blockchain.rs @@ -1,12 +1,31 @@ +use std::sync::Mutex; + use bitcoin::{Block, Transaction, Txid}; use dlc_manager::{error::Error, Blockchain, Utxo}; use lightning::chain::chaininterface::FeeEstimator; use simple_wallet::WalletBlockchainProvider; -pub struct MockBlockchain {} +pub struct MockBlockchain { + transactions: Mutex>, +} + +impl MockBlockchain { + pub fn new() -> Self { + Self { + transactions: Mutex::new(Vec::new()), + } + } +} + +impl Default for MockBlockchain { + fn default() -> Self { + Self::new() + } +} impl Blockchain for MockBlockchain { - fn send_transaction(&self, _transaction: &Transaction) -> Result<(), Error> { + fn send_transaction(&self, transaction: &Transaction) -> Result<(), Error> { + self.transactions.lock().unwrap().push(transaction.clone()); Ok(()) } fn get_network(&self) -> Result { @@ -18,8 +37,15 @@ impl Blockchain for MockBlockchain { fn get_block_at_height(&self, _height: u64) -> Result { unimplemented!(); } - fn get_transaction(&self, _tx_id: &Txid) -> Result { - unimplemented!(); + fn get_transaction(&self, tx_id: &Txid) -> Result { + Ok(self + .transactions + .lock() + .unwrap() + .iter() + .find(|x| &x.txid() == tx_id) + .unwrap() + .clone()) } fn get_transaction_confirmations(&self, _tx_id: &Txid) -> Result { Ok(6) diff --git a/mocks/src/mock_wallet.rs b/mocks/src/mock_wallet.rs index 0595d686..b83b60d0 100644 --- a/mocks/src/mock_wallet.rs +++ b/mocks/src/mock_wallet.rs @@ -11,12 +11,12 @@ pub struct MockWallet { } impl MockWallet { - pub fn new(blockchain: &Rc, nb_utxo: u16) -> Self { - let mut utxos = Vec::with_capacity(nb_utxo as usize); + pub fn new(blockchain: &Rc, utxo_values: &[u64]) -> Self { + let mut utxos = Vec::with_capacity(utxo_values.len()); - for i in 0..nb_utxo { + for utxo_value in utxo_values { let tx_out = TxOut { - value: 1000000 * i as u64, + value: *utxo_value, script_pubkey: Script::default(), }; let tx = Transaction { @@ -102,7 +102,7 @@ impl Wallet for MockWallet { return Ok(res); } - Err(Error::InvalidParameters("".to_string())) + Err(Error::InvalidParameters("Not enought UTXOs".to_string())) } fn import_address(&self, _address: &Address) -> Result<(), dlc_manager::error::Error> { diff --git a/simple-wallet/Cargo.toml b/simple-wallet/Cargo.toml index a582b733..fa822adb 100644 --- a/simple-wallet/Cargo.toml +++ b/simple-wallet/Cargo.toml @@ -10,7 +10,7 @@ bitcoin = "0.29" dlc = {path = "../dlc"} dlc-manager = {path = "../dlc-manager"} lightning = {version = "0.0.113"} -rust-bitcoin-coin-selection = {version = "0.1.0", git = "https://github.com/p2pderivatives/rust-bitcoin-coin-selection", features = ["rand"]} +bdk = {version = "0.28.0"} secp256k1-zkp = {version = "0.7.0"} [dev-dependencies] diff --git a/simple-wallet/src/lib.rs b/simple-wallet/src/lib.rs index 6044a469..c36e3a0a 100644 --- a/simple-wallet/src/lib.rs +++ b/simple-wallet/src/lib.rs @@ -1,11 +1,16 @@ use std::ops::Deref; +use bdk::{ + database::{BatchOperations, Database}, + wallet::coin_selection::{BranchAndBoundCoinSelection, CoinSelectionAlgorithm}, + FeeRate, KeychainKind, LocalUtxo, Utxo as BdkUtxo, WeightedUtxo, +}; use bitcoin::{ - Address, Network, PackedLockTime, Script, Sequence, Transaction, TxIn, TxOut, Txid, Witness, + hashes::Hash, Address, Network, PackedLockTime, Script, Sequence, Transaction, TxIn, TxOut, + Txid, Witness, }; use dlc_manager::{error::Error, Blockchain, Signer, Utxo, Wallet}; use lightning::chain::chaininterface::{ConfirmationTarget, FeeEstimator}; -use rust_bitcoin_coin_selection::select_coins; use secp256k1_zkp::{rand::thread_rng, All, PublicKey, Secp256k1, SecretKey}; type Result = core::result::Result; @@ -223,28 +228,55 @@ where fn get_utxos_for_amount( &self, amount: u64, - _: Option, + fee_rate: Option, lock_utxos: bool, ) -> Result> { - let mut utxos = self - .storage - .get_utxos()? - .into_iter() + let org_utxos = self.storage.get_utxos()?; + let utxos = org_utxos + .iter() .filter(|x| !x.reserved) - .map(|x| UtxoWrap { utxo: x }) + .map(|x| WeightedUtxo { + utxo: BdkUtxo::Local(LocalUtxo { + outpoint: x.outpoint, + txout: x.tx_out.clone(), + keychain: KeychainKind::External, + is_spent: false, + }), + satisfaction_weight: 107, + }) .collect::>(); - let selection = select_coins(amount, 20, &mut utxos) - .ok_or_else(|| Error::InvalidState("Not enough fund in utxos".to_string()))?; + let coin_selection = BranchAndBoundCoinSelection::default(); + let dummy_pubkey: PublicKey = + "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" + .parse() + .unwrap(); + let dummy_drain = + Script::new_v0_p2wpkh(&bitcoin::WPubkeyHash::hash(&dummy_pubkey.serialize())); + let fee_rate = FeeRate::from_sat_per_vb(fee_rate.unwrap() as f32); + let selection = coin_selection + .coin_select(self, Vec::new(), utxos, fee_rate, amount, &dummy_drain) + .map_err(|e| Error::WalletError(Box::new(e)))?; + let mut res = Vec::new(); if lock_utxos { - for utxo in selection.clone() { + for utxo in selection.selected { + let local_utxo = if let BdkUtxo::Local(l) = utxo { + l + } else { + panic!(); + }; + let org = org_utxos + .iter() + .find(|x| x.tx_out == local_utxo.txout && x.outpoint == local_utxo.outpoint) + .unwrap(); let updated = Utxo { reserved: true, - ..utxo.utxo + ..org.clone() }; + res.push(org.clone()); self.storage.upsert_utxo(&updated)?; } } - Ok(selection.into_iter().map(|x| x.utxo).collect::>()) + Ok(res) } fn import_address(&self, _: &Address) -> Result<()> { @@ -252,14 +284,171 @@ where } } -#[derive(Clone)] -struct UtxoWrap { - utxo: Utxo, +impl BatchOperations for SimpleWallet +where + B::Target: WalletBlockchainProvider, + W::Target: WalletStorage, +{ + fn set_script_pubkey( + &mut self, + _: &Script, + _: bdk::KeychainKind, + _: u32, + ) -> std::result::Result<(), bdk::Error> { + Ok(()) + } + + fn set_utxo(&mut self, _: &bdk::LocalUtxo) -> std::result::Result<(), bdk::Error> { + Ok(()) + } + + fn set_raw_tx(&mut self, _: &Transaction) -> std::result::Result<(), bdk::Error> { + Ok(()) + } + + fn set_tx(&mut self, _: &bdk::TransactionDetails) -> std::result::Result<(), bdk::Error> { + Ok(()) + } + + fn set_last_index( + &mut self, + _: bdk::KeychainKind, + _: u32, + ) -> std::result::Result<(), bdk::Error> { + Ok(()) + } + + fn set_sync_time(&mut self, _: bdk::database::SyncTime) -> std::result::Result<(), bdk::Error> { + Ok(()) + } + + fn del_script_pubkey_from_path( + &mut self, + _: bdk::KeychainKind, + _: u32, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn del_path_from_script_pubkey( + &mut self, + _: &Script, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn del_utxo( + &mut self, + _: &bitcoin::OutPoint, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn del_raw_tx(&mut self, _: &Txid) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn del_tx( + &mut self, + _: &Txid, + _: bool, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn del_last_index( + &mut self, + _: bdk::KeychainKind, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn del_sync_time( + &mut self, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } } -impl rust_bitcoin_coin_selection::Utxo for UtxoWrap { - fn get_value(&self) -> u64 { - self.utxo.tx_out.value +impl Database for SimpleWallet +where + B::Target: WalletBlockchainProvider, + W::Target: WalletStorage, +{ + fn check_descriptor_checksum>( + &mut self, + _: bdk::KeychainKind, + _: BY, + ) -> std::result::Result<(), bdk::Error> { + Ok(()) + } + + fn iter_script_pubkeys( + &self, + _: Option, + ) -> std::result::Result, bdk::Error> { + Ok(Vec::new()) + } + + fn iter_utxos(&self) -> std::result::Result, bdk::Error> { + Ok(Vec::new()) + } + + fn iter_raw_txs(&self) -> std::result::Result, bdk::Error> { + Ok(Vec::new()) + } + + fn iter_txs(&self, _: bool) -> std::result::Result, bdk::Error> { + Ok(Vec::new()) + } + + fn get_script_pubkey_from_path( + &self, + _: bdk::KeychainKind, + _: u32, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn get_path_from_script_pubkey( + &self, + _: &Script, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn get_utxo( + &self, + _: &bitcoin::OutPoint, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn get_raw_tx(&self, _: &Txid) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn get_tx( + &self, + _: &Txid, + _: bool, + ) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn get_last_index(&self, _: bdk::KeychainKind) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn get_sync_time(&self) -> std::result::Result, bdk::Error> { + Ok(None) + } + + fn increment_last_index( + &mut self, + _: bdk::KeychainKind, + ) -> std::result::Result { + Ok(0) } } @@ -273,7 +462,7 @@ mod tests { use secp256k1_zkp::{PublicKey, SECP256K1}; fn get_wallet() -> SimpleWallet, Rc> { - let blockchain = Rc::new(MockBlockchain {}); + let blockchain = Rc::new(MockBlockchain::new()); let storage = Rc::new(MemoryStorage::new()); SimpleWallet::new(blockchain, storage, bitcoin::Network::Regtest) } From 1561ce9d2770e9e9b54c5e859bf4d4e62cda2195 Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Fri, 9 Jun 2023 13:09:13 +0900 Subject: [PATCH 02/12] Fix lint warning --- dlc-trie/src/digit_trie.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlc-trie/src/digit_trie.rs b/dlc-trie/src/digit_trie.rs index 4e649518..6f035a4d 100644 --- a/dlc-trie/src/digit_trie.rs +++ b/dlc-trie/src/digit_trie.rs @@ -259,7 +259,7 @@ impl<'a, T> Iterator for DigitTrieIter<'a, T> { while cur_child < (self.trie.base as isize) { self.index_stack.push((Some(cur_index), cur_child + 1)); self.index_stack - .push((cur_children[(cur_child as usize)], -1)); + .push((cur_children[cur_child as usize], -1)); match self.next() { None => { self.index_stack.pop(); From 96b30b7d345c5029de58e98f0a6247a35f396bf7 Mon Sep 17 00:00:00 2001 From: sosaucily Date: Wed, 21 Jun 2023 12:04:44 +0200 Subject: [PATCH 03/12] remove default features for simple-wallet bdk --- simple-wallet/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-wallet/Cargo.toml b/simple-wallet/Cargo.toml index fa822adb..80428df6 100644 --- a/simple-wallet/Cargo.toml +++ b/simple-wallet/Cargo.toml @@ -10,7 +10,7 @@ bitcoin = "0.29" dlc = {path = "../dlc"} dlc-manager = {path = "../dlc-manager"} lightning = {version = "0.0.113"} -bdk = {version = "0.28.0"} +bdk = {version = "0.28.0", default-features = false, features = ["async-interface", "use-esplora-async"]} secp256k1-zkp = {version = "0.7.0"} [dev-dependencies] From 800bc0b6ccc4bd55779b377ae2e6c7a871f3cca5 Mon Sep 17 00:00:00 2001 From: sosaucily Date: Sat, 24 Jun 2023 14:37:32 +0200 Subject: [PATCH 04/12] update miniscript to prevent compile errors --- dlc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlc/Cargo.toml b/dlc/Cargo.toml index e2039838..a6c5cb15 100644 --- a/dlc/Cargo.toml +++ b/dlc/Cargo.toml @@ -9,7 +9,7 @@ version = "0.4.0" [dependencies] bitcoin = {version = "0.29.2"} -miniscript = "8.0.0" +miniscript = { version = "9.0", features = ["serde", "std"], default-features = false } secp256k1-sys = {version = "0.6.1" } secp256k1-zkp = {version = "0.7.0", features = ["bitcoin_hashes", "rand-std"]} serde = {version = "1.0", default-features = false, optional = true} From a4c38b5f9d53dc8d98575b9146d78e9ff06a158c Mon Sep 17 00:00:00 2001 From: sosaucily Date: Mon, 10 Jul 2023 16:20:59 +0200 Subject: [PATCH 05/12] periodic check returns a set of affected contracts --- dlc-manager/Cargo.toml | 2 + dlc-manager/src/lib.rs | 11 ++++ dlc-manager/src/manager.rs | 115 ++++++++++++++++++++++++++----------- 3 files changed, 96 insertions(+), 32 deletions(-) diff --git a/dlc-manager/Cargo.toml b/dlc-manager/Cargo.toml index 3bbd99d4..12c92421 100644 --- a/dlc-manager/Cargo.toml +++ b/dlc-manager/Cargo.toml @@ -24,6 +24,7 @@ log = "0.4.14" rand_chacha = {version = "0.3.1", optional = true} secp256k1-zkp = {version = "0.7.0", features = ["bitcoin_hashes", "rand", "rand-std"]} serde = {version = "1.0", optional = true} +serde_json = "1.0" [dev-dependencies] bitcoin-rpc-provider = {path = "../bitcoin-rpc-provider"} @@ -35,6 +36,7 @@ dlc-manager = {path = ".", features = ["use-serde"]} dlc-messages = {path = "../dlc-messages", features = ["serde"]} electrs-blockchain-provider = {path = "../electrs-blockchain-provider"} env_logger = "0.9.1" +mockito = "0.31.0" mocks = {path = "../mocks"} secp256k1-zkp = {version = "0.7.0", features = ["bitcoin_hashes", "rand", "rand-std", "global-context", "use-serde"]} serde = "1.0" diff --git a/dlc-manager/src/lib.rs b/dlc-manager/src/lib.rs index d6707ec8..6c35dee0 100644 --- a/dlc-manager/src/lib.rs +++ b/dlc-manager/src/lib.rs @@ -199,3 +199,14 @@ impl_dlc_writeable!(Utxo, { (redeem_script, writeable), (reserved, writeable) }); + +/// The response from periodic_check fn which returns the ids of the contracts that were affected in each state. +#[derive(Clone, Debug)] +pub struct AffectedContractIDs { + /// The list of contracts that were moved into the confirmed state. + pub confirmed_contracts: Vec, + /// The list of contracts that were moved into the pre-closed state. + pub pre_closed_contracts: Vec, + /// The list of contracts that were moved into the closed state. + pub closed_contracts: Vec, +} diff --git a/dlc-manager/src/manager.rs b/dlc-manager/src/manager.rs index 0d98cec5..2d1063b4 100644 --- a/dlc-manager/src/manager.rs +++ b/dlc-manager/src/manager.rs @@ -15,7 +15,7 @@ use crate::contract::{ }; use crate::contract_updater::{accept_contract, verify_accepted_and_sign_contract}; use crate::error::Error; -use crate::Signer; +use crate::{AffectedContractIDs, Signer}; use crate::{ChannelId, ContractId}; use bitcoin::Address; use bitcoin::Transaction; @@ -330,13 +330,15 @@ where /// Function to call to check the state of the currently executing DLCs and /// update them if possible. - pub fn periodic_check(&mut self) -> Result<(), Error> { - self.check_signed_contracts()?; - self.check_confirmed_contracts()?; - self.check_preclosed_contracts()?; + pub fn periodic_check(&mut self) -> Result { + let affected_contracts = AffectedContractIDs { + confirmed_contracts: self.check_signed_contracts()?, + pre_closed_contracts: self.check_confirmed_contracts()?, + closed_contracts: self.check_preclosed_contracts()?, + }; self.channel_checks()?; - Ok(()) + Ok(affected_contracts) } fn on_offer_message( @@ -470,47 +472,59 @@ where Err(e) } - fn check_signed_contract(&mut self, contract: &SignedContract) -> Result<(), Error> { + fn check_signed_contract( + &mut self, + contract: &SignedContract, + ) -> Result, Error> { let confirmations = self.blockchain.get_transaction_confirmations( &contract.accepted_contract.dlc_transactions.fund.txid(), )?; if confirmations >= NB_CONFIRMATIONS { self.store .update_contract(&Contract::Confirmed(contract.clone()))?; + return Ok(Some(contract.accepted_contract.get_contract_id())); } - Ok(()) + Ok(None) } - fn check_signed_contracts(&mut self) -> Result<(), Error> { + fn check_signed_contracts(&mut self) -> Result, Error> { + let mut contracts_to_confirm = Vec::new(); for c in self.store.get_signed_contracts()? { - if let Err(e) = self.check_signed_contract(&c) { - error!( + match self.check_signed_contract(&c) { + Ok(Some(contract_id)) => contracts_to_confirm.push(contract_id), + Ok(None) => (), + Err(e) => error!( "Error checking confirmed contract {}: {}", c.accepted_contract.get_contract_id_string(), e - ) + ), } } - Ok(()) + Ok(contracts_to_confirm) } - fn check_confirmed_contracts(&mut self) -> Result<(), Error> { + fn check_confirmed_contracts(&mut self) -> Result, Error> { + let mut contracts_to_close = Vec::new(); 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) { - error!( - "Error checking confirmed contract {}: {}", - c.accepted_contract.get_contract_id_string(), - e - ) + match self.check_confirmed_contract(&c) { + Err(e) => { + error!( + "Error checking confirmed contract {}: {}", + c.accepted_contract.get_contract_id_string(), + e + ) + } + Ok(Some(contract_id)) => contracts_to_close.push(contract_id), + Ok(None) => (), } } - Ok(()) + Ok(contracts_to_close) } fn get_closable_contract_info<'a>( @@ -549,7 +563,10 @@ where None } - fn check_confirmed_contract(&mut self, contract: &SignedContract) -> Result<(), Error> { + fn check_confirmed_contract( + &mut self, + contract: &SignedContract, + ) -> Result, Error> { let closable_contract_info = self.get_closable_contract_info(contract); if let Some((contract_info, adaptor_info, attestations)) = closable_contract_info { let cet = crate::contract_updater::get_signed_cet( @@ -567,7 +584,7 @@ where ) { Ok(closed_contract) => { self.store.update_contract(&closed_contract)?; - return Ok(()); + return Ok(Some(closed_contract.get_id())); } Err(e) => { warn!( @@ -582,24 +599,30 @@ where self.check_refund(contract)?; - Ok(()) + Ok(None) } - fn check_preclosed_contracts(&mut self) -> Result<(), Error> { + fn check_preclosed_contracts(&mut self) -> Result, Error> { + let mut contracts_to_close = Vec::new(); for c in self.store.get_preclosed_contracts()? { - if let Err(e) = self.check_preclosed_contract(&c) { - error!( + match self.check_preclosed_contract(&c) { + Ok(Some(contract_id)) => contracts_to_close.push(contract_id), + Ok(None) => (), + Err(e) => error!( "Error checking pre-closed contract {}: {}", c.signed_contract.accepted_contract.get_contract_id_string(), e - ) + ), } } - Ok(()) + Ok(contracts_to_close) } - fn check_preclosed_contract(&mut self, contract: &PreClosedContract) -> Result<(), Error> { + fn check_preclosed_contract( + &mut self, + contract: &PreClosedContract, + ) -> Result, Error> { let broadcasted_txid = contract.signed_cet.txid(); let confirmations = self .blockchain @@ -625,10 +648,11 @@ where .compute_pnl(&contract.signed_cet), }; self.store - .update_contract(&Contract::Closed(closed_contract))?; + .update_contract(&Contract::Closed(closed_contract.clone()))?; + return Ok(Some(closed_contract.contract_id)); } - Ok(()) + Ok(None) } fn close_contract( @@ -2199,6 +2223,8 @@ mod test { use secp256k1_zkp::PublicKey; use std::{collections::HashMap, rc::Rc}; + use crate::AffectedContractIDs; + type TestManager = Manager< Rc, Rc, @@ -2267,4 +2293,29 @@ mod test { .on_dlc_message(&offer_message, pubkey()) .expect_err("To reject the second offer message"); } + + #[test] + fn periodic_check_should_return_affected_contracts() { + let mut manager = get_manager(); + + let offer_message = Message::Offer( + serde_json::from_str(include_str!("../test_inputs/offer_contract.json")).unwrap(), + ); + + manager + .on_dlc_message(&offer_message, pubkey()) + .expect("To accept the first offer message"); + + let affected_contracts = manager.periodic_check().unwrap(); + + let expected_affected_contracts = AffectedContractIDs { + confirmed_contracts: vec![], + pre_closed_contracts: vec![], + closed_contracts: vec![], + }; + assert_eq!( + expected_affected_contracts.confirmed_contracts, + affected_contracts.confirmed_contracts + ); + } } From b61b2122036c9e4d6e678e405929522141e46a5b Mon Sep 17 00:00:00 2001 From: sosaucily Date: Mon, 10 Jul 2023 16:22:25 +0200 Subject: [PATCH 06/12] remove unused imports --- dlc-manager/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlc-manager/Cargo.toml b/dlc-manager/Cargo.toml index 12c92421..3bbd99d4 100644 --- a/dlc-manager/Cargo.toml +++ b/dlc-manager/Cargo.toml @@ -24,7 +24,6 @@ log = "0.4.14" rand_chacha = {version = "0.3.1", optional = true} secp256k1-zkp = {version = "0.7.0", features = ["bitcoin_hashes", "rand", "rand-std"]} serde = {version = "1.0", optional = true} -serde_json = "1.0" [dev-dependencies] bitcoin-rpc-provider = {path = "../bitcoin-rpc-provider"} @@ -36,7 +35,6 @@ dlc-manager = {path = ".", features = ["use-serde"]} dlc-messages = {path = "../dlc-messages", features = ["serde"]} electrs-blockchain-provider = {path = "../electrs-blockchain-provider"} env_logger = "0.9.1" -mockito = "0.31.0" mocks = {path = "../mocks"} secp256k1-zkp = {version = "0.7.0", features = ["bitcoin_hashes", "rand", "rand-std", "global-context", "use-serde"]} serde = "1.0" From 23f0ee722fc58aae02a6b4add74cb8bc5482df32 Mon Sep 17 00:00:00 2001 From: sosaucily Date: Tue, 11 Jul 2023 14:45:31 +0200 Subject: [PATCH 07/12] Revert "remove default features for simple-wallet bdk" This reverts commit 96b30b7d345c5029de58e98f0a6247a35f396bf7. --- simple-wallet/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-wallet/Cargo.toml b/simple-wallet/Cargo.toml index 80428df6..fa822adb 100644 --- a/simple-wallet/Cargo.toml +++ b/simple-wallet/Cargo.toml @@ -10,7 +10,7 @@ bitcoin = "0.29" dlc = {path = "../dlc"} dlc-manager = {path = "../dlc-manager"} lightning = {version = "0.0.113"} -bdk = {version = "0.28.0", default-features = false, features = ["async-interface", "use-esplora-async"]} +bdk = {version = "0.28.0"} secp256k1-zkp = {version = "0.7.0"} [dev-dependencies] From 06c3a30cf001ad1fb56038349c4e85fea7a6e073 Mon Sep 17 00:00:00 2001 From: sosaucily Date: Tue, 11 Jul 2023 14:45:38 +0200 Subject: [PATCH 08/12] Revert "update miniscript to prevent compile errors" This reverts commit 800bc0b6ccc4bd55779b377ae2e6c7a871f3cca5. --- dlc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlc/Cargo.toml b/dlc/Cargo.toml index a6c5cb15..e2039838 100644 --- a/dlc/Cargo.toml +++ b/dlc/Cargo.toml @@ -9,7 +9,7 @@ version = "0.4.0" [dependencies] bitcoin = {version = "0.29.2"} -miniscript = { version = "9.0", features = ["serde", "std"], default-features = false } +miniscript = "8.0.0" secp256k1-sys = {version = "0.6.1" } secp256k1-zkp = {version = "0.7.0", features = ["bitcoin_hashes", "rand-std"]} serde = {version = "1.0", default-features = false, optional = true} From c3656455a5d5044de2506f3803cac5a352d16d65 Mon Sep 17 00:00:00 2001 From: sosaucily Date: Wed, 12 Jul 2023 10:17:09 +0200 Subject: [PATCH 09/12] WIP: log in tests --- dlc-manager/src/lib.rs | 2 +- dlc-manager/src/manager.rs | 74 ++++++-------------- dlc-manager/tests/manager_execution_tests.rs | 52 +++++++++----- 3 files changed, 55 insertions(+), 73 deletions(-) diff --git a/dlc-manager/src/lib.rs b/dlc-manager/src/lib.rs index 6c35dee0..7a7ba67e 100644 --- a/dlc-manager/src/lib.rs +++ b/dlc-manager/src/lib.rs @@ -202,7 +202,7 @@ impl_dlc_writeable!(Utxo, { /// The response from periodic_check fn which returns the ids of the contracts that were affected in each state. #[derive(Clone, Debug)] -pub struct AffectedContractIDs { +pub struct UpdatedContractIDs { /// The list of contracts that were moved into the confirmed state. pub confirmed_contracts: Vec, /// The list of contracts that were moved into the pre-closed state. diff --git a/dlc-manager/src/manager.rs b/dlc-manager/src/manager.rs index 2d1063b4..2a46d682 100644 --- a/dlc-manager/src/manager.rs +++ b/dlc-manager/src/manager.rs @@ -15,8 +15,8 @@ use crate::contract::{ }; use crate::contract_updater::{accept_contract, verify_accepted_and_sign_contract}; use crate::error::Error; -use crate::{AffectedContractIDs, Signer}; use crate::{ChannelId, ContractId}; +use crate::{Signer, UpdatedContractIDs}; use bitcoin::Address; use bitcoin::Transaction; use dlc_messages::channel::{ @@ -330,8 +330,8 @@ where /// Function to call to check the state of the currently executing DLCs and /// update them if possible. - pub fn periodic_check(&mut self) -> Result { - let affected_contracts = AffectedContractIDs { + pub fn periodic_check(&mut self) -> Result { + let affected_contracts = UpdatedContractIDs { confirmed_contracts: self.check_signed_contracts()?, pre_closed_contracts: self.check_confirmed_contracts()?, closed_contracts: self.check_preclosed_contracts()?, @@ -472,27 +472,24 @@ where Err(e) } - fn check_signed_contract( - &mut self, - contract: &SignedContract, - ) -> Result, Error> { + fn check_signed_contract(&mut self, contract: &SignedContract) -> Result { let confirmations = self.blockchain.get_transaction_confirmations( &contract.accepted_contract.dlc_transactions.fund.txid(), )?; if confirmations >= NB_CONFIRMATIONS { self.store .update_contract(&Contract::Confirmed(contract.clone()))?; - return Ok(Some(contract.accepted_contract.get_contract_id())); + return Ok(true); } - Ok(None) + Ok(false) } fn check_signed_contracts(&mut self) -> Result, Error> { let mut contracts_to_confirm = Vec::new(); for c in self.store.get_signed_contracts()? { match self.check_signed_contract(&c) { - Ok(Some(contract_id)) => contracts_to_confirm.push(contract_id), - Ok(None) => (), + Ok(true) => contracts_to_confirm.push(c.accepted_contract.get_contract_id()), + Ok(false) => (), Err(e) => error!( "Error checking confirmed contract {}: {}", c.accepted_contract.get_contract_id_string(), @@ -519,8 +516,8 @@ where e ) } - Ok(Some(contract_id)) => contracts_to_close.push(contract_id), - Ok(None) => (), + Ok(true) => contracts_to_close.push(c.accepted_contract.get_contract_id()), + Ok(false) => (), } } @@ -563,10 +560,7 @@ where None } - fn check_confirmed_contract( - &mut self, - contract: &SignedContract, - ) -> Result, Error> { + fn check_confirmed_contract(&mut self, contract: &SignedContract) -> Result { let closable_contract_info = self.get_closable_contract_info(contract); if let Some((contract_info, adaptor_info, attestations)) = closable_contract_info { let cet = crate::contract_updater::get_signed_cet( @@ -584,7 +578,7 @@ where ) { Ok(closed_contract) => { self.store.update_contract(&closed_contract)?; - return Ok(Some(closed_contract.get_id())); + return Ok(true); } Err(e) => { warn!( @@ -599,15 +593,17 @@ where self.check_refund(contract)?; - Ok(None) + Ok(false) } fn check_preclosed_contracts(&mut self) -> Result, Error> { let mut contracts_to_close = Vec::new(); for c in self.store.get_preclosed_contracts()? { match self.check_preclosed_contract(&c) { - Ok(Some(contract_id)) => contracts_to_close.push(contract_id), - Ok(None) => (), + Ok(true) => { + contracts_to_close.push(c.signed_contract.accepted_contract.get_contract_id()) + } + Ok(false) => (), Err(e) => error!( "Error checking pre-closed contract {}: {}", c.signed_contract.accepted_contract.get_contract_id_string(), @@ -619,10 +615,7 @@ where Ok(contracts_to_close) } - fn check_preclosed_contract( - &mut self, - contract: &PreClosedContract, - ) -> Result, Error> { + fn check_preclosed_contract(&mut self, contract: &PreClosedContract) -> Result { let broadcasted_txid = contract.signed_cet.txid(); let confirmations = self .blockchain @@ -649,10 +642,10 @@ where }; self.store .update_contract(&Contract::Closed(closed_contract.clone()))?; - return Ok(Some(closed_contract.contract_id)); + return Ok(true); } - Ok(None) + Ok(false) } fn close_contract( @@ -2223,8 +2216,6 @@ mod test { use secp256k1_zkp::PublicKey; use std::{collections::HashMap, rc::Rc}; - use crate::AffectedContractIDs; - type TestManager = Manager< Rc, Rc, @@ -2293,29 +2284,4 @@ mod test { .on_dlc_message(&offer_message, pubkey()) .expect_err("To reject the second offer message"); } - - #[test] - fn periodic_check_should_return_affected_contracts() { - let mut manager = get_manager(); - - let offer_message = Message::Offer( - serde_json::from_str(include_str!("../test_inputs/offer_contract.json")).unwrap(), - ); - - manager - .on_dlc_message(&offer_message, pubkey()) - .expect("To accept the first offer message"); - - let affected_contracts = manager.periodic_check().unwrap(); - - let expected_affected_contracts = AffectedContractIDs { - confirmed_contracts: vec![], - pre_closed_contracts: vec![], - closed_contracts: vec![], - }; - assert_eq!( - expected_affected_contracts.confirmed_contracts, - affected_contracts.confirmed_contracts - ); - } } diff --git a/dlc-manager/tests/manager_execution_tests.rs b/dlc-manager/tests/manager_execution_tests.rs index 5d5109f8..0c78fe9d 100644 --- a/dlc-manager/tests/manager_execution_tests.rs +++ b/dlc-manager/tests/manager_execution_tests.rs @@ -11,6 +11,7 @@ mod test_utils; use bitcoin::Amount; use dlc_manager::payout_curve::PayoutFunctionPiece; use electrs_blockchain_provider::ElectrsBlockchainProvider; +use log::debug; use simple_wallet::SimpleWallet; use test_utils::*; @@ -18,7 +19,7 @@ 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_manager::{Blockchain, ContractId, Oracle, Storage, UpdatedContractIDs, Wallet}; use dlc_messages::{AcceptDlc, OfferDlc, SignDlc}; use dlc_messages::{CetAdaptorSignatures, Message}; use lightning::ln::wire::Type; @@ -87,14 +88,16 @@ fn create_test_vector() { } macro_rules! periodic_check { - ($d:expr, $id:expr, $p:ident) => { - $d.lock() + ($d:expr, $id:expr, $p:ident) => {{ + let updated_contract_ids = $d + .lock() .unwrap() .periodic_check() .expect("Periodic check error"); assert_contract_state!($d, $id, $p); - }; + updated_contract_ids + }}; } fn numerical_common( @@ -638,7 +641,10 @@ fn manager_execution_test(test_params: TestParams, path: TestPath) { assert_contract_state!(bob_manager_send, contract_id, Signed); // Should not change state and should not error - periodic_check!(bob_manager_send, contract_id, Signed); + debug!( + "{:?}", + periodic_check!(bob_manager_send, contract_id, Signed) + ); sync_receive.recv().expect("Error synchronizing"); @@ -646,8 +652,18 @@ fn manager_execution_test(test_params: TestParams, path: TestPath) { generate_blocks(6); - periodic_check!(alice_manager_send, contract_id, Confirmed); - periodic_check!(bob_manager_send, contract_id, Confirmed); + debug!( + "{:?}", + periodic_check!(alice_manager_send, contract_id, Confirmed) + ); + let updated_contract_ids: UpdatedContractIDs = + periodic_check!(bob_manager_send, contract_id, Confirmed); + debug!("updated contract ids: {:?}", updated_contract_ids); + assert_eq!(updated_contract_ids.confirmed_contracts, vec![contract_id]); + assert_eq!( + updated_contract_ids.closed_contracts, + Vec::::new() + ); mocks::mock_time::set_time((EVENT_MATURITY as u64) + 1); @@ -660,29 +676,29 @@ fn manager_execution_test(test_params: TestParams, path: TestPath) { match path { TestPath::Close => { - periodic_check!(first, contract_id, PreClosed); + debug!("{:?}", periodic_check!(first, contract_id, PreClosed)); // Randomly check with or without having the CET mined let case = thread_rng().next_u64() % 3; if case == 2 { // cet becomes fully confirmed to blockchain generate_blocks(6); - periodic_check!(first, contract_id, Closed); - periodic_check!(second, contract_id, Closed); + debug!("{:?}", periodic_check!(first, contract_id, Closed)); + debug!("{:?}", periodic_check!(second, contract_id, Closed)); } else if case == 1 { // cet is not yet fully confirmed to blockchain generate_blocks(1); - periodic_check!(first, contract_id, PreClosed); - periodic_check!(second, contract_id, PreClosed); + debug!("{:?}", periodic_check!(first, contract_id, PreClosed)); + debug!("{:?}", periodic_check!(second, contract_id, PreClosed)); } else { - periodic_check!(first, contract_id, PreClosed); - periodic_check!(second, contract_id, PreClosed); + debug!("{:?}", periodic_check!(first, contract_id, PreClosed)); + debug!("{:?}", periodic_check!(second, contract_id, PreClosed)); } } TestPath::Refund => { - periodic_check!(first, contract_id, Confirmed); + debug!("{:?}", periodic_check!(first, contract_id, Confirmed)); - periodic_check!(second, contract_id, Confirmed); + debug!("{:?}", periodic_check!(second, contract_id, Confirmed)); mocks::mock_time::set_time( ((EVENT_MATURITY + dlc_manager::manager::REFUND_DELAY) as u64) + 1, @@ -690,14 +706,14 @@ fn manager_execution_test(test_params: TestParams, path: TestPath) { generate_blocks(10); - periodic_check!(first, contract_id, Refunded); + debug!("{:?}", 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); } - periodic_check!(second, contract_id, Refunded); + debug!("{:?}", periodic_check!(second, contract_id, Refunded)); } _ => unreachable!(), } From 784c2035868c0012db81e78f08a5a695aebf5e65 Mon Sep 17 00:00:00 2001 From: sosaucily Date: Wed, 12 Jul 2023 11:40:59 +0200 Subject: [PATCH 10/12] switch to a single return vector --- dlc-manager/src/lib.rs | 11 ----- dlc-manager/src/manager.rs | 14 +++--- dlc-manager/tests/manager_execution_tests.rs | 46 +++++++++----------- 3 files changed, 28 insertions(+), 43 deletions(-) diff --git a/dlc-manager/src/lib.rs b/dlc-manager/src/lib.rs index 7a7ba67e..d6707ec8 100644 --- a/dlc-manager/src/lib.rs +++ b/dlc-manager/src/lib.rs @@ -199,14 +199,3 @@ impl_dlc_writeable!(Utxo, { (redeem_script, writeable), (reserved, writeable) }); - -/// The response from periodic_check fn which returns the ids of the contracts that were affected in each state. -#[derive(Clone, Debug)] -pub struct UpdatedContractIDs { - /// The list of contracts that were moved into the confirmed state. - pub confirmed_contracts: Vec, - /// The list of contracts that were moved into the pre-closed state. - pub pre_closed_contracts: Vec, - /// The list of contracts that were moved into the closed state. - pub closed_contracts: Vec, -} diff --git a/dlc-manager/src/manager.rs b/dlc-manager/src/manager.rs index 2a46d682..ad4e3ce0 100644 --- a/dlc-manager/src/manager.rs +++ b/dlc-manager/src/manager.rs @@ -15,8 +15,8 @@ use crate::contract::{ }; use crate::contract_updater::{accept_contract, verify_accepted_and_sign_contract}; use crate::error::Error; +use crate::Signer; use crate::{ChannelId, ContractId}; -use crate::{Signer, UpdatedContractIDs}; use bitcoin::Address; use bitcoin::Transaction; use dlc_messages::channel::{ @@ -330,12 +330,12 @@ where /// Function to call to check the state of the currently executing DLCs and /// update them if possible. - pub fn periodic_check(&mut self) -> Result { - let affected_contracts = UpdatedContractIDs { - confirmed_contracts: self.check_signed_contracts()?, - pre_closed_contracts: self.check_confirmed_contracts()?, - closed_contracts: self.check_preclosed_contracts()?, - }; + pub fn periodic_check(&mut self) -> Result, Error> { + let mut affected_contracts = Vec::::new(); + affected_contracts.extend_from_slice(&self.check_signed_contracts()?); + affected_contracts.extend_from_slice(&self.check_confirmed_contracts()?); + affected_contracts.extend_from_slice(&self.check_preclosed_contracts()?); + self.channel_checks()?; Ok(affected_contracts) diff --git a/dlc-manager/tests/manager_execution_tests.rs b/dlc-manager/tests/manager_execution_tests.rs index 0c78fe9d..8b0e5c09 100644 --- a/dlc-manager/tests/manager_execution_tests.rs +++ b/dlc-manager/tests/manager_execution_tests.rs @@ -19,7 +19,7 @@ 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, ContractId, Oracle, Storage, UpdatedContractIDs, Wallet}; +use dlc_manager::{Blockchain, Oracle, Storage, Wallet}; use dlc_messages::{AcceptDlc, OfferDlc, SignDlc}; use dlc_messages::{CetAdaptorSignatures, Message}; use lightning::ln::wire::Type; @@ -641,10 +641,7 @@ fn manager_execution_test(test_params: TestParams, path: TestPath) { assert_contract_state!(bob_manager_send, contract_id, Signed); // Should not change state and should not error - debug!( - "{:?}", - periodic_check!(bob_manager_send, contract_id, Signed) - ); + periodic_check!(bob_manager_send, contract_id, Signed); sync_receive.recv().expect("Error synchronizing"); @@ -652,17 +649,13 @@ fn manager_execution_test(test_params: TestParams, path: TestPath) { generate_blocks(6); - debug!( - "{:?}", - periodic_check!(alice_manager_send, contract_id, Confirmed) + assert_eq!( + periodic_check!(alice_manager_send, contract_id, Confirmed), + vec![contract_id] ); - let updated_contract_ids: UpdatedContractIDs = - periodic_check!(bob_manager_send, contract_id, Confirmed); - debug!("updated contract ids: {:?}", updated_contract_ids); - assert_eq!(updated_contract_ids.confirmed_contracts, vec![contract_id]); assert_eq!( - updated_contract_ids.closed_contracts, - Vec::::new() + periodic_check!(bob_manager_send, contract_id, Confirmed), + vec![contract_id] ); mocks::mock_time::set_time((EVENT_MATURITY as u64) + 1); @@ -676,29 +669,29 @@ fn manager_execution_test(test_params: TestParams, path: TestPath) { match path { TestPath::Close => { - debug!("{:?}", periodic_check!(first, contract_id, PreClosed)); + periodic_check!(first, contract_id, PreClosed); // Randomly check with or without having the CET mined let case = thread_rng().next_u64() % 3; if case == 2 { // cet becomes fully confirmed to blockchain generate_blocks(6); - debug!("{:?}", periodic_check!(first, contract_id, Closed)); - debug!("{:?}", periodic_check!(second, contract_id, Closed)); + periodic_check!(first, contract_id, Closed); + periodic_check!(second, contract_id, Closed); } else if case == 1 { // cet is not yet fully confirmed to blockchain generate_blocks(1); - debug!("{:?}", periodic_check!(first, contract_id, PreClosed)); - debug!("{:?}", periodic_check!(second, contract_id, PreClosed)); + periodic_check!(first, contract_id, PreClosed); + periodic_check!(second, contract_id, PreClosed); } else { - debug!("{:?}", periodic_check!(first, contract_id, PreClosed)); - debug!("{:?}", periodic_check!(second, contract_id, PreClosed)); + periodic_check!(first, contract_id, PreClosed); + periodic_check!(second, contract_id, PreClosed); } } TestPath::Refund => { - debug!("{:?}", periodic_check!(first, contract_id, Confirmed)); + periodic_check!(first, contract_id, Confirmed); - debug!("{:?}", 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, @@ -706,14 +699,17 @@ fn manager_execution_test(test_params: TestParams, path: TestPath) { generate_blocks(10); - debug!("{:?}", 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); } - debug!("{:?}", periodic_check!(second, contract_id, Refunded)); + debug!( + "{:?} asdfasdfasdf", + periodic_check!(second, contract_id, Refunded) + ); } _ => unreachable!(), } From 60cf0d792b058d6fccf6f4e5f5bbe13d367a3384 Mon Sep 17 00:00:00 2001 From: sosaucily Date: Wed, 12 Jul 2023 15:17:34 +0200 Subject: [PATCH 11/12] Revert "Revert "update miniscript to prevent compile errors"" This reverts commit 06c3a30cf001ad1fb56038349c4e85fea7a6e073. --- dlc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlc/Cargo.toml b/dlc/Cargo.toml index e2039838..a6c5cb15 100644 --- a/dlc/Cargo.toml +++ b/dlc/Cargo.toml @@ -9,7 +9,7 @@ version = "0.4.0" [dependencies] bitcoin = {version = "0.29.2"} -miniscript = "8.0.0" +miniscript = { version = "9.0", features = ["serde", "std"], default-features = false } secp256k1-sys = {version = "0.6.1" } secp256k1-zkp = {version = "0.7.0", features = ["bitcoin_hashes", "rand-std"]} serde = {version = "1.0", default-features = false, optional = true} From e59ed0ce2a7d10ab974b5890f8c0d0fb103c761a Mon Sep 17 00:00:00 2001 From: sosaucily Date: Wed, 12 Jul 2023 15:17:41 +0200 Subject: [PATCH 12/12] Revert "Revert "remove default features for simple-wallet bdk"" This reverts commit 23f0ee722fc58aae02a6b4add74cb8bc5482df32. --- simple-wallet/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-wallet/Cargo.toml b/simple-wallet/Cargo.toml index fa822adb..80428df6 100644 --- a/simple-wallet/Cargo.toml +++ b/simple-wallet/Cargo.toml @@ -10,7 +10,7 @@ bitcoin = "0.29" dlc = {path = "../dlc"} dlc-manager = {path = "../dlc-manager"} lightning = {version = "0.0.113"} -bdk = {version = "0.28.0"} +bdk = {version = "0.28.0", default-features = false, features = ["async-interface", "use-esplora-async"]} secp256k1-zkp = {version = "0.7.0"} [dev-dependencies]