From d0cd3b0f389c10610ad58a999d42b4b7ca39ba6c Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Tue, 29 Nov 2022 18:16:27 -0800 Subject: [PATCH] Add Auth, RpcSyncParams, and RpcConfig --- Cargo.lock | 46 +++++++++++++++++++++++++ bdk-ffi/Cargo.toml | 2 +- bdk-ffi/src/bdk.udl | 24 +++++++++++++ bdk-ffi/src/lib.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 154 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a24fb7e..4a8d953 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,6 +107,15 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64-compat" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a8d4d2746f89841e49230dd26917df1876050f95abafafbe34f47cb534b88d7" +dependencies = [ + "byteorder", +] + [[package]] name = "bdk" version = "0.25.0" @@ -118,6 +127,7 @@ dependencies = [ "bdk-macros", "bip39", "bitcoin", + "bitcoincore-rpc", "electrum-client", "esplora-client", "getrandom", @@ -218,6 +228,30 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoincore-rpc" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0261b2bb7617e0c91b452a837bbd1291fd34ad6990cb8e3ffc28239cc045b5ca" +dependencies = [ + "bitcoincore-rpc-json", + "jsonrpc", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "bitcoincore-rpc-json" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c231bea28e314879c5aef240f6052e8a72a369e3c9f9b20d9bfbb33ad18029b2" +dependencies = [ + "bitcoin", + "serde", + "serde_json", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -567,6 +601,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonrpc" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8423b78fc94d12ef1a4a9d13c348c9a78766dda0cc18817adf0faf77e670c8" +dependencies = [ + "base64-compat", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "lazy_static" version = "1.4.0" diff --git a/bdk-ffi/Cargo.toml b/bdk-ffi/Cargo.toml index bd750b0..501de9d 100644 --- a/bdk-ffi/Cargo.toml +++ b/bdk-ffi/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["staticlib", "cdylib"] name = "bdkffi" [dependencies] -bdk = { version = "0.25", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled"] } +bdk = { version = "0.25", features = ["all-keys", "use-esplora-ureq", "sqlite-bundled", "rpc"] } uniffi_macros = { version = "0.21.0", features = ["builtin-bindgen"] } uniffi = { version = "0.21.0", features = ["builtin-bindgen"] } diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index 2a53dd4..f79aa16 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -45,6 +45,7 @@ enum BdkError { "Esplora", "Sled", "Rusqlite", + "Rpc", }; dictionary AddressInfo { @@ -126,10 +127,33 @@ dictionary EsploraConfig { u64? timeout; }; +[Enum] +interface Auth { + None(); + UserPass(string username, string password); + Cookie(string file); +}; + +dictionary RpcSyncParams { + u64 start_script_count; + u64 start_time; + boolean force_start_time; + u64 poll_rate_sec; +}; + +dictionary RpcConfig { + string url; + Auth auth; + Network network; + string wallet_name; + RpcSyncParams? sync_params; +}; + [Enum] interface BlockchainConfig { Electrum(ElectrumConfig config); Esplora(EsploraConfig config); + Rpc(RpcConfig config); }; interface Blockchain { diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index 1bb5364..8beae71 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -7,10 +7,12 @@ use bdk::bitcoin::util::psbt::PartiallySignedTransaction as BdkPartiallySignedTr use bdk::bitcoin::Sequence; use bdk::bitcoin::{Address as BdkAddress, Network, OutPoint as BdkOutPoint, Txid}; use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig}; +use bdk::blockchain::rpc::Auth as BdkAuth; use bdk::blockchain::GetBlockHash; use bdk::blockchain::GetHeight; use bdk::blockchain::{ - electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain, + electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, + rpc::RpcConfig as BdkRpcConfig, rpc::RpcSyncParams as BdkRpcSyncParams, ConfigurableBlockchain, }; use bdk::blockchain::{Blockchain as BdkBlockchain, Progress as BdkProgress}; use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration}; @@ -34,6 +36,7 @@ use std::collections::HashSet; use std::convert::{From, TryFrom}; use std::fmt; use std::ops::Deref; +use std::path::PathBuf; use std::str::FromStr; use std::sync::{Arc, Mutex, MutexGuard}; @@ -134,12 +137,84 @@ pub struct EsploraConfig { pub timeout: Option, } +pub enum Auth { + /// No authentication + None, + /// Authentication with username and password, usually [Auth::Cookie] should be preferred + UserPass { + /// Username + username: String, + /// Password + password: String, + }, + /// Authentication with a cookie file + Cookie { + /// Cookie file + file: String, + }, +} + +impl From for BdkAuth { + fn from(auth: Auth) -> Self { + match auth { + Auth::None => BdkAuth::None, + Auth::UserPass { username, password } => BdkAuth::UserPass { username, password }, + Auth::Cookie { file } => BdkAuth::Cookie { + file: PathBuf::from(file), + }, + } + } +} + +/// Sync parameters for Bitcoin Core RPC. +/// +/// In general, BDK tries to sync `scriptPubKey`s cached in `Database` with +/// `scriptPubKey`s imported in the Bitcoin Core Wallet. These parameters are used for determining +/// how the `importdescriptors` RPC calls are to be made. +pub struct RpcSyncParams { + /// The minimum number of scripts to scan for on initial sync. + pub start_script_count: u64, + /// Time in unix seconds in which initial sync will start scanning from (0 to start from genesis). + pub start_time: u64, + /// Forces every sync to use `start_time` as import timestamp. + pub force_start_time: bool, + /// RPC poll rate (in seconds) to get state updates. + pub poll_rate_sec: u64, +} + +impl From for BdkRpcSyncParams { + fn from(params: RpcSyncParams) -> Self { + BdkRpcSyncParams { + start_script_count: params.start_script_count as usize, + start_time: params.start_time, + force_start_time: params.force_start_time, + poll_rate_sec: params.poll_rate_sec, + } + } +} + +/// RpcBlockchain configuration options +pub struct RpcConfig { + /// The bitcoin node url + pub url: String, + /// The bitcoin node authentication mechanism + pub auth: Auth, + /// The network we are using (it will be checked the bitcoin node network matches this) + pub network: Network, + /// The wallet name in the bitcoin node, consider using [crate::wallet::wallet_name_from_descriptor] for this + pub wallet_name: String, + /// Sync parameters + pub sync_params: Option, +} + /// Type that can contain any of the blockchain configurations defined by the library. pub enum BlockchainConfig { /// Electrum client Electrum { config: ElectrumConfig }, /// Esplora client Esplora { config: EsploraConfig }, + /// Bitcoin Core RPC client + Rpc { config: RpcConfig }, } /// A wallet transaction @@ -200,6 +275,13 @@ impl Blockchain { timeout: config.timeout, }) } + BlockchainConfig::Rpc { config } => AnyBlockchainConfig::Rpc(BdkRpcConfig { + url: config.url, + auth: config.auth.into(), + network: config.network, + wallet_name: config.wallet_name, + sync_params: config.sync_params.map(|p| p.into()), + }), }; let blockchain = AnyBlockchain::from_config(&any_blockchain_config)?; Ok(Self {