forked from citadel-tech/coinswap
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtaker_cli.rs
More file actions
180 lines (136 loc) · 5.78 KB
/
taker_cli.rs
File metadata and controls
180 lines (136 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#![cfg(feature = "integration-test")]
use bip39::rand;
use bitcoin::{address::NetworkChecked, Address, Amount};
use bitcoind::{bitcoincore_rpc::RpcApi, tempfile::env::temp_dir, BitcoinD};
use serde_json::Value;
use std::{fs, path::PathBuf, process::Command, str::FromStr};
mod test_framework;
use test_framework::{generate_blocks, init_bitcoind, send_to_address};
use log::info;
/// The taker-cli command struct
struct TakerCli {
data_dir: PathBuf,
bitcoind: BitcoinD,
zmq_addr: String,
}
impl TakerCli {
/// Construct a new [`TakerCli`] struct that also include initiating bitcoind.
fn new() -> TakerCli {
// Initiate the bitcoind backend.
let temp_dir = temp_dir().join("coinswap");
// Remove if previously existing
if temp_dir.exists() {
fs::remove_dir_all(&temp_dir).unwrap();
}
let port_zmq = 28332 + rand::random::<u16>() % 1000;
let zmq_addr = format!("tcp://127.0.0.1:{port_zmq}");
let bitcoind = init_bitcoind(&temp_dir, zmq_addr.clone());
let data_dir = temp_dir.join("taker");
TakerCli {
data_dir,
bitcoind,
zmq_addr,
}
}
// Execute a cli-command
fn execute(&self, cmd: &[&str]) -> String {
let mut args = vec!["--data-directory", self.data_dir.to_str().unwrap()];
// RPC authentication (user:password) from the cookie file
let cookie_file_path = &self.bitcoind.params.cookie_file;
let rpc_auth = fs::read_to_string(cookie_file_path).expect("failed to read from file");
args.push("--USER:PASSWORD");
args.push(&rpc_auth);
// Full node address for RPC connection
let rpc_address = self.bitcoind.params.rpc_socket.to_string();
args.push("--ADDRESS:PORT");
args.push(&rpc_address);
args.push("--WALLET");
args.push("test_wallet");
args.push("--ZMQ");
args.push(&self.zmq_addr);
for arg in cmd {
args.push(arg);
}
let output = Command::new(env!("CARGO_BIN_EXE_taker"))
.args(args)
.output()
.expect("Failed to execute taker");
// Capture the standard output and error from the command execution
let mut value = output.stdout;
let error = output.stderr;
// Panic if there is any error output
if !error.is_empty() {
panic!("Error: {:?}", String::from_utf8(error).unwrap());
}
// Remove the `\n` at the end of the output
value.pop();
// Convert the output bytes to a UTF-8 string
let output_string = std::str::from_utf8(&value).unwrap().to_string();
output_string
}
}
#[test]
fn test_taker_cli() {
info!("🧪 Running Test: Taker CLI functionality and wallet operations");
let taker_cli = TakerCli::new();
info!("🚀 TakerCli initialized successfully");
let bitcoind = &taker_cli.bitcoind;
info!("💰 Funding taker with 3 UTXOs of 1 BTC each");
// Fund the taker with 3 utxos of 1 BTC each.
for _ in 0..3 {
let taker_address = taker_cli.execute(&["get-new-address"]);
let taker_address: Address<NetworkChecked> =
Address::from_str(&taker_address).unwrap().assume_checked();
send_to_address(bitcoind, &taker_address, Amount::ONE_BTC);
}
// confirm balance
generate_blocks(bitcoind, 10);
info!("📊 Verifying initial balance - expecting 3 BTC");
// Assert that total_balance & seed_balance must be 3 BTC
let balances = taker_cli.execute(&["get-balances"]);
let balances = serde_json::from_str::<Value>(&balances).unwrap();
assert_eq!("300000000", balances["regular"].to_string());
assert_eq!("0", balances["swap"].to_string());
assert_eq!("0", balances["contract"].to_string());
assert_eq!("300000000", balances["spendable"].to_string());
info!("🔍 Checking UTXO count - expecting 3 UTXOs");
// Assert that total no of seed-utxos are 3.
let all_utxos = taker_cli.execute(&["list-utxo"]);
let no_of_seed_utxos = all_utxos.matches("addr").count();
assert_eq!(3, no_of_seed_utxos);
info!("✅ Initial setup verification successful");
info!("💸 Testing internal transfer - 100,000 sats with 1,000 sats fee");
// Send 100,000 sats to a new address within the wallet, with a fee of 1,000 sats.
// get new external address
let new_address = taker_cli.execute(&["get-new-address"]);
let _ = taker_cli.execute(&[
"send-to-address",
"-t",
&new_address,
"-a",
"100000",
"-f",
"2",
]);
generate_blocks(bitcoind, 10);
info!("📊 Verifying balance after transfer - expecting only fee deduction");
// Assert the total_amount & seed_amount must be initial (balance -fee)
let balances = taker_cli.execute(&["get-balances"]);
let balances = serde_json::from_str::<Value>(&balances).unwrap();
// Since the amount is sent back to our wallet, the transaction fee is deducted from the balance.
assert_eq!("299999720", balances["regular"].to_string());
assert_eq!("0", balances["swap"].to_string());
assert_eq!("0", balances["contract"].to_string());
assert_eq!("299999720", balances["spendable"].to_string());
info!("🔍 Checking final UTXO count - expecting 4 UTXOs");
// Assert that no of seed utxos are 4
let all_utxos = taker_cli.execute(&["list-utxo"]);
let no_of_seed_utxos = all_utxos.matches("addr").count();
assert_eq!(4, no_of_seed_utxos);
info!("✅ Transfer verification successful");
info!("🔧 Shutting down bitcoind");
bitcoind.client.stop().unwrap();
// Wait for some time for successful shutdown of bitcoind.
std::thread::sleep(std::time::Duration::from_secs(3));
info!("🎉 Taker CLI test completed successfully!");
}