Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow rpc_user and rpc_pass in config file #1527

Merged
merged 48 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
37d36ea
allow rpc_user and rpc_pass instead of cookie file
raphjaph Feb 6, 2023
5f0376f
merging
raphjaph Feb 10, 2023
439324b
stashing
raphjaph Feb 11, 2023
2ff901d
Merge branch 'master' of https://github.com/casey/ord into allow-rpc-…
raphjaph Feb 13, 2023
e0a918e
see diff
raphjaph Feb 13, 2023
453b957
quick fix
raphjaph Feb 13, 2023
0d00d5e
takes env vars as well
raphjaph Feb 13, 2023
3578d55
placate clippy
raphjaph Feb 13, 2023
6676846
read rpc_user and rpc_pass from config file as well
raphjaph Feb 13, 2023
95c3b06
fmt
raphjaph Feb 13, 2023
b17e52d
Merge branch 'master' into allow-rpc-pass
raphjaph Feb 13, 2023
f02aacb
Merge branch 'master' into allow-rpc-pass
raphjaph Feb 22, 2023
c3e326a
stash
raphjaph Feb 27, 2023
d37c440
Merge branch 'master' of https://github.com/casey/ord into allow-rpc-…
raphjaph Feb 27, 2023
b10603f
casey's derive function
raphjaph Mar 7, 2023
35e69cb
works now
raphjaph Mar 7, 2023
1ad42da
remove superfluous options from updater.rs
raphjaph Mar 7, 2023
745cc76
quick fix
raphjaph Mar 7, 2023
864b762
Merge branch 'master' of https://github.com/casey/ord into allow-rpc-…
raphjaph Mar 7, 2023
5458d31
fix tests
raphjaph Mar 13, 2023
85bb212
placate clippy
raphjaph Mar 14, 2023
b642bcf
Merge branch 'master' into allow-rpc-pass
raphjaph Apr 7, 2023
6bfa872
delete comment
raphjaph Apr 7, 2023
e961fbd
sort struct fields
raphjaph Apr 7, 2023
52d3456
stash
raphjaph Apr 7, 2023
645d202
stash
raphjaph Apr 11, 2023
34515dc
Merge branch 'master' into allow-rpc-pass
raphjaph Apr 11, 2023
c388e0c
fix nits
raphjaph Apr 11, 2023
2af9415
Merge branch 'master' of https://github.com/casey/ord into allow-rpc-…
raphjaph Apr 14, 2023
e0299cd
Merge branch 'master' of https://github.com/casey/ord into allow-rpc-…
raphjaph Apr 24, 2023
9949879
fix justfile
raphjaph Apr 24, 2023
cb7b496
derive_var arg fix
raphjaph Apr 24, 2023
f141c1d
better error msgs
raphjaph Apr 24, 2023
3b1dc37
Improve error messages and add logging
casey Apr 24, 2023
8e60b79
Use default::default
casey Apr 24, 2023
6ef45ee
tweak
casey Apr 24, 2023
aee8d94
Use more explicit variable names
casey Apr 24, 2023
db1a5b4
Make command line arguments more explicit
casey Apr 24, 2023
a354ff7
Use default default
casey Apr 24, 2023
796f171
Delete test
casey Apr 24, 2023
884c976
Use default::default
casey Apr 24, 2023
c6e2d39
improve test derive var
casey Apr 24, 2023
0891cf1
Merge branch 'master' of https://github.com/casey/ord into allow-rpc-…
raphjaph Apr 26, 2023
56109dd
improved some tests
raphjaph Apr 26, 2023
762b3ed
remove asssert
raphjaph May 1, 2023
ddb62b7
get rid of credentials tests
raphjaph May 1, 2023
c8d069e
done
raphjaph May 1, 2023
3d6328e
quick fix
raphjaph May 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use super::*;
#[derive(Deserialize, Default, PartialEq, Debug)]
pub(crate) struct Config {
pub(crate) hidden: HashSet<InscriptionId>,
pub(crate) rpc_pass: Option<String>,
pub(crate) rpc_user: Option<String>,
}

