Rust比特币开发工具包BDK的使用,BDK提供安全的比特币钱包构建与区块链交互功能

Rust比特币开发工具包BDK的使用,BDK提供安全的比特币钱包构建与区块链交互功能

BDK Logo

关于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(())
}

最佳实践

  1. 密钥安全:永远不要将私钥硬编码在源代码中
  2. 描述符使用:优先使用描述符钱包而非原始私钥
  3. 错误处理:妥善处理所有可能的错误
  4. 网络选择:开发时使用Testnet,生产环境再切换到Mainnet
  5. 费用估算:合理设置交易费用

BDK为Rust开发者提供了构建比特币应用的强大工具集,通过模块化设计平衡了安全性与灵活性。

回到顶部