Rust比特币开发工具包BDK的使用,BDK提供安全的比特币钱包构建与区块链交互功能
Rust比特币开发工具包BDK的使用,BDK提供安全的比特币钱包构建与区块链交互功能
关于BDK
BDK库旨在成为各种比特币钱包的核心构建块:
- 使用Miniscript支持带广义条件的描述符
- 支持多种区块链后端和数据库
- 跨平台设计(桌面、移动端、WebAssembly)
- 易于扩展(可自定义区块链后端、数据库、签名器等)
示例代码
同步描述符余额
use bdk::Wallet;
use bdk::database::MemoryDatabase;
use bdk::blockchain::ElectrumBlockchain;
use bdk::SyncOptions;
use bdk::electrum_client::Client;
use bdk::bitcoin::Network;
fn main() -> Result<(), bdk::Error> {
// 创建Electrum区块链客户端
let blockchain = ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002")?);
// 创建钱包实例
let wallet = Wallet::new(
"wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
Network::Testnet,
MemoryDatabase::default(),
)?;
// 同步钱包余额
wallet.sync(&blockchain, SyncOptions::default())?;
// 打印余额
println!("Descriptor balance: {} SAT", wallet.get_balance()?);
Ok(())
}
生成多个地址
use bdk::{Wallet, database::MemoryDatabase};
use bdk::wallet::AddressIndex::New;
use bdk::bitcoin::Network;
fn main() -> Result<(), bdk::Error> {
// 创建测试网钱包
let wallet = Wallet::new(
"wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
Network::Testnet,
MemoryDatabase::default(),
)?;
// 生成3个新地址
println!("Address #0: {}", wallet.get_address(New)?);
println!("Address #1: {}", wallet.get_address(New)?);
println!("Address #2: {}", wallet.get_address(New)?);
Ok(())
}
创建交易
use bdk::{FeeRate, Wallet, SyncOptions};
use bdk::database::MemoryDatabase;
use bdk::blockchain::ElectrumBlockchain;
use bdk::electrum_client::Client;
use bdk::wallet::AddressIndex::New;
use bitcoin::base64;
use bdk::bitcoin::consensus::serialize;
use bdk::bitcoin::Network;
fn main() -> Result<(), bdk::Error> {
// 初始化区块链连接
let blockchain = ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002")?);
// 创建钱包
let wallet = Wallet::new(
"wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP极速4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbn极速SNecE/1/*)"),
Network::Testnet,
MemoryDatabase::default(),
)?;
// 同步钱包
wallet.sync(&blockchain, SyncOptions::default())?;
// 获取新地址作为接收方
let send_to = wallet.get_address(New)?;
// 构建交易
let (psbt, details) = {
let mut builder = wallet.build_tx();
builder
.add_recipient(send_to.script_pubkey(), 50_000) // 添加接收方和金额
.enable_rbf() // 启用RBF
.do_not_spend_change() // 不花费找零
.fee_rate(FeeRate::from_sat_per_vb(5.0)); // 设置费率
builder.finish()?
};
// 打印交易详情和PSBT
println!("Transaction details: {:#?}", details);
println!("Unsigned PSBT: {}", base64::encode(psbt.serialize()));
Ok(())
}
签名交易
use bdk::{Wallet, SignOptions, database::MemoryDatabase};
use bitcoin::base64;
use bdk::bitcoin::consensus::deserialize;
use bdk::bitcoin::{psbt::Psbt, Network};
fn main() -> Result<(), bdk::Error> {
// 创建钱包实例
let wallet = Wallet::new(
"wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
Some("wpkh([c258d2e4/84h极速1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
Network::Testnet,
MemoryDatabase::default(),
)?;
// 假设的PSBT数据
let psbt = "...";
let mut psbt = Psbt::deserialize(&base64::decode(psbt).unwrap())?;
// 签名交易
let _finalized = wallet.sign(&mut psbt, SignOptions::default())?;
Ok(())
}
完整示例Demo
以下是一个完整的BDK钱包使用示例,包含创建钱包、同步余额、生成地址和创建交易:
use bdk::{
Wallet,
database::MemoryDatabase,
blockchain::{Blockchain, ElectrumBlockchain},
SyncOptions,
electrum_client::Client,
bitcoin::Network,
wallet::AddressIndex::New,
FeeRate
};
fn main() -> Result<(), bdk::Error> {
// 1. 创建区块链客户端
let client = Client::new("ssl://electrum.blockstream.info:60002")?;
let blockchain = ElectrumBlockchain::from(client);
// 2. 创建钱包
let wallet = Wallet::new(
"wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A极速ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
Network::Testnet,
MemoryDatabase::default(),
)?;
// 3. 同步钱包
wallet.sync(&blockchain, SyncOptions::default())?;
// 4. 打印余额
println!("Wallet balance: {} SAT", wallet.get_balance()?);
// 5. 生成新地址
let new_address = wallet.get_address(New)?;
println!("New receiving address: {}", new_address);
// 6. 创建交易
let (psbt, details) = {
let mut builder = wallet.build_tx();
builder
.add_recipient(new_address.script_pubkey(), 10_000)
.fee_rate(FeeRate::from_sat_per_vb(5.0));
builder.finish()?
};
println!("Transaction details: {:#?}", details);
Ok(())
}
注意
bdk
库现已弃用,建议迁移至bdk_wallet 1.0.0
或更新版本。
1 回复
Rust比特币开发工具包BDK使用指南
什么是BDK
BDK (Bitcoin Development Kit) 是一个Rust编写的比特币开发工具包,提供安全构建比特币钱包和与区块链交互的功能。它旨在成为比特币应用开发的模块化基础组件。
主要特性
- 支持多种区块链后端(Esplora, Electrum, Compact Filters等)
- 提供钱包创建、交易构建和签名功能
- 支持描述符钱包(Descriptor Wallet)
- 包含丰富的密钥管理选项
- 可自定义的数据库存储
- 支持主流操作系统和WASM
安装BDK
在Cargo.toml中添加依赖:
[dependencies]
bdk = { version = "0.28.0", features = ["all"] }
基础使用示例
1. 创建钱包
use bdk::{
blockchain::ElectrumBlockchain,
database::MemoryDatabase,
wallet::AddressIndex,
SyncOptions, Wallet,
};
use bdk::electrum_client::Client as ElectrumClient;
use bdk::bitcoin::Network;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建描述符钱包
let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/0/*)";
let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/1/*)";
let wallet = Wallet::new(
external_descriptor,
Some(internal_descriptor),
Network::Testnet,
MemoryDatabase::default(),
)?;
// 获取新地址
let new_address = wallet.get_address(AddressIndex::New)?;
println!("Generated new address: {}", new_address.address);
Ok(())
}
2. 同步钱包余额
use bdk::blockchain::ElectrumBlockchain;
use bdk::electrum_client::Client;
fn sync_wallet(wallet: &Wallet<MemoryDatabase>) -> Result<(), Box<dyn std::error::Error>> {
let electrum_url = "ssl://electrum.blockstream.info:60002";
let blockchain = ElectrumBlockchain::from(ElectrumClient::new(electrum_url)?);
wallet.sync(&blockchain, SyncOptions::default())?;
let balance = wallet.get_balance()?;
println!("Wallet balance: {} satoshis", balance);
Ok(())
}
3. 创建并广播交易
use bdk::bitcoin::Address;
fn create_transaction(
wallet: &Wallet<MemoryDatabase>,
recipient: &str,
amount: u64,
) -> Result<(), Box<dyn std::error::Error>> {
let recipient_address = Address::from_str(recipient)?.assume_checked();
let mut tx_builder = wallet.build_tx();
tx_builder
.add_recipient(recipient_address.script_pubkey(), amount)
.enable_rbf();
let (mut psbt, _) = tx_builder.finish()?;
let finalized = wallet.sign(&mut psbt, Default::default())?;
if finalized {
let raw_transaction = psbt.extract_tx();
let txid = raw_transaction.txid();
// 广播交易
let electrum_url = "ssl://electrum.blockstream.info:60002";
let blockchain = ElectrumBlockchain::from(ElectrumClient::new(electrum_url)?);
blockchain.bbroadcast(&raw_transaction)?;
println!("Transaction broadcasted: {}", txid);
}
Ok(())
}
高级功能
使用不同区块链后端
BDK支持多种区块链后端:
// 使用Esplora后端
use bdk::blockchain::EsploraBlockchain;
let esplora_url = "https://blockstream.info/testnet/api";
let blockchain = EsploraBlockchain::new(esplora_url, 20);
// 使用Compact Filters (BIP157/158)
use bdk::blockchain::CompactFiltersBlockchain;
let cf_url = "127.0.0.1:8333";
let blockchain = CompactFiltersBlockchain::new(cf_url, Network::Bitcoin)?;
使用不同数据库
// 使用SQLite数据库
use bdk::database::SqliteDatabase;
let wallet = Wallet::new(
external_descriptor,
Some(internal_descriptor),
Network::Testnet,
SqliteDatabase::new("wallet.db")?,
)?;
// 使用内存数据库 (仅示例)
use bdk::database::MemoryDatabase;
let wallet = Wallet::new(
external_descriptor,
Some(internal_descriptor),
Network::Testnet,
MemoryDatabase::default(),
)?;
完整示例代码
下面是一个完整的BDK示例,包含钱包创建、同步和发送交易:
use bdk::{
bitcoin::Network,
blockchain::{Blockchain, ElectrumBlockchain},
database::MemoryDatabase,
electrum_client::Client as ElectrumClient,
wallet::{AddressIndex, Wallet},
SyncOptions,
};
use bdk::bitcoin::Address;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 创建钱包
let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/0/*)";
let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/1/*)";
let wallet = Wallet::new(
external_descriptor,
Some(internal_descriptor),
Network::Testnet,
MemoryDatabase::default(),
)?;
// 2. 获取新地址
let new_address = wallet.get_address(AddressIndex::New)?;
println!("New address: {}", new_address.address);
// 3. 同步钱包
let electrum_url = "ssl://electrum.blockstream.info:60002";
let blockchain = ElectrumBlockchain::from(ElectrumClient::new(electrum_url)?);
wallet.sync(&blockchain, SyncOptions::default())?;
// 4. 检查余额
let balance = wallet.get_balance()?;
println!("Wallet balance: {} satoshis", balance);
// 5. 发送交易(如果有余额)
if balance > 1000 {
let recipient = "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx";
let amount = 500;
let recipient_address = Address::from_str(recipient)?.assume_checked();
let mut tx_builder = wallet.build_tx();
tx_builder
.add_recipient(recipient_address.script_pubkey(), amount)
.enable_rbf();
let (mut psbt, _) = tx_builder.finish()?;
let finalized = wallet.sign(&mut psbt, Default::default())?;
if finalized {
let raw_transaction = psbt.extract_tx();
let txid = raw_transaction.txid();
blockchain.broadcast(&raw_transaction)?;
println!("Transaction broadcasted: {}", txid);
}
}
Ok(())
}
最佳实践
- 密钥安全:永远不要将私钥硬编码在源代码中
- 描述符使用:优先使用描述符钱包而非原始私钥
- 错误处理:妥善处理所有可能的错误
- 网络选择:开发时使用Testnet,生产环境再切换到Mainnet
- 费用估算:合理设置交易费用
BDK为Rust开发者提供了构建比特币应用的强大工具集,通过模块化设计平衡了安全性与灵活性。