A clean Bitcoin regtest environment using electrsd with automatic executable downloads.
-blockfilterindex=1 -peerblockfilters=1 -txindex=1 and P2P
enabled, so wallets can sync over CBF as well as via Electrumtestenv-server
binary runs the environment outside of a test, e.g. for the Java
integration testsInside your test use TestEnv.
// Create environment (automatically downloads executables)
let mut env = TestEnv::new()?;
env.mine_block()?;
// Create and fund an address
let address = env.new_address()?;
let txid = env.fund_address(&address, Amount::from_sat(100000))?;
// Wait until electrum sees the transaction, then confirm it
env.wait_for_tx(txid)?;
env.mine_block()?;
env.wait_for_block()?;
println!("Transaction confirmed: {}", txid);
The wait_for_* methods poll until the configured
Config::timeout (5 seconds by default) expires.
The test environment provides a web-based blockchain explorer for visual debugging.
// Create environment
let mut env = TestEnv::new()?;
// Start the Container with the web-ui in a separate process.
// only include this line if you want to debug. do not check in into git.
env.start_explorer_in_container()?;
this will automatically start the podman container, so you need to have podman installed. It will destroy the container when Testenv is dropped.
When the frontend container is started, it will log the URL to access
the explorer (via tracing, so make sure logging is not
switched off with RUST_LOG=off). The port always changes
and therefore parallel testing works, even though it makes little sense
to have more than one frontend container running.
env.debug_tx(txid) logs the explorer URL of a specific
transaction.
Note: Keep the Rust environment running while using the web interface. So you need to set a breakpoint, then you have time to inspect the blockchain. If the program terminates, the blockchain is dropped (and the container).
// Create custom configuration
let mut config = Config::default();
// Customize bitcoind settings
config.bitcoind.args.push("-maxmempool=100");
// Wait longer in the wait_for_* methods
config.timeout = Duration::from_secs(10);
// Customize electrsd settings
// config.electrsd.view_stderr = true; // Uncomment to see electrsd logs
// Create environment with custom configuration
let mut env = TestEnv::new_with_conf(config)?;
env.mine_blocks(5)?;
TestEnvBuilder offers a shortcut for a fixed RPC
password and a persistent data directory:
let env = TestEnvBuilder::new(Some("bitcoin".to_owned()))
.with_data_dir(Some(PathBuf::from("/path/to/data")))
.build()?;
# Override executables via environment variables
export BITCOIND_EXEC="/custom/path/to/bitcoind"
export ELECTRS_EXEC="/custom/path/to/electrs"
cargo test # Will use custom executables
# Allow several TestEnv instances to run at the same time (faster, but may be flaky).
# By default a global lock serializes them.
TEST_MULTITHREADED=true cargo testcargo run --bin testenv-server -p testenv # temporary data, deleted on exit
cargo run --bin testenv-server -p testenv -- --data-dir /path/to/dir # persistent dataIt prints the connection details as KEY=value lines
(TESTENV_RPC_URL, TESTENV_RPC_USER,
TESTENV_RPC_PASS, TESTENV_ELECTRUM_URL,
TESTENV_P2P_ADDR, …) and runs until stopped with Ctrl+C.
The RPC credentials are bitcoin/bitcoin.
The main environment manager that handles both bitcoind and electrs instances.
⚠️ Important: Keep the
TestEnvinstance alive (don’t drop it) while you need the services running. When the instance is dropped, both bitcoind and electrs processes will be terminated.
TestEnv::new() - Creates environment with automatic
downloadsTestEnv::new_with_conf(config) - Creates environment
with custom configurationTestEnv::enable_zmq() - Creates environment with ZMQ
notifications enabled on bitcoindTestEnvBuilder - Builder for a fixed RPC password
and/or persistent data directoryelectrum_client() / bdk_electrum_client()
- Access to the electrum client for blockchain operationsnew_client() - Create a new, independent
BdkElectrumClientnew_testchain() - Create a Testchain
(implements ChainApi / ChainScanner)bitcoind_client() /
bitcoin_core_rpc_client() - Access to bitcoind’s RPCelectrum_url() - Get electrum server URLesplora_url() - Get Esplora REST URL (if
available)bitcoin_rpc_port() /
bitcoin_rpc_password() - RPC connection details (user is
bitcoin)p2p_socket_addr() - bitcoind’s P2P address, e.g. for
Compact Block Filter syncingzmq_pub_raw_tx_socket() /
zmq_pub_raw_block_socket() - ZMQ endpoints (with
enable_zmq())TestEnv itself also implements
ChainScanner.
start_explorer_in_container() - Starts btc-rpc-explorer
in a podman containerdebug_tx(txid) - Logs the explorer URL of a
transactionmine_block() - Mine a single blockmine_blocks(count) - Mine multiple blocksfund_address(address, amount) - Send BTC to
addressfund_from_prv_key(key, amount) - Send BTC to the P2TR
address of a private keybroadcast(tx) - Broadcast a transactionnew_address() - Generate new test addresswait_for_block() - Wait for electrum to see new
blockwait_for_tx(txid) - Wait for electrum and bitcoind to
see transactionblock_count() - Get current blockchain heightbest_block_hash() - Get current tip block hashgenesis_hash() - Get genesis block hashtrigger_sync() - Trigger electrs sync (Unix only)workdir() - Get working directory pathnew_temp_path() - Get a fresh temporary directory that
lives as long as the TestEnvTestEnv::get_bound_port() - Get a
TcpListener bound to a free local portThe executables are downloaded automatically at build time, so the tests need no further setup:
cargo test -p testenv