Skip to content

Commit fd65d9b

Browse files
committed
Enable tests in Liquid mode
Using the `elementsd` crate to spawn a regtest elements envirnoment.
1 parent 728b3a0 commit fd65d9b

File tree

5 files changed

+139
-41
lines changed

5 files changed

+139
-41
lines changed

Cargo.lock

Lines changed: 30 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: 7 additions & 1 deletion
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+
elementsd = { version = "0.3.0", features = [ "0_21_0" ] }
6566
electrumd = { version = "0.1.0", features = [ "4_1_5" ] }
6667
ureq = { version = "2.4", default-features = false, features = [ "json" ] }
6768
tempfile = "3.0"
@@ -83,4 +84,9 @@ rev = "d988bd7ed9cf539b8fea0da042efa5a4e1eef86f"
8384
# not yet published on crates.io
8485
[patch.crates-io.electrumd]
8586
git = "https://github.com/shesek/electrumd"
86-
rev = "ea32146dc1db378d4444cd713a27a8ea3919c4c0"
87+
rev = "ea32146dc1db378d4444cd713a27a8ea3919c4c0"
88+
89+
# pending https://github.com/RCasatta/elementsd/pull/1
90+
[patch.crates-io.elementsd]
91+
git = "https://github.com/shesek/elementsd"
92+
rev = "86d9c3d480f72963c81671705ac84af89d4d1b4b"

tests/common.rs

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ use std::sync::{Arc, Once, RwLock};
22
use std::{env, net};
33

44
use stderrlog::StdErrLog;
5+
use tempfile::TempDir;
56

6-
use bitcoind::{
7-
bitcoincore_rpc::{self, RpcApi},
8-
BitcoinD,
9-
};
7+
use serde_json::{json, Value};
8+
9+
#[cfg(not(feature = "liquid"))]
10+
use bitcoind::{self as noded, BitcoinD as NodeD};
11+
#[cfg(feature = "liquid")]
12+
use elementsd::{self as noded, ElementsD as NodeD};
13+
14+
use noded::bitcoincore_rpc::{self, RpcApi};
1015

