1
0
mirror of https://github.com/romanz/electrs.git synced 2024-11-19 09:54:09 +01:00

Allow configuration of JSON-RPC timeout

Following https://github.com/romanz/electrs/issues/495.

Also, fix https://github.com/romanz/electrs/issues/443.
This commit is contained in:
Roman Zeyde 2021-09-22 11:42:17 +03:00
parent 492d6aa275
commit 8285cf3fc7
3 changed files with 56 additions and 9 deletions

View File

@ -80,6 +80,12 @@ type = "u64"
doc = "Duration to wait between bitcoind polling" doc = "Duration to wait between bitcoind polling"
default = "10" default = "10"
[[param]]
name = "jsonrpc_timeout_secs"
type = "u64"
doc = "Duration to wait until bitcoind JSON-RPC timeouts (must be greater than wait_duration_secs)."
default = "15"
[[param]] [[param]]
name = "index_batch_size" name = "index_batch_size"
type = "usize" type = "usize"

View File

@ -130,6 +130,7 @@ pub struct Config {
pub electrum_rpc_addr: SocketAddr, pub electrum_rpc_addr: SocketAddr,
pub monitoring_addr: SocketAddr, pub monitoring_addr: SocketAddr,
pub wait_duration: Duration, pub wait_duration: Duration,
pub jsonrpc_timeout: Duration,
pub index_batch_size: usize, pub index_batch_size: usize,
pub index_lookup_limit: Option<usize>, pub index_lookup_limit: Option<usize>,
pub auto_reindex: bool, pub auto_reindex: bool,
@ -283,6 +284,15 @@ impl Config {
0 => None, 0 => None,
_ => Some(config.index_lookup_limit), _ => Some(config.index_lookup_limit),
}; };
if config.jsonrpc_timeout_secs <= config.wait_duration_secs {
eprintln!(
"Error: jsonrpc_timeout_secs ({}) must be higher than wait_duration_secs ({})",
config.jsonrpc_timeout_secs, config.wait_duration_secs
);
std::process::exit(1);
}
let config = Config { let config = Config {
network: config.network, network: config.network,
db_path: config.db_dir, db_path: config.db_dir,
@ -293,6 +303,7 @@ impl Config {
electrum_rpc_addr, electrum_rpc_addr,
monitoring_addr, monitoring_addr,
wait_duration: Duration::from_secs(config.wait_duration_secs), wait_duration: Duration::from_secs(config.wait_duration_secs),
jsonrpc_timeout: Duration::from_secs(config.jsonrpc_timeout_secs),
index_batch_size: config.index_batch_size, index_batch_size: config.index_batch_size,
index_lookup_limit, index_lookup_limit,
auto_reindex: config.auto_reindex, auto_reindex: config.auto_reindex,

View File

@ -3,10 +3,14 @@ use anyhow::{Context, Result};
use bitcoin::{ use bitcoin::{
consensus::serialize, hashes::hex::ToHex, Amount, Block, BlockHash, Transaction, Txid, consensus::serialize, hashes::hex::ToHex, Amount, Block, BlockHash, Transaction, Txid,
}; };
use core_rpc::{json, Auth, Client, RpcApi}; use core_rpc::{json, jsonrpc, Auth, Client, RpcApi};
use parking_lot::Mutex; use parking_lot::Mutex;
use serde_json::{json, Value}; use serde_json::{json, Value};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use crate::{ use crate::{
chain::{Chain, NewHeader}, chain::{Chain, NewHeader},
config::Config, config::Config,
@ -48,16 +52,42 @@ fn rpc_poll(client: &mut Client) -> PollResult {
} }
} }
fn read_cookie(path: &Path) -> Result<(String, String)> {
// Load username and password from bitcoind cookie file:
// * https://github.com/bitcoin/bitcoin/pull/6388/commits/71cbeaad9a929ba6a7b62d9b37a09b214ae00c1a
// * https://bitcoin.stackexchange.com/questions/46782/rpc-cookie-authentication
let mut file = File::open(path)
.with_context(|| format!("failed to open bitcoind cookie file: {}", path.display()))?;
let mut contents = String::new();
file.read_to_string(&mut contents)
.with_context(|| format!("failed to read bitcoind cookie from {}", path.display()))?;
let parts: Vec<&str> = contents.splitn(2, ':').collect();
ensure!(
parts.len() == 2,
"failed to parse bitcoind cookie - missing ':' separator"
);
Ok((parts[0].to_owned(), parts[1].to_owned()))
}
pub(crate) fn rpc_connect(config: &Config) -> Result<Client> { pub(crate) fn rpc_connect(config: &Config) -> Result<Client> {
let rpc_url = format!("http://{}", config.daemon_rpc_addr); let rpc_url = format!("http://{}", config.daemon_rpc_addr);
let auth = config.daemon_auth.get_auth(); let mut client = {
if let Auth::CookieFile(ref path) = auth { // Allow `wait_for_new_block` to take a bit longer before timing out.
if !path.exists() { // See https://github.com/romanz/electrs/issues/495 for more details.
bail!("{:?} is missing - is bitcoind running?", path); let builder = jsonrpc::simple_http::SimpleHttpTransport::builder()
.url(&rpc_url)?
.timeout(config.jsonrpc_timeout);
let builder = match config.daemon_auth.get_auth() {
Auth::None => builder,
Auth::UserPass(user, pass) => builder.auth(user, Some(pass)),
Auth::CookieFile(path) => {
let (user, pass) = read_cookie(&path)?;
builder.auth(user, Some(pass))
} }
} };
let mut client = Client::new(&rpc_url, auth) Client::from_jsonrpc(jsonrpc::Client::with_transport(builder.build()))
.with_context(|| format!("failed to connect to RPC: {}", config.daemon_rpc_addr))?; };
loop { loop {
match rpc_poll(&mut client) { match rpc_poll(&mut client) {