Skip to content

Commit 9ce1421

Browse files
0xEgaostark-3k
andauthored
test: added few taproot integration test case (#649)
* test: added few taproot integration test case * test: added remaining test cases * test: use absolute value for testing,mark bad makers * do not mark bad makers as good * fmt fix * add todos for test --------- Co-authored-by: Rishabh <rishkwal@gmail.com>
1 parent be3e089 commit 9ce1421

17 files changed

+2171
-457
lines changed

src/bin/taker.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use log::LevelFilter;
1010
use serde_json::{json, to_string_pretty};
1111
use std::{path::PathBuf, str::FromStr};
1212

13+
#[cfg(feature = "integration-test")]
14+
use coinswap::taker::api2::TakerBehavior as TaprootTakerBehavior;
1315
#[cfg(feature = "integration-test")]
1416
use coinswap::taker::TakerBehavior;
1517

@@ -200,6 +202,8 @@ fn main() -> Result<(), TakerError> {
200202
args.tor_auth,
201203
args.zmq,
202204
None,
205+
#[cfg(feature = "integration-test")]
206+
TaprootTakerBehavior::Normal,
203207
)?;
204208
taproot_taker.recover_from_swap()?;
205209
}
@@ -214,6 +218,8 @@ fn main() -> Result<(), TakerError> {
214218
args.tor_auth,
215219
args.zmq,
216220
None,
221+
#[cfg(feature = "integration-test")]
222+
TaprootTakerBehavior::Normal,
217223
)?;
218224