1116
use electrs::{
12-
chain::{self, Network},
17+
chain::{self, Address, BlockHash, Network, Txid},
1318
config::{self, Config},
1419
daemon::Daemon,
1520
electrum::RPC as ElectrumRPC,
@@ -18,28 +23,49 @@ use electrs::{
1823
rest,
1924
signal::Waiter,
2025
};
21-
use tempfile::TempDir;
2226

2327
pub fn init_tester() -> Result<TestRunner> {
2428
let log = init_log();
2529

26-
let mut bitcoind_conf = bitcoind::Conf::default();
27-
bitcoind_conf.view_stdout = true;
30+
// Setup the bitcoind/elementsd config
31+
let mut node_conf = noded::Conf::default();
32+
{
33+
#[cfg(not(feature = "liquid"))]
34+
let node_conf = &mut node_conf;
35+
#[cfg(feature = "liquid")]
36+
let node_conf = &mut node_conf.0;
37+
38+
#[cfg(feature = "liquid")]
39+
{
40+
node_conf.args.push("-anyonecanspendaremine=1");
41+
}
42+
43+
node_conf.view_stdout = true;
44+
}
45+
46+
// Setup node
47+
let node = NodeD::with_conf(noded::downloaded_exe_path().unwrap(), &node_conf).unwrap();
48+
49+
#[cfg(not(feature = "liquid"))]
50+
let (node_client, params) = (&node.client, &node.params);
51+
#[cfg(feature = "liquid")]
52+
let (node_client, params) = (node.client(), &node.params());
2853

29-
let bitcoind =
30-
BitcoinD::with_conf(bitcoind::downloaded_exe_path().unwrap(), &bitcoind_conf).unwrap();
54+
log::info!("node params: {:?}", params);
3155

32-
init_node(&bitcoind.client).chain_err(|| "failed initializing node")?;
56+
generate(node_client, 101).chain_err(|| "failed initializing blocks")?;
3357

34-
log::info!("bitcoind: {:?}", bitcoind.params);
58+
// Needed to claim the initialfreecoins are our own
59+
// See https://github.com/ElementsProject/elements/issues/956
60+
#[cfg(feature = "liquid")]
61+
node_client.call::<Value>("rescanblockchain", &[])?;
3562

3663
#[cfg(not(feature = "liquid"))]
3764
let network_type = Network::Regtest;
3865
#[cfg(feature = "liquid")]
3966
let network_type = Network::LiquidRegtest;
4067

41-
let daemon_subdir = bitcoind
42-
.params
68+
let daemon_subdir = params
4369
.datadir
4470
.join(config::get_network_subdir(network_type).unwrap());
4571

@@ -51,7 +77,7 @@ pub fn init_tester() -> Result<TestRunner> {
5177
db_path: electrsdb.path().to_path_buf(),
5278
daemon_dir: daemon_subdir.clone(),
5379
blocks_dir: daemon_subdir.join("blocks"),
54-
daemon_rpc_addr: bitcoind.params.rpc_socket.into(),
80+
daemon_rpc_addr: params.rpc_socket.into(),
5581
cookie: None,
5682
electrum_rpc_addr: rand_available_addr(),
5783
http_addr: rand_available_addr(),
@@ -134,7 +160,7 @@ pub fn init_tester() -> Result<TestRunner> {
134160

135161
Ok(TestRunner {
136162
config,
137-
bitcoind,
163+
node,
138164
_electrsdb: electrsdb,
139165
indexer,
140166
query,
@@ -146,7 +172,8 @@ pub fn init_tester() -> Result<TestRunner> {
146172

147173
pub struct TestRunner {
148174
config: Arc<Config>,
149-
bitcoind: BitcoinD,
175+
/// bitcoind::BitcoinD or an elementsd::ElementsD in liquid mode
176+
node: NodeD,
150177
_electrsdb: TempDir, // rm'd when dropped
151178
indexer: Indexer,
152179
query: Arc<Query>,
@@ -156,8 +183,11 @@ pub struct TestRunner {
156183
}
157184

158185
impl TestRunner {
159-
pub fn bitcoind(&self) -> &bitcoincore_rpc::Client {
160-
&self.bitcoind.client
186+
pub fn node_client(&self) -> &bitcoincore_rpc::Client {
187+
#[cfg(not(feature = "liquid"))]
188+
return &self.node.client;
189+
#[cfg(feature = "liquid")]
190+
return &self.node.client();
161191
}
162192

163193
pub fn sync(&mut self) -> Result<()> {
@@ -169,18 +199,17 @@ impl TestRunner {
169199
Ok(())
170200
}
171201

172-
pub fn mine(&mut self) -> Result<chain::BlockHash> {
173-
let addr = self.bitcoind.client.get_new_address(None, None)?;
174-
let mut generated = self.bitcoind.client.generate_to_address(1, &addr)?;
202+
pub fn mine(&mut self) -> Result<BlockHash> {
203+
let mut generated = generate(self.node_client(), 1)?;
175204
self.sync()?;
176205
Ok(generated.remove(0))
177206
}
178207

179-
pub fn send(&mut self, addr: &chain::Address, amount: bitcoin::Amount) -> Result<chain::Txid> {
180-
let txid = self
181-
.bitcoind
182-
.client
183-
.send_to_address(addr, amount, None, None, None, None, None, None)?;
208+
pub fn send(&mut self, addr: &Address, amount: bitcoin::Amount) -> Result<Txid> {
209+
let txid = self.node_client().call(
210+
"sendtoaddress",
211+
&[addr.to_string().into(), json!(amount.as_btc())],
212+
)?;
184213
self.sync()?;
185214
Ok(txid)
186215
}
@@ -206,10 +235,15 @@ pub fn init_electrum_tester() -> Result<(ElectrumRPC, net::SocketAddr, TestRunne
206235
Ok((electrum_server, tester.config.electrum_rpc_addr, tester))
207236
}
208237

209-
fn init_node(client: &bitcoincore_rpc::Client) -> bitcoincore_rpc::Result<()> {
210-
let addr = client.get_new_address(None, None)?;
211-
client.generate_to_address(101, &addr)?;
212-
Ok(())
238+
fn generate(
239+
client: &bitcoincore_rpc::Client,
240+
num_blocks: u32,
241+
) -> bitcoincore_rpc::Result<Vec<BlockHash>> {
242+
let addr = client.call::<Address>("getnewaddress", &[])?;
243+
client.call(
244+
"generatetoaddress",
245+
&[num_blocks.into(), addr.to_string().into()],
246+
)
213247
}
214248

215249
fn init_log() -> StdErrLog {
@@ -256,6 +290,10 @@ error_chain::error_chain! {
256290
description("ureq error")
257291
display("ureq error: {:?}", e)
258292
}
293+
Json(e: serde_json::Error) {
294+
description("JSON error")
295+
display("JSON error: {:?}", e)
296+
}
259297
}
260298
}
261299

@@ -284,3 +322,8 @@ impl From<ureq::Error> for Error {
284322
Error::from(ErrorKind::Ureq(e))
285323
}
286324
}
325+
impl From<serde_json::Error> for Error {
326+
fn from(e: serde_json::Error) -> Self {
327+
Error::from(ErrorKind::Json(e))
328+
}
329+
}

tests/electrum.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@ fn test_electrum() -> Result<()> {
100100
// Send an outgoing payment
101101
electrum_wallet.call(
102102
"broadcast",
103-
&json!([ electrum_wallet.call(
103+
&json!([electrum_wallet.call(
104104
"payto",
105105
&json!({
106-
"destination": tester.bitcoind().get_new_address(None, None)?,
106+
"destination": tester.node_client().get_new_address(None, None)?,
107107
"amount": 0.16,
108108
"fee": 0.001,
109109
}),
110-
)? ]),
110+
)?]),
111111
)?;
112112
notify_wallet();
113113
assert_balance(0.3, -0.161);

tests/rest.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use bitcoind::bitcoincore_rpc::RpcApi;
22
use serde_json::Value;
33
use std::collections::HashSet;
44

5+
use electrs::chain::{Address, Txid};
6+
57
mod common;
68

79
use common::Result;
@@ -22,8 +24,23 @@ fn test_rest() -> Result<()> {
2224
.into_string()?)
2325
};
2426

27+
let newaddress = || -> Result<Address> {
28+
let addr = tester.node_client().call::<Address>("getnewaddress", &[])?;
29+
// On Liquid, return the unconfidential address, so that the tests below work
30+
// on both Bitcoin and Liquid mode. The Liquid-specific functionality, including
31+
// confidentially, is tested separately below.
32+
#[cfg(feature = "liquid")]
33+
let addr = {
34+
let mut info = tester
35+
.node_client()
36+
.call::<Value>("getaddressinfo", &[addr.to_string().into()])?;
37+
serde_json::from_value(info["unconfidential"].take())?
38+
};
39+
Ok(addr)
40+
};
41+
2542
// Send transaction and confirm it
26-
let addr1 = tester.bitcoind().get_new_address(None, None)?;
43+
let addr1 = newaddress()?;
2744
let txid1_confirmed = tester.send(&addr1, "1.19123 BTC".parse().unwrap())?;
2845
tester.mine()?;
2946

@@ -32,6 +49,7 @@ fn test_rest() -> Result<()> {
3249

3350
// Test GET /tx/:txid
3451
let res = get_json(&format!("/tx/{}", txid1_confirmed))?;
52+
log::debug!("tx: {:#?}", res);
3553
let outs = res["vout"].as_array().expect("array of outs");
3654
assert!(outs.iter().any(|vout| {
3755
vout["scriptpubkey_address"].as_str() == Some(&addr1.to_string())
@@ -50,11 +68,13 @@ fn test_rest() -> Result<()> {
5068
// Test GET /address/:address
5169
let res = get_json(&format!("/address/{}", addr1))?;
5270
assert_eq!(res["chain_stats"]["funded_txo_count"].as_u64(), Some(1));
71+
#[cfg(not(feature = "liquid"))]
5372
assert_eq!(
5473
res["chain_stats"]["funded_txo_sum"].as_u64(),
5574
Some(119123000)
5675
);
5776
assert_eq!(res["mempool_stats"]["funded_txo_count"].as_u64(), Some(1));
77+
#[cfg(not(feature = "liquid"))]
5878
assert_eq!(
5979
res["mempool_stats"]["funded_txo_sum"].as_u64(),
6080
Some(71130000)
@@ -66,7 +86,7 @@ fn test_rest() -> Result<()> {
6686
let mut txids = txs
6787
.iter()
6888
.map(|tx| tx["txid"].as_str().unwrap().parse().unwrap())
69-
.collect::<HashSet<electrs::chain::Txid>>();
89+
.collect::<HashSet<Txid>>();
7090
assert!(txids.remove(&txid1_confirmed));
7191
assert!(txids.remove(&txid2_mempool));
7292
assert!(txids.is_empty());
@@ -79,7 +99,7 @@ fn test_rest() -> Result<()> {
7999
assert_eq!(found[0].as_str(), Some(addr1.to_string().as_str()));
80100

81101
// Test GET /blocks/tip/hash
82-
let bestblockhash = tester.bitcoind().get_best_block_hash()?;
102+
let bestblockhash = tester.node_client().get_best_block_hash()?;
83103
let res = get_plain("/blocks/tip/hash")?;
84104
assert_eq!(res, bestblockhash.to_string());
85105

@@ -88,7 +108,7 @@ fn test_rest() -> Result<()> {
88108
assert_eq!(res, bestblockhash.to_string());
89109

90110
// Test GET /blocks/tip/height
91-
let bestblockheight = tester.bitcoind().get_block_count()?;
111+
let bestblockheight = tester.node_client().get_block_count()?;
92112
let res = get_plain("/blocks/tip/height")?;
93113
assert_eq!(
94114
res.parse::<u64>().expect("tip block height as an int"),
@@ -124,7 +144,7 @@ fn test_rest() -> Result<()> {
124144
assert_eq!(res["id"].as_str(), Some(blockhash.to_string().as_str()));
125145
assert_eq!(
126146
res["height"].as_u64(),
127-
Some(tester.bitcoind().get_block_count()?)
147+
Some(tester.node_client().get_block_count()?)
128148
);
129149
assert_eq!(res["tx_count"].as_u64(), Some(2));
130150

0 commit comments

Comments
 (0)