Skip to content

Commit a010fd4

Browse files
committed
Retrying spawning the bitcoind process
It may rarely happen the port we asked with get_available_port is in the meantime used by another process, with this commit we retry to spawn the process with different ports
1 parent 8acc8e7 commit a010fd4

File tree

1 file changed

+23
-7
lines changed

1 file changed

+23
-7
lines changed

src/lib.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod versions;
1515

1616
use crate::bitcoincore_rpc::jsonrpc::serde_json::Value;
1717
use bitcoincore_rpc::{Auth, Client, RpcApi};
18-
use log::{debug, error};
18+
use log::{debug, error, warn};
1919
use std::ffi::OsStr;
2020
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener};
2121
use std::path::PathBuf;
@@ -55,7 +55,7 @@ pub struct ConnectParams {
5555
}
5656

5757
/// Enum to specify p2p settings
58-
#[derive(Debug, PartialEq, Eq)]
58+
#[derive(Debug, PartialEq, Eq, Clone)]
5959
pub enum P2P {
6060
/// the node doesn't open a p2p port and work in standalone mode
6161
No,
@@ -123,11 +123,12 @@ const LOCAL_IP: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
123123
/// conf.p2p = bitcoind::P2P::No;
124124
/// conf.network = "regtest";
125125
/// conf.tmpdir = None;
126+
/// conf.attempts = 3;
126127
/// assert_eq!(conf, bitcoind::Conf::default());
127128
/// ```
128129
///
129130
#[non_exhaustive]
130-
#[derive(Debug, PartialEq, Eq)]
131+
#[derive(Debug, PartialEq, Eq, Clone)]
131132
pub struct Conf<'a> {
132133
/// Bitcoind command line arguments containing no spaces like `vec!["-dbcache=300", "-regtest"]`
133134
/// note that `port`, `rpcport`, `connect`, `datadir`, `listen`
@@ -150,6 +151,13 @@ pub struct Conf<'a> {
150151
/// It may be useful for example to set to a ramdisk so that bitcoin nodes spawn very fast
151152
/// because their datadirs are in RAM
152153
pub tmpdir: Option<PathBuf>,
154+
155+
/// Try to spawn the process `attempt` time
156+
///
157+
/// The OS is giving available ports to use, however, they aren't booked, so it could rarely
158+
/// happen they are used at the time the process is spawn. When retrying other available ports
159+
/// are returned reducing the probability of conflicts to negligible.
160+
pub attempts: u8,
153161
}
154162

155163
impl Default for Conf<'_> {
@@ -160,6 +168,7 @@ impl Default for Conf<'_> {
160168
p2p: P2P::No,
161169
network: "regtest",
162170
tmpdir: None,
171+
attempts: 3,
163172
}
164173
}
165174
}
@@ -224,7 +233,7 @@ impl BitcoinD {
224233
default_args,
225234
p2p_args
226235
);
227-
let mut process = Command::new(exe)
236+
let mut process = Command::new(exe.as_ref())
228237
.args(&default_args)
229238
.args(&p2p_args)
230239
.args(&conf.args)
@@ -235,8 +244,15 @@ impl BitcoinD {
235244
// wait bitcoind is ready, use default wallet
236245
let client = loop {
237246
if let Some(status) = process.try_wait()? {
238-
error!("early exit with: {:?}", status);
239-
return Err(Error::EarlyExit(status));
247+
if conf.attempts > 0 {
248+
warn!("early exit with: {:?}. Trying to launch again ({} attempts remaining), maybe some other process used our available port", status, conf.attempts);
249+
let mut conf = conf.clone();
250+
conf.attempts -= 1;
251+
return Self::with_conf(exe, &conf);
252+
} else {
253+
error!("early exit with: {:?}", status);
254+
return Err(Error::EarlyExit(status));
255+
}
240256
}
241257
thread::sleep(Duration::from_millis(500));
242258
assert!(process.stderr.is_none());
@@ -380,7 +396,6 @@ mod test {
380396
#[test]
381397
fn test_bitcoind() {
382398
let exe = init();
383-
println!("{}", exe);
384399
let bitcoind = BitcoinD::new(exe).unwrap();
385400
let info = bitcoind.client.get_blockchain_info().unwrap();
386401
assert_eq!(0, info.blocks);
@@ -425,6 +440,7 @@ mod test {
425440

426441
#[test]
427442
fn test_multi_p2p() {
443+
let _ = env_logger::try_init();
428444
let mut conf_node1 = Conf::default();
429445
conf_node1.p2p = P2P::Yes;
430446
let node1 = BitcoinD::with_conf(exe_path().unwrap(), &conf_node1).unwrap();

0 commit comments

Comments
 (0)