219225
let taproot_swap_params = coinswap::taker::api2::SwapParams {

src/maker/api2.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ pub enum MakerBehavior {
6565
/// Close connection after sweeping incoming contract but before completing handover
6666
/// This allows maker to recover their coins but forces taker to recover via hashlock/timelock
6767
CloseAfterSweep,
68+
/// Close connection after accepting Swap offer from taker and sending it AckResponse message.
69+
CloseAfterAckResponse,
6870
}
6971

7072
/// Interval for health checks on a stable RPC connection with bitcoind.
@@ -925,6 +927,20 @@ impl Maker {
925927
.contract_tx
926928
.compute_txid();
927929

930+
for (vout, _) in connection_state
931+
.incoming_contract
932+
.contract_tx
933+
.output
934+
.iter()
935+
.enumerate()
936+
{
937+
let outpoint = OutPoint {
938+
txid: incoming_txid,
939+
vout: vout as u32,
940+
};
941+
self.watch_service.unwatch(outpoint);
942+
}
943+
928944
// Record the swept coin to track swap balance
929945
let output_scriptpubkey = spending_tx.output[0].script_pubkey.clone();
930946
wallet

src/maker/handlers2.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,18 @@ fn handle_swap_details(
119119
our_fee
120120
);
121121

122+
// Check for CloseAfterAckResponse behavior
123+
#[cfg(feature = "integration-test")]
124+
if maker.behavior == super::api2::MakerBehavior::CloseAfterAckResponse {
125+
log::warn!(
126+
"[{}] Maker behavior: CloseAfterAckResponse - Closing connection after sending Ack Response message to taker",
127+
maker.config.network_port
128+
);
129+
return Err(MakerError::General(
130+
"Maker closing connection after sending AckResponse to taker (test behavior)",
131+
));
132+
}
133+
122134
// Send acknowledgment
123135
Ok(Some(MakerToTakerMessage::AckResponse(AckResponse::Ack)))
124136
}

src/taker/api2.rs

Lines changed: 100 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::error::TakerError;
12
use crate::{
23
protocol::{
34
contract2::{
@@ -52,7 +53,20 @@ use std::{
5253
collections::HashSet, net::TcpStream, path::PathBuf, sync::mpsc, thread, time::Duration,
5354
};
5455

55-
use super::error::TakerError;
56+
/// Represents different behaviors taker can have during the swap.
57+
/// Used for testing various possible scenarios that can happen during a swap.
58+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59+
#[cfg(feature = "integration-test")]
60+
pub enum TakerBehavior {
61+
/// Normal behaviour
62+
Normal,
63+
/// Close connection after receiving AckResponse message from the maker. (no outgoing/incoming contract created)
64+
CloseAtAckResponse,
65+
/// Close connection after sending SendersContract (outgoing contract created)
66+
CloseAtSendersContract,
67+
/// Close connection after receiving SendersContract from maker (outgoing contract created).
68+
CloseAtSendersContractFromMaker,
69+
}
5670

5771
/// Represents how a taproot contract output was spent
5872
#[derive(Debug, Clone)]
@@ -201,6 +215,8 @@ pub struct Taker {
201215
ongoing_swap_state: OngoingSwapState,
202216
watch_service: WatchService,
203217
offer_sync_handle: OfferSyncHandle,
218+
#[cfg(feature = "integration-test")]
219+
behavior: TakerBehavior,
204220
}
205221

206222
impl Drop for Taker {
@@ -219,6 +235,7 @@ impl Drop for Taker {
219235

220236
impl Taker {
221237
/// Initialize a new Taker instance
238+
#[allow(clippy::too_many_arguments)]
222239
pub fn init(
223240
data_dir: Option<PathBuf>,
224241
wallet_file_name: Option<String>,
@@ -227,6 +244,7 @@ impl Taker {
227244
tor_auth_password: Option<String>,
228245
zmq_addr: String,
229246
password: Option<String>,
247+
#[cfg(feature = "integration-test")] behavior: TakerBehavior,
230248
) -> Result<Taker, TakerError> {
231249
let data_dir = data_dir.unwrap_or_else(get_taker_dir);
232250

@@ -302,6 +320,8 @@ impl Taker {
302320
ongoing_swap_state: OngoingSwapState::default(),
303321
watch_service,
304322
offer_sync_handle,
323+
#[cfg(feature = "integration-test")]
324+
behavior,
305325
})
306326
}
307327

@@ -348,6 +368,16 @@ impl Taker {
348368
self.choose_makers_for_swap(swap_params)?;
349369
self.setup_contract_keys_and_scripts()?;
350370

371+
#[cfg(feature = "integration-test")]
372+
{
373+
if self.behavior == TakerBehavior::CloseAtAckResponse {
374+
log::error!(
375+
"Dropping Swap Process after receiving Ack Response message from maker"
376+
);
377+
return Err(TakerError::General("Taker Dropping after receiving AckResponse message from maker. (Test behavior)".to_string(),));
378+
}
379+
}
380+
351381
let outgoing_signed_contract_transactions = self.create_outgoing_contract_transactions()?;
352382
let tx = match outgoing_signed_contract_transactions.first() {
353383
Some(tx) => tx,
@@ -380,7 +410,6 @@ impl Taker {
380410
for tx in &outgoing_signed_contract_transactions {
381411
self.wallet.wait_for_tx_confirmation(tx.compute_txid())?;
382412
}
383-
384413
match self
385414
.negotiate_with_makers_and_coordinate_sweep(&outgoing_signed_contract_transactions)
386415
{
@@ -391,6 +420,7 @@ impl Taker {
391420

392421
// Store swap state before reset for report generation
393422
let prereset_swapstate = self.ongoing_swap_state.clone();
423+
self.ongoing_swap_state = OngoingSwapState::default();
394424

395425
// Sync wallet and generate report
396426
self.wallet.sync_and_save()?;
@@ -763,19 +793,20 @@ impl Taker {
763793
};
764794

765795
let msg = TakerToMakerMessage::SwapDetails(swap_details);
766-
let response = self.send_to_maker_and_get_response(&suitable_maker.address, msg)?;
796+
let response = self.send_to_maker_and_get_response(&suitable_maker.address, msg);
767797
match response {
768-
MakerToTakerMessage::AckResponse(AckResponse::Ack) => {
798+
Ok(MakerToTakerMessage::AckResponse(AckResponse::Ack)) => {
769799
log::info!("Received AckResponse from maker: {:?}", suitable_maker);
770800
self.ongoing_swap_state
771801
.chosen_makers
772802
.push(suitable_maker.clone());
773803
}
774-
MakerToTakerMessage::AckResponse(AckResponse::Nack) => {
804+
Ok(MakerToTakerMessage::AckResponse(AckResponse::Nack)) => {
775805
log::warn!("Maker {:?} did not accept the swap request", suitable_maker);
776806
continue;
777807
}
778808
_ => {
809+
self.offerbook.add_bad_maker(suitable_maker);
779810
log::warn!("Received unexpected message from maker: {:?}", response);
780811
continue;
781812
}
@@ -872,6 +903,10 @@ impl Taker {
872903

873904
suitable_makers
874905
}
906+
/// Get all the bad makers
907+
pub fn get_bad_makers(&self) -> Vec<OfferAndAddress> {
908+
self.offerbook.get_bad_makers(&MakerProtocol::Taproot)
909+
}
875910

876911
/// Setup contract keys and scripts for the swap
877912
fn setup_contract_keys_and_scripts(&mut self) -> Result<(), TakerError> {
@@ -1052,13 +1087,24 @@ impl Taker {
10521087
};
10531088

10541089
let msg = TakerToMakerMessage::SendersContract(senders_contract.clone());
1055-
let response = self.send_to_maker_and_get_response(&first_maker.address, msg)?;
1090+
let response = self.send_to_maker_and_get_response(&first_maker.address, msg);
1091+
#[cfg(feature = "integration-test")]
1092+
{
1093+
if self.behavior == TakerBehavior::CloseAtSendersContract {
1094+
log::error!("Dropping connection after sending SendersContract to Maker");
1095+
return Err(TakerError::General(
1096+
"Taker dropping of after sending Senders Contract to Maker (test behavior) "
1097+
.to_string(),
1098+
));
1099+
}
1100+
}
10561101

10571102
match response {
1058-
MakerToTakerMessage::SenderContractFromMaker(incoming_contract) => {
1103+
Ok(MakerToTakerMessage::SenderContractFromMaker(incoming_contract)) => {
10591104
self.forward_contracts_and_coordinate_sweep(incoming_contract)?;
10601105
}
10611106
_ => {
1107+
self.offerbook.add_bad_maker(first_maker);
10621108
return Err(TakerError::General(
10631109
"Unexpected response from first maker".to_string(),
10641110
));
@@ -1124,11 +1170,21 @@ impl Taker {
11241170
};
11251171

11261172
let forward_msg = TakerToMakerMessage::SendersContract(forward_contract);
1127-
let maker_response =
1128-
self.send_to_maker_and_get_response(&maker.address, forward_msg)?;
1173+
let maker_response = self.send_to_maker_and_get_response(&maker.address, forward_msg);
11291174

11301175
match maker_response {
1131-
MakerToTakerMessage::SenderContractFromMaker(maker_contract) => {
1176+
Ok(MakerToTakerMessage::SenderContractFromMaker(maker_contract)) => {
1177+
#[cfg(feature = "integration-test")]
1178+
{
1179+
if self.behavior == TakerBehavior::CloseAtSendersContractFromMaker {
1180+
log::error!(
1181+
"Dropping connection after receiving Sender Contract from Maker"
1182+
);
1183+
return Err(TakerError::General(
1184+
"Taker dropping of after receiving Senders Contract from Maker (test behavior) ".to_string(),));
1185+
}
1186+
}
1187+
11321188
if maker_index == maker_count - 1 {
11331189
// This is the last maker - store its response as final contract data
11341190
self.store_final_contract_data(&maker_contract)?;
@@ -1140,6 +1196,7 @@ impl Taker {
11401196
}
11411197
}
11421198
_ => {
1199+
self.offerbook.add_bad_maker(maker);
11431200
return Err(TakerError::General(format!(
11441201
"Unexpected response from maker {}",
11451202
maker_index
@@ -1272,15 +1329,28 @@ impl Taker {
12721329
});
12731330

12741331
// Send to maker and get their outgoing key in response
1275-
let response = self.send_to_maker_and_get_response(&maker_address, privkey_msg)?;
1276-
1332+
let response = self.send_to_maker_and_get_response(&maker_address, privkey_msg);
12771333
// remove taker's outgoing swapcoin since we've handed over the key
12781334
if maker_index == 0 {
12791335
let outgoing_txid = self
12801336
.ongoing_swap_state
12811337
.outgoing_contract
12821338
.contract_tx
12831339
.compute_txid();
1340+
for (vout, _) in self
1341+
.ongoing_swap_state
1342+
.outgoing_contract
1343+
.contract_tx
1344+
.output
1345+
.iter()
1346+
.enumerate()
1347+
{
1348+
let outpoint = OutPoint {
1349+
txid: outgoing_txid,
1350+
vout: vout as u32,
1351+
};
1352+
self.watch_service.unwatch(outpoint);
1353+
}
12841354
self.wallet.remove_outgoing_swapcoin_v2(&outgoing_txid);
12851355
log::info!(
12861356
"Removed taker's outgoing swapcoin {} after sending PrivateKeyHandover",
@@ -1291,7 +1361,7 @@ impl Taker {
12911361

12921362
// Extract maker's outgoing key from response
12931363
match response {
1294-
MakerToTakerMessage::PrivateKeyHandover(maker_privkey_handover) => {
1364+
Ok(MakerToTakerMessage::PrivateKeyHandover(maker_privkey_handover)) => {
12951365
let maker_outgoing_privkey = maker_privkey_handover.secret_key;
12961366

12971367
log::info!(" [Maker {}] Received outgoing private key", maker_index);
@@ -1301,6 +1371,8 @@ impl Taker {
13011371
Some(maker_outgoing_privkey);
13021372
}
13031373
_ => {
1374+
self.offerbook
1375+
.add_bad_maker(&self.ongoing_swap_state.chosen_makers[maker_index]);
13041376
return Err(TakerError::General(format!(
13051377
"Unexpected response from maker {}: expected PrivateKeyHandover",
13061378
maker_index
@@ -1512,6 +1584,21 @@ impl Taker {
15121584
incoming_contract_txid
15131585
);
15141586

1587+
for (vout, _) in self
1588+
.ongoing_swap_state
1589+
.incoming_contract
1590+
.contract_tx
1591+
.output
1592+
.iter()
1593+
.enumerate()
1594+
{
1595+
let outpoint = OutPoint {
1596+
txid: incoming_contract_txid,
1597+
vout: vout as u32,
1598+
};
1599+
self.watch_service.unwatch(outpoint);
1600+
}
1601+
15151602
// Remove the incoming swapcoin since we've successfully swept it
15161603
self.wallet
15171604
.remove_incoming_swapcoin_v2(&incoming_contract_txid);

src/taker/offers.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ impl MakerOfferCandidate {
8585
fn mark_success(&mut self, offer: Offer, protocol: MakerProtocol) {
8686
self.offer = Some(offer);
8787
self.protocol = Some(protocol);
88-
self.state = MakerState::Good;
88+
if self.state != MakerState::Bad {
89+
self.state = MakerState::Good;
90+
}
8991
}
9092

9193
fn mark_failure(&mut self) {

0 commit comments

Comments
 (0)