Skip to content

Commit 4607b77

Browse files
authored
Merge pull request #216 from EddieHouston/feat/dual-daemon-rpc
Add --daemon-rpc-fallback-addr for backup bitcoind RPC
2 parents 503b740 + 8f1b604 commit 4607b77

5 files changed

Lines changed: 57 additions & 7 deletions

File tree

src/bin/electrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ fn run_server(config: Arc<Config>, salt_rwlock: Arc<RwLock<String>>) -> Result<(
6868
&config.daemon_dir,
6969
&config.blocks_dir,
7070
config.daemon_rpc_addr,
71+
config.daemon_rpc_fallback_addr,
7172
config.daemon_parallelism,
7273
config.cookie_getter(),
7374
config.network_type,

src/bin/tx-fingerprint-stats.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ fn main() {
3434
&config.daemon_dir,
3535
&config.blocks_dir,
3636
config.daemon_rpc_addr,
37+
config.daemon_rpc_fallback_addr,
3738
config.daemon_parallelism,
3839
config.cookie_getter(),
3940
config.network_type,

src/config.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct Config {
2525
pub daemon_dir: PathBuf,
2626
pub blocks_dir: PathBuf,
2727
pub daemon_rpc_addr: SocketAddr,
28+
pub daemon_rpc_fallback_addr: Option<SocketAddr>,
2829
pub daemon_parallelism: usize,
2930
pub cookie: Option<String>,
3031
pub electrum_rpc_addr: SocketAddr,
@@ -164,6 +165,12 @@ impl Config {
164165
.help("Bitcoin daemon JSONRPC 'addr:port' to connect (default: 127.0.0.1:8332 for mainnet, 127.0.0.1:18332 for testnet3 and 127.0.0.1:48332 for testnet4 and 127.0.0.1:18443 for regtest)")
165166
.takes_value(true),
166167
)
168+
.arg(
169+
Arg::with_name("daemon_rpc_fallback_addr")
170+
.long("daemon-rpc-fallback-addr")
171+
.help("Fallback Bitcoin daemon JSONRPC 'addr:port' to connect if the primary fails")
172+
.takes_value(true),
173+
)
167174
.arg(
168175
Arg::with_name("daemon_parallelism")
169176
.long("daemon-parallelism")
@@ -414,6 +421,10 @@ impl Config {
414421
.unwrap_or(&format!("127.0.0.1:{}", default_daemon_port)),
415422
"Bitcoin RPC",
416423
);
424+
let daemon_rpc_fallback_addr: Option<SocketAddr> = m
425+
.value_of("daemon_rpc_fallback_addr")
426+
.map(|e| str_to_socketaddr(e, "Bitcoin Fallback RPC"));
427+
417428
let electrum_rpc_addr: SocketAddr = str_to_socketaddr(
418429
m.value_of("electrum_rpc_addr")
419430
.unwrap_or(&format!("127.0.0.1:{}", default_electrum_port)),
@@ -481,6 +492,7 @@ impl Config {
481492
daemon_dir,
482493
blocks_dir,
483494
daemon_rpc_addr,
495+
daemon_rpc_fallback_addr,
484496
daemon_parallelism: value_t_or_exit!(m, "daemon_parallelism", usize),
485497
cookie,
486498
utxos_limit: value_t_or_exit!(m, "utxos_limit", usize),

src/daemon.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,24 +186,48 @@ struct Connection {
186186
rx: Lines<BufReader<TcpStream>>,
187187
cookie_getter: Arc<dyn CookieGetter>,
188188
addr: SocketAddr,
189+
fallback: Option<SocketAddr>,
189190
signal: Waiter,
190191
}
191192

192193
#[trace]
193-
fn tcp_connect(addr: SocketAddr, signal: &Waiter) -> Result<TcpStream> {
194+
fn tcp_connect(
195+
primary: SocketAddr,
196+
fallback: Option<SocketAddr>,
197+
signal: &Waiter,
198+
) -> Result<(TcpStream, SocketAddr)> {
194199
loop {
195-
match TcpStream::connect_timeout(&addr, *DAEMON_CONNECTION_TIMEOUT) {
200+
match TcpStream::connect_timeout(&primary, *DAEMON_CONNECTION_TIMEOUT) {
196201
Ok(conn) => {
197202
// can only fail if DAEMON_TIMEOUT is 0
198203
conn.set_read_timeout(Some(*DAEMON_READ_TIMEOUT)).unwrap();
199204
conn.set_write_timeout(Some(*DAEMON_WRITE_TIMEOUT)).unwrap();
200-
return Ok(conn);
205+
return Ok((conn, primary));
201206
}
202207
Err(err) => {
208+
let suffix = if fallback.is_some() {
209+
" (trying fallback...)"
210+
} else {
211+
""
212+
};
203213
warn!(
204-
"failed to connect daemon at {}: {} (backoff 3 seconds)",
205-
addr, err
214+
"failed to connect to primary daemon at {}: {}{}",
215+
primary, err, suffix
206216
);
217+
if let Some(fallback_addr) = fallback {
218+
match TcpStream::connect_timeout(&fallback_addr, *DAEMON_CONNECTION_TIMEOUT) {
219+
Ok(conn) => {
220+
info!("connected to fallback daemon at {}", fallback_addr);
221+
conn.set_read_timeout(Some(*DAEMON_READ_TIMEOUT)).unwrap();
222+
conn.set_write_timeout(Some(*DAEMON_WRITE_TIMEOUT)).unwrap();
223+
return Ok((conn, fallback_addr));
224+
}
225+
Err(err) => {
226+
warn!("failed to connect to fallback daemon at {}: {}", fallback_addr, err);
227+
}
228+
}
229+
}
230+
warn!("backoff 3 seconds before next attempt");
207231
signal.wait(Duration::from_secs(3), false)?;
208232
continue;
209233
}
@@ -215,10 +239,12 @@ impl Connection {
215239
#[trace]
216240
fn new(
217241
addr: SocketAddr,
242+
fallback: Option<SocketAddr>,
218243
cookie_getter: Arc<dyn CookieGetter>,
219244
signal: Waiter,
220245
) -> Result<Connection> {
221-
let conn = tcp_connect(addr, &signal)?;
246+
let (conn, active_addr) = tcp_connect(addr, fallback, &signal)?;
247+
debug!("connected to bitcoind at {}", active_addr);
222248
let reader = BufReader::new(
223249
conn.try_clone()
224250
.chain_err(|| format!("failed to clone {:?}", conn))?,
@@ -228,13 +254,19 @@ impl Connection {
228254
rx: reader.lines(),
229255
cookie_getter,
230256
addr,
257+
fallback,
231258
signal,
232259
})
233260
}
234261

235262
#[trace]
236263
fn reconnect(&self) -> Result<Connection> {
237-
Connection::new(self.addr, self.cookie_getter.clone(), self.signal.clone())
264+
Connection::new(
265+
self.addr,
266+
self.fallback,
267+
self.cookie_getter.clone(),
268+
self.signal.clone(),
269+
)
238270
}
239271

240272
#[trace]
@@ -353,6 +385,7 @@ impl Daemon {
353385
daemon_dir: &PathBuf,
354386
blocks_dir: &PathBuf,
355387
daemon_rpc_addr: SocketAddr,
388+
daemon_rpc_fallback_addr: Option<SocketAddr>,
356389
daemon_parallelism: usize,
357390
cookie_getter: Arc<dyn CookieGetter>,
358391
network: Network,
@@ -365,6 +398,7 @@ impl Daemon {
365398
network,
366399
conn: Mutex::new(Connection::new(
367400
daemon_rpc_addr,
401+
daemon_rpc_fallback_addr,
368402
cookie_getter,
369403
signal.clone(),
370404
)?),

tests/common.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ impl TestRunner {
9696
daemon_parallelism: 3,
9797
blocks_dir: daemon_subdir.join("blocks"),
9898
daemon_rpc_addr: params.rpc_socket.into(),
99+
daemon_rpc_fallback_addr: None,
99100
cookie: None,
100101
electrum_rpc_addr: rand_available_addr(),
101102
http_addr: rand_available_addr(),
@@ -138,6 +139,7 @@ impl TestRunner {
138139
&config.daemon_dir,
139140
&config.blocks_dir,
140141
config.daemon_rpc_addr,
142+
config.daemon_rpc_fallback_addr,
141143
config.daemon_parallelism,
142144
config.cookie_getter(),
143145
config.network_type,

0 commit comments

Comments
 (0)