impl Config {
Expand All @@ -27,6 +29,7 @@ mod tests {

let config = Config {
hidden: iter::once(a).collect(),
..Default::default()
};

assert!(config.is_hidden(a));
Expand Down
20 changes: 4 additions & 16 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use {
super::*,
crate::wallet::Wallet,
bitcoin::BlockHeader,
bitcoincore_rpc::{json::GetBlockHeaderResult, Auth, Client},
bitcoincore_rpc::{json::GetBlockHeaderResult, Client},
chrono::SubsecRound,
indicatif::{ProgressBar, ProgressStyle},
log::log_enabled,
Expand Down Expand Up @@ -44,16 +44,15 @@ define_table! { STATISTIC_TO_COUNT, u64, u64 }
define_table! { WRITE_TRANSACTION_STARTING_BLOCK_COUNT_TO_TIMESTAMP, u64, u128 }

pub(crate) struct Index {
auth: Auth,
client: Client,
database: Database,
path: PathBuf,
first_inscription_height: u64,
genesis_block_coinbase_transaction: Transaction,
genesis_block_coinbase_txid: Txid,
height_limit: Option<u64>,
options: Options,
reorged: AtomicBool,
rpc_url: String,
}

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -133,17 +132,7 @@ impl<T> BitcoinCoreRpcResultExt<T> for Result<T, bitcoincore_rpc::Error> {

impl Index {
pub(crate) fn open(options: &Options) -> Result<Self> {
let rpc_url = options.rpc_url();
let cookie_file = options.cookie_file()?;

log::info!(
"Connecting to Bitcoin Core RPC server at {rpc_url} using credentials from `{}`",
cookie_file.display()
);

let auth = Auth::CookieFile(cookie_file);

let client = Client::new(&rpc_url, auth.clone()).context("failed to connect to RPC URL")?;
let client = options.bitcoin_rpc_client()?;

let data_dir = options.data_dir()?;

Expand Down Expand Up @@ -232,15 +221,14 @@ impl Index {

Ok(Self {
genesis_block_coinbase_txid: genesis_block_coinbase_transaction.txid(),
auth,
client,
database,
path,
first_inscription_height: options.first_inscription_height(),
genesis_block_coinbase_transaction,
height_limit: options.height_limit,
reorged: AtomicBool::new(false),
rpc_url,
options: options.clone(),
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
})
}

Expand Down
20 changes: 8 additions & 12 deletions src/index/fetcher.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use {
crate::Options,
anyhow::{anyhow, Result},
base64::Engine,
bitcoin::{Transaction, Txid},
bitcoincore_rpc::Auth,
hyper::{client::HttpConnector, Body, Client, Method, Request, Uri},
serde::Deserialize,
serde_json::{json, Value},
};

pub(crate) struct Fetcher {
auth: String,
client: Client<HttpConnector>,
url: Uri,
auth: String,
}

#[derive(Deserialize, Debug)]
struct JsonResponse<T> {
result: Option<T>,
error: Option<JsonError>,
id: usize,
result: Option<T>,
}

#[derive(Deserialize, Debug)]
Expand All @@ -28,22 +28,18 @@ struct JsonError {
}

impl Fetcher {
pub(crate) fn new(url: &str, auth: Auth) -> Result<Self> {
if auth == Auth::None {
return Err(anyhow!("No rpc authentication provided"));
}

pub(crate) fn new(options: &Options) -> Result<Self> {
let client = Client::new();

let url = if url.starts_with("http://") {
url.to_string()
let url = if options.rpc_url().starts_with("http://") {
options.rpc_url()
} else {
"http://".to_string() + url
"http://".to_string() + &options.rpc_url()
};

let url = Uri::try_from(&url).map_err(|e| anyhow!("Invalid rpc url {url}: {e}"))?;

let (user, password) = auth.get_user_pass()?;
let (user, password) = options.auth()?.get_user_pass()?;
let auth = format!("{}:{}", user.unwrap(), password.unwrap());
let auth = format!(
"Basic {}",
Expand Down
5 changes: 2 additions & 3 deletions src/index/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ impl Updater {

let height_limit = index.height_limit;

let client =
Client::new(&index.rpc_url, index.auth.clone()).context("failed to connect to RPC URL")?;
let client = index.options.bitcoin_rpc_client()?;

let first_inscription_height = index.first_inscription_height;

Expand Down Expand Up @@ -262,7 +261,7 @@ impl Updater {
}

fn spawn_fetcher(index: &Index) -> Result<(Sender<OutPoint>, Receiver<u64>)> {
let fetcher = Fetcher::new(&index.rpc_url, index.auth.clone())?;
let fetcher = Fetcher::new(&index.options)?;

// Not sure if any block has more than 20k inputs, but none so far after first inscription block
const CHANNEL_BUFFER_SIZE: usize = 20_000;
Expand Down
135 changes: 118 additions & 17 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ use {super::*, bitcoincore_rpc::Auth};
pub(crate) struct Options {
#[clap(long, help = "Load Bitcoin Core data dir from <BITCOIN_DATA_DIR>.")]
pub(crate) bitcoin_data_dir: Option<PathBuf>,
#[clap(long, help = "Authenticate to Bitcoin Core RPC with <RPC_PASS>.")]
pub(crate) bitcoin_rpc_pass: Option<String>,
#[clap(long, help = "Authenticate to Bitcoin Core RPC as <RPC_USER>.")]
pub(crate) bitcoin_rpc_user: Option<String>,
#[clap(
long = "chain",
arg_enum,
Expand Down Expand Up @@ -91,11 +95,11 @@ impl Options {
bitcoin_data_dir.clone()
} else if cfg!(target_os = "linux") {
dirs::home_dir()
.ok_or_else(|| anyhow!("failed to retrieve home dir"))?
.ok_or_else(|| anyhow!("failed to get cookie file path: could not get home dir"))?
.join(".bitcoin")
} else {
dirs::data_dir()
.ok_or_else(|| anyhow!("failed to retrieve data dir"))?
.ok_or_else(|| anyhow!("failed to get cookie file path: could not get data dir"))?
.join("Bitcoin")
};

Expand Down Expand Up @@ -136,25 +140,69 @@ impl Options {
)
}

pub(crate) fn bitcoin_rpc_client(&self) -> Result<Client> {
let cookie_file = self
.cookie_file()
.map_err(|err| anyhow!("failed to get cookie file path: {err}"))?;
fn derive_var(
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
arg_value: Option<&str>,
env_key: Option<&str>,
config_value: Option<&str>,
default_value: Option<&str>,
) -> Result<Option<String>> {
let env_value = match env_key {
Some(env_key) => match env::var(format!("ORD_{env_key}")) {
Ok(env_value) => Some(env_value),
Err(err @ env::VarError::NotUnicode(_)) => return Err(err.into()),
Err(env::VarError::NotPresent) => None,
},
None => None,
};

Ok(
arg_value
.or(env_value.as_deref())
.or(config_value)
.or(default_value)
.map(str::to_string),
)
}

pub(crate) fn auth(&self) -> Result<Auth> {
let config = self.load_config()?;

let rpc_user = Options::derive_var(
self.bitcoin_rpc_user.as_deref(),
Some("BITCOIN_RPC_USER"),
config.rpc_user.as_deref(),
None,
)?;

let rpc_pass = Options::derive_var(
self.bitcoin_rpc_pass.as_deref(),
Some("BITCOIN_RPC_PASS"),
config.rpc_pass.as_deref(),
None,
)?;

match (rpc_user, rpc_pass) {
(Some(rpc_user), Some(rpc_pass)) => Ok(Auth::UserPass(rpc_user, rpc_pass)),
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
_ => Ok(Auth::CookieFile(self.cookie_file()?)),
}
}

pub(crate) fn bitcoin_rpc_client(&self) -> Result<Client> {
let rpc_url = self.rpc_url();

log::info!(
"Connecting to Bitcoin Core RPC server at {rpc_url} using credentials from `{}`",
cookie_file.display()
);
let auth = self.auth()?;

let client =
Client::new(&rpc_url, Auth::CookieFile(cookie_file.clone())).with_context(|| {
format!(
"failed to connect to Bitcoin Core RPC at {rpc_url} using cookie file {}",
cookie_file.display()
)
})?;
log::info!("Connecting to Bitcoin Core at {}", self.rpc_url());

if let Auth::CookieFile(cookie_file) = &auth {
log::info!(
"Using credentials from cookie file at `{}`",
cookie_file.display()
);
}

let client = Client::new(&rpc_url, auth)
.with_context(|| format!("failed to connect to Bitcoin Core RPC at {rpc_url}"))?;

let rpc_chain = match client.get_blockchain_info()?.chain.as_str() {
"main" => Chain::Mainnet,
Expand Down Expand Up @@ -561,6 +609,27 @@ mod tests {
.unwrap(),
Config {
hidden: iter::once(id).collect(),
..Default::default()
}
);
}

#[test]
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
fn config_with_rpc_user_pass() {
let tempdir = TempDir::new().unwrap();
let path = tempdir.path().join("ord.yaml");
fs::write(&path, "hidden:\nrpc_user: foo\nrpc_pass: bar").unwrap();

assert_eq!(
Arguments::try_parse_from(["ord", "--config", path.to_str().unwrap(), "index",])
.unwrap()
.options
.load_config()
.unwrap(),
Config {
rpc_user: Some("foo".into()),
rpc_pass: Some("bar".into()),
..Default::default()
}
);
}
Expand Down Expand Up @@ -592,7 +661,39 @@ mod tests {
.unwrap(),
Config {
hidden: iter::once(id).collect(),
..Default::default()
}
);
}

#[test]
fn test_derive_var() {
assert_eq!(Options::derive_var(None, None, None, None).unwrap(), None);

assert_eq!(
Options::derive_var(None, None, None, Some("foo".into())).unwrap(),
Some("foo".into())
);

assert_eq!(
Options::derive_var(None, None, Some("bar".into()), Some("foo".into())).unwrap(),
Some("bar".into())
);

assert_eq!(
Options::derive_var(
Some("qux".into()),
None,
Some("bar".into()),
Some("foo".into())
)
.unwrap(),
Some("qux".into())
);

assert_eq!(
Options::derive_var(Some("qux".into()), None, None, Some("foo".into())).unwrap(),
Some("qux".into()),
);
}
}
Loading