diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..4f1bd7c9 --- /dev/null +++ b/.env.example @@ -0,0 +1,118 @@ +# bdk-cli environment variables +# +# Copy this file to .env and uncomment the lines you want to set. +# Values here are loaded automatically when bdk-cli starts (via dotenvy). +# Command-line flags always take precedence over these values. +# +# cp .env.example .env + +# Global options + +# NETWORK=regtest +# DATADIR=~/.bdk-bitcoin +# WALLET_NAME=my_wallet + +# Wallet descriptors — used with `wallet config` or passed directly as flags + +# EXT_DESCRIPTOR=wpkh(/84h/1h/0h/0/*)# +# INT_DESCRIPTOR=wpkh(/84h/1h/0h/1/*)# + +# Blockchain backend — requires the matching compiled feature: electrum | esplora | rpc | cbf + +# CLIENT_TYPE=rpc +# DATABASE_TYPE=sqlite +# +# SERVER_URL values by backend: +# rpc: 127.0.0.1:18443 +# electrum: ssl://mempool.space:40002 +# esplora: https://mempool.space/testnet4/api +# SERVER_URL=127.0.0.1:18443 + +# RPC backend — CLIENT_TYPE=rpc + +# Basic auth, format user:password +# RPC_BASIC_AUTH=user:password +# +# Cookie file path, alternative to RPC_BASIC_AUTH +# COOKIE=~/.bitcoin/regtest/.cookie + +# Electrum backend — CLIENT_TYPE=electrum + +# ELECTRUM_BATCH_SIZE=10 + +# Esplora backend — CLIENT_TYPE=esplora + +# ESPLORA_PARALLEL_REQUESTS=5 + +# SOCKS5 proxy — electrum | esplora | cbf backends + +# PROXY_ADDRS_PORT=socks5://127.0.0.1:9050 +# PROXY_USER_PASSWD=: +# PROXY_RETRIES=5 +# PROXY_TIMEOUT= + +# Full scan + +# STOP_GAP=20 + +# Key management — key generate | key restore | key derive + +# WORD_COUNT=12 +# PASSWORD= +# MNEMONIC= ... +# XPRV= +# DERIVATION_PATH=m/84h/1h/0h + +# Transaction building — create_tx + +# Recipient, format
:, e.g. bcrt1q:50000 for regtest +# ADDRESS_SAT=bcrt1q:50000 + +# SATS_VBYTE=2 + +# UTXOs that must be included, format : +# MUST_SPEND_TXID_VOUT=:0 + +# UTXOs that must not be included +# CANT_SPEND_TXID_VOUT=:0 + +# EXT_POLICY= +# INT_POLICY= + +# OP_RETURN as a UTF-8 string, max 80 bytes, conflicts with ADD_DATA +# ADD_STRING= + +# OP_RETURN as base64, max 80 bytes, conflicts with ADD_STRING +# ADD_DATA= + +# PSBT operations — sign | broadcast | bump_fee + +# BASE64_PSBT= +# RAWTX= +# TXID= +# HEIGHT= +# WITNESS=false +# SHRINK_ADDRESS=bcrt1q + +# Miniscript compiler — compile (feature: compiler) + +# Spending policy to compile, e.g. or(pk(),and(pk(),older(52560))) +# POLICY= +# +# Script type to embed the compiled policy in: sh | wsh | sh-wsh | tr +# TYPE=wsh + +# Payjoin — receive_payjoin | send_payjoin | resume_payjoin +# Requires a backend feature compiled in. + +# PAYJOIN_AMOUNT=400000 +# PAYJOIN_DIRECTORY=https://payjo.in +# PAYJOIN_OHTTP_RELAY=https://pj.bobspacebkk.com +# PAYJOIN_RECEIVER_MAX_FEE_RATE= +# PAYJOIN_URI=bitcoin:bcrt1q?amount=0.004&pj=https://payjo.in/ +# PAYJOIN_SENDER_FEE_RATE=1 +# PAYJOIN_SESSION_ID= + +# Logging +# RUST_LOG=warn +# Scope to specific crates: RUST_LOG=debug,rusqlite=info,rustls=info diff --git a/.gitignore b/.gitignore index 6dfb84d0..b3f36133 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.swp .idea +.env diff --git a/Cargo.lock b/Cargo.lock index 9b1d2695..d8cc3e0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,6 +261,7 @@ dependencies = [ "clap_complete", "cli-table", "dirs", + "dotenvy", "env_logger", "log", "payjoin", @@ -1230,6 +1231,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dunce" version = "1.0.5" @@ -3362,7 +3369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix 1.1.4", "windows-sys 0.61.2", diff --git a/Cargo.toml b/Cargo.toml index adc1d9c9..bae4631a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ tracing = "0.1.44" tracing-subscriber = "0.3.20" toml = "1.1.0" serde= {version = "1.0", features = ["derive"]} +dotenvy = "0.15" # Optional dependencies bdk_bitcoind_rpc = { version = "0.22.0", features = ["std"], optional = true } diff --git a/README.md b/README.md index 94278f3c..74a3334e 100644 --- a/README.md +++ b/README.md @@ -70,16 +70,55 @@ Building BDK requires `gcc`. If you do not have this installed run: sudo apt-get install build-essential ``` +#### Bitcoin Core (required for the `rpc` backend and the Justfile workflow) + +The `rpc` feature and all `just` recipes (`just start`, `just create`, `just generate`, etc.) require +`bitcoind` and `bitcoin-cli` to be on your `PATH`. They are **not** installed automatically. + +If you do not have Bitcoin Core installed, download the official binaries for your platform from +[bitcoincore.org](https://bitcoincore.org/en/download/) and add the `bin/` directory to your `PATH`. + +On Linux (x86_64), a quick install looks like: + +```shell +# Download and extract Bitcoin Core 29.0 +cd /tmp +wget https://bitcoincore.org/bin/bitcoin-core-29.0/bitcoin-29.0-x86_64-linux-gnu.tar.gz +tar xzf bitcoin-29.0-x86_64-linux-gnu.tar.gz -C ~/.local/ + +# Add to PATH (add this line to your ~/.bashrc or ~/.zshrc to make it permanent) +export PATH="$HOME/.local/bitcoin-29.0/bin:$PATH" + +# Verify +bitcoind --version +bitcoin-cli --version +``` + +> **Security note:** the snippet above skips checksum verification for brevity. Before running +> these binaries, verify them against the signed `SHA256SUMS` from the +> [download page](https://bitcoincore.org/en/download/) - see the +> [verification guide](https://bitcoincore.org/en/download/#verify-your-download) for the full steps. + +If you only want to test with a public server (no local node), use the `electrum` or `esplora` +feature instead — those do not require a local `bitcoind`: + +```shell +cargo install --path . --features electrum +``` + ### From source To install a dev version of `bdk-cli` from a local git repo with the `electrum` blockchain client enabled: ```shell cd +cp .env.example .env # set your network, wallet name, and backend defaults cargo install --path . --features electrum bdk-cli help # to verify it worked ``` +`.env.example` documents every supported environment variable. Copy it to `.env` at the repo root and uncomment the values you want. The file is loaded automatically on startup; command-line flags always take precedence. + If no blockchain client feature is enabled online wallet commands `sync` and `broadcast` will be disabled. To enable these commands a blockchain client feature such as `electrum` or another blockchain client feature must be enabled. Below is an example of how to run the `bdk-cli` binary with @@ -232,12 +271,20 @@ Note: You can modify the `Justfile` to reflect your nodes' configuration values. #### Steps -1. Start bitcoind +1. Copy the environment template at the repo root + + ```shell + cp .env.example .env + ``` + + Edit `.env` to set `NETWORK`, `RPC_BASIC_AUTH`, and any other values you want as defaults. The Justfile uses its own hardcoded defaults (`user`/`password`, `~/.bdk-bitcoin`), but bdk-cli commands in later steps will pick up whatever you set in `.env`. + +2. Start bitcoind ```shell just start ``` -2. Create or load a bitcoind wallet with default wallet name +3. Create or load a bitcoind wallet with default wallet name ```shell just create @@ -247,44 +294,47 @@ Note: You can modify the `Justfile` to reflect your nodes' configuration values. just load ``` -3. Generate a bitcoind wallet address to send regtest bitcoins to. +4. Generate a bitcoind wallet address to send regtest bitcoins to. ```shell just address ``` -4. Mine 101 blocks on regtest to bitcoind wallet address +5. Mine 101 blocks on regtest to bitcoind wallet address + + > **Note:** use `$(just address)` (command substitution with `$(...)`), not `${just address}`. + ```shell just generate 101 $(just address) ``` -5. Check the bitcoind wallet balance +6. Check the bitcoind wallet balance ```shell just balance ``` -6. Setup your `bdk-cli` wallet config and connect it to your regtest node to perform a `sync` +7. Setup your `bdk-cli` wallet config and connect it to your regtest node to perform a `sync` ```shell cargo run --features rpc -- -n regtest wallet -w regtest1 config -e "wpkh(tprv8ZgxMBicQKsPdMzWj9KHvoExKJDqfZFuT5D8o9XVZ3wfyUcnPNPJKncq5df8kpDWnMxoKbGrpS44VawHG17ZSwTkdhEtVRzSYXd14vDYXKw/0/*)" -i "wpkh(tprv8ZgxMBicQKsPdMzWj9KHvoExKJDqfZFuT5D8o9XVZ3wfyUcnPNPJKncq5df8kpDWnMxoKbGrpS44VawHG17ZSwTkdhEtVRzSYXd14vDYXKw/1/*)" -u "127.0.0.1:18443" -c rpc -d sqlite -a user:password cargo run --features rpc -- wallet -w regtest1 sync ``` -7. Generate an address from your `bdk-cli` wallet and fund it with 10 bitcoins from your bitcoind node's wallet +8. Generate an address from your `bdk-cli` wallet and fund it with 10 bitcoins from your bitcoind node's wallet ```shell export address=$(cargo run --features rpc -- wallet -w regtest1 new_address | jq '.address') just send 10 $address ``` -8. Mine 6 more blocks to the bitcoind wallet +9. Mine 6 more blocks to the bitcoind wallet ```shell just generate 6 $(just address) ``` -9. You can `sync` your `bdk-cli` wallet now and the balance should reflect the regtest bitcoin you received - ```shell - cargo run --features rpc -- wallet -w regtest1 sync - cargo run --features rpc -- wallet -w regtest1 balance - ``` +10. You can `sync` your `bdk-cli` wallet now and the balance should reflect the regtest bitcoin you received + ```shell + cargo run --features rpc -- wallet -w regtest1 sync + cargo run --features rpc -- wallet -w regtest1 balance + ``` ## Shell Completions diff --git a/src/main.rs b/src/main.rs index 06e3ea24..cb0865f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,7 +33,13 @@ use clap::{CommandFactory, Parser}; #[tokio::main] async fn main() { + let dotenv_result = dotenvy::dotenv(); env_logger::init(); + if let Err(e) = dotenv_result { + if !e.not_found() { + warn!(".env file found but failed to load: {e}"); + } + } let cli_opts: CliOpts = CliOpts::parse(); let network = &cli_opts.network;