Skip to content

Commit b433c9a

Browse files
committed
Add integration tests for the Electrum JSON-RPC API
Using the headless Electrum wallet daemon: https://electrum.readthedocs.io/en/latest/jsonrpc.html
1 parent 3fe89db commit b433c9a

File tree

5 files changed

+165
-2
lines changed

5 files changed

+165
-2
lines changed

Cargo.lock

Lines changed: 29 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ electrum-client = { version = "0.8", optional = true }
6262

6363
[dev-dependencies]
6464
bitcoind = { version = "0.20.0", features = [ "22_0" ] }
65+
electrumd = { version = "0.1.0", features = [ "4_1_5" ] }
6566
ureq = { version = "2.4", default-features = false, features = [ "json" ] }
6667
tempfile = "3.0"
6768

@@ -78,3 +79,7 @@ rev = "d3792352992a539afffbe11501d1aff9fd5b919d" # add-peer branch
7879
[patch.crates-io.elements]
7980
git = "https://github.com/ElementsProject/rust-elements"
8081
rev = "d988bd7ed9cf539b8fea0da042efa5a4e1eef86f"
82+
83+
[patch.crates-io.electrumd]
84+
git = "https://github.com/shesek/electrumd"
85+
rev = "ea32146dc1db378d4444cd713a27a8ea3919c4c0"

tests/common.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ error_chain::error_chain! {
243243
display("Bitcoind RPC error: {:?}", e)
244244
}
245245

246+
ElectrumD(e: electrumd::Error) {
247+
description("Electrum wallet RPC error")
248+
display("Electrum wallet RPC error: {:?}", e)
249+
}
250+
246251
Io(e: std::io::Error) {
247252
description("IO error")
248253
display("IO error: {:?}", e)
@@ -264,6 +269,11 @@ impl From<bitcoind::bitcoincore_rpc::Error> for Error {
264269
Error::from(ErrorKind::BitcoindRpc(e))
265270
}
266271
}
272+
impl From<electrumd::Error> for Error {
273+
fn from(e: electrumd::Error) -> Self {
274+
Error::from(ErrorKind::ElectrumD(e))
275+
}
276+
}
267277
impl From<std::io::Error> for Error {
268278
fn from(e: std::io::Error) -> Self {
269279
Error::from(ErrorKind::Io(e))

tests/electrum.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
mod common;
2+
use common::Result;
3+
4+
use bitcoind::bitcoincore_rpc::RpcApi;
5+
use electrumd::jsonrpc::serde_json::json;
6+
use electrumd::ElectrumD;
7+
8+
use electrs::chain::Address;
9+
10+
#[test]
11+
fn test_electrum() -> Result<()> {
12+
// Spawn the Electrs Electrum RPC server
13+
let (electrum_server, electrum_addr, mut tester) = common::init_electrum_tester().unwrap();
14+
15+
// Spawn headless Electrum wallet RPC server
16+
let mut electrum_wallet_conf = electrumd::Conf::default();
17+
let server_arg = format!("{}:t", electrum_addr.to_string());
18+
electrum_wallet_conf.args = vec!["-v", "--server", &server_arg];
19+
electrum_wallet_conf.view_stdout = true;
20+
let electrum_wallet =
21+
ElectrumD::with_conf(electrumd::downloaded_exe_path()?, &electrum_wallet_conf)?;
22+
23+
let notify_wallet = || {
24+
electrum_server.notify();
25+
std::thread::sleep(std::time::Duration::from_millis(200));
26+
};
27+
28+
let assert_balance = |confirmed: f64, unconfirmed: f64| {
29+
let balance = electrum_wallet.call("getbalance", &json!([])).unwrap();
30+
log::info!("balance: {}", balance);
31+
32+
assert_eq!(
33+
balance["confirmed"].as_str(),
34+
Some(confirmed.to_string().as_str())
35+
);
36+
if unconfirmed != 0.0 {
37+
assert_eq!(
38+
balance["unconfirmed"].as_str(),
39+
Some(unconfirmed.to_string().as_str())
40+
);
41+
} else {
42+
assert!(balance["unconfirmed"].is_null())
43+
}
44+
};
45+
46+
let newaddress = || -> Address {
47+
electrum_wallet
48+
.call("createnewaddress", &json!([]))
49+
.unwrap()
50+
.as_str()
51+
.expect("missing address")
52+
.parse()
53+
.expect("valid address")
54+
};
55+
56+
log::info!(
57+
"Electrum wallet version: {:?}",
58+
electrum_wallet.call("version", &json!([]))?
59+
);
60+
61+
// Send some funds and verify that the balance checks out
62+
let addr1 = newaddress();
63+
let addr2 = newaddress();
64+
65+
assert_balance(0.0, 0.0);
66+
67+
let txid1 = tester.send(&addr1, "0.1 BTC".parse().unwrap())?;
68+
notify_wallet();
69+
assert_balance(0.0, 0.1);
70+
71+
tester.mine()?;
72+
notify_wallet();
73+
assert_balance(0.1, 0.0);
74+
75+
let txid2 = tester.send(&addr2, "0.2 BTC".parse().unwrap())?;
76+
notify_wallet();
77+
assert_balance(0.1, 0.2);
78+
79+
tester.mine()?;
80+
notify_wallet();
81+
assert_balance(0.3, 0.0);
82+
83+
// Verify that the transaction history checks out
84+
let history = electrum_wallet.call("onchain_history", &json!([]))?;
85+
log::debug!("history = {:#?}", history);
86+
assert_eq!(
87+
history["transactions"][0]["txid"].as_str(),
88+
Some(txid1.to_string().as_str())
89+
);
90+
assert_eq!(history["transactions"][0]["height"].as_u64(), Some(102));
91+
assert_eq!(history["transactions"][0]["bc_value"].as_str(), Some("0.1"));
92+
93+
assert_eq!(
94+
history["transactions"][1]["txid"].as_str(),
95+
Some(txid2.to_string().as_str())
96+
);
97+
assert_eq!(history["transactions"][1]["height"].as_u64(), Some(103));
98+
assert_eq!(history["transactions"][1]["bc_value"].as_str(), Some("0.2"));
99+
100+
// Send an outgoing payment
101+
electrum_wallet.call(
102+
"broadcast",
103+
&json!([ electrum_wallet.call(
104+
"payto",
105+
&json!({
106+
"destination": tester.bitcoind().get_new_address(None, None)?,
107+
"amount": 0.16,
108+
"fee": 0.001,
109+
}),
110+
)? ]),
111+
)?;
112+
notify_wallet();
113+
assert_balance(0.3, -0.161);
114+
115+
tester.mine()?;
116+
notify_wallet();
117+
assert_balance(0.139, 0.0);
118+
119+
Ok(())
120+
}

tests/rest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ mod common;
77
use common::Result;
88

99
#[test]
10-
fn test() -> Result<()> {
10+
fn test_rest() -> Result<()> {
1111
let (rest_handle, rest_addr, mut tester) = common::init_rest_tester().unwrap();
1212

1313
let get_json = |path: &str| -> Result<Value> {

0 commit comments

Comments
 (0)