Tutorials
Configure the Esplora Proxy with BDK
9 min
this guide will walk you through how to setup an authenticated esplora proxy for bdk https //github com/bitcoindevkit/bdk applications to communicate with the maestro esplora api https //docs gomaestro org/esplora api service bdk client โ esplora proxy โ maestro esplora api requirements maestro api key https //dashboard gomaestro org configuration clone maestro esplora proxy https //github com/maestro org/maestro esplora proxy repo git clone https //github com/maestro org/maestro esplora proxy git && cd maestro esplora proxy copy env example template cp env example env edit your env file maestro api key=your maestro api key here \# mainnet esplora url=https //xbt mainnet gomaestro api org/v0/esplora \# testnet4 \# esplora url=https //xbt testnet gomaestro api org/v0/esplora cargo toml \[package] name = "maestro esplora proxy" version = "0 1 0" edition = "2021" \[dependencies] hyper = { version = "1 6 0", features = \["full"] } hyper util = { version = "0 1", features = \["full"] } hyper tls = "0 6" http body util = "0 1" bytes = "1 0" tokio = { version = "1", features = \["full"] } chrono = { version = "0 4", features = \["serde"] } dotenvy = "0 15" src/main rs use hyper {request, response, uri}; use hyper body incoming; use hyper service service fn; use hyper util client legacy client; use hyper util rt tokioexecutor; use http body util {full, bodyext}; use std convert infallible; use std net socketaddr; use dotenvy dotenv; // load env file dotenv() ok(); // read values from environment let api key = env var("maestro api key") expect("maestro api key not set"); let esplora url = env var("esplora url") expect("esplora url not set"); \#\[tokio main] async fn main() { let addr socketaddr = (\[0, 0, 0, 0], 8080) into(); println!("proxy listening on http //{}", addr); let listener = match tokio net tcplistener bind(addr) await { ok(listener) => listener, err(e) => { eprintln!("failed to bind to address {} {}", addr, e); std process exit(1); } }; loop { let (stream, ) = match listener accept() await { ok(conn) => conn, err(e) => { eprintln!("failed to accept connection { ?}", e); continue; } }; let io = hyper util rt tokioio new(stream); tokio task spawn(async move { if let err(err) = hyper server conn http1 builder new() serve connection(io, service fn(proxy handler)) await { eprintln!("error serving connection { ?}", err); } }); } } async fn proxy handler(req request\<incoming>) > result\<response\<full\<bytes bytes>>, infallible> { // extract info before consuming request let method = req method() clone(); let path and query = req uri() path and query() map(|x| x as str()) unwrap or("") to string(); let timestamp = chrono utc now() format("%y %m %d %h %m %s utc"); println!("\[{}] {} {} proxying request ", timestamp, method, path and query); // build new uri with api key as query parameter let separator = if path and query contains('?') { "&" } else { "?" }; let target uri uri = format!( "{}{}{}api key={}", esplora url, path and query, separator, api key ) parse() map err(|e| { eprintln!("failed to parse uri {}", e); response builder() status(400) body(full new(bytes bytes from("invalid uri"))) unwrap() })?; // clone request body let whole body = req into body() collect() await unwrap() to bytes(); // build new request with api key in query parameter let new req = request builder() method(method clone()) uri(target uri clone()) body(full new(whole body)) unwrap(); // send request to esplora let https connector = hyper tls httpsconnector new(); let client = client builder(tokioexecutor new()) build(https connector); match client request(new req) await { ok(resp) => { let status = resp status(); println!("\[{}] {} {} response {}", timestamp, method, path and query, status); let (parts, body) = resp into parts(); let body bytes = body collect() await unwrap() to bytes(); let response = response from parts(parts, full new(body bytes)); ok(response) } err(e) => { println!("\[{}] {} {} error {}", timestamp, method, path and query, e); // return a 500 error response let response = response builder() status(500) body(full new(bytes bytes from(format!("proxy error {}", e)))) unwrap(); ok(response) } } } run proxy cargo run bdk integration below is a barebones example of how to integrate the esplora proxy into your bdk https //github com/bitcoindevkit/bdk client change esplora url to point to proxy // before let blockchain = esplorablockchain new("https //blockstream info/testnet/api", 20); // after let blockchain = esplorablockchain new("http //localhost 8080", 20); example use bdk blockchain esplora esplorablockchain; use bdk {syncoptions, wallet}; let blockchain = esplorablockchain new("http //localhost 8080", 20); wallet sync(\&blockchain, syncoptions default())?; let balance = wallet get balance()?; ๐ youโre done! you now have walked through a guide on how to configure your bdk https //github com/bitcoindevkit/bdk client and esplora proxy to communicate with the maestro esplora api https //docs gomaestro org/esplora api service additional resources maestro documentation https //docs gomaestro org/esplora api https //docs gomaestro org/esplora api esplora postman https //www postman com/go maestro/maestro api/collection/tbetkqq/bitcoin esplora api https //www postman com/go maestro/maestro api/collection/tbetkqq/bitcoin esplora api be sure to review maestro's rate limits and pricing tiers https //www gomaestro org/pricing to select the plan that best fits your application's needs support if you are experiencing any trouble with the above, reach out on https //discord gg/es2rdhbjt3 https //discord gg/es2rdhbjt3 discord