像做拼乐高一样,用简单的条件拼出复杂而安全的比特币脚本。
许多用户以为比特币只能进行“地址到地址”的转账,事实远不止如此:每一聪比特币背后都是一个可编程脚本。只是过去,想写出既正确又省费率的脚本门槛过高,直到 Miniscript 与 描述符(Descriptor) 诞生。本文通过一口气读完的案例,带你掌握这对隐藏力量,轻松实现多签名、时间锁、智能奖金等高级场景,并确保在所有钱包间“一次定义,处处通用”。
为何我们不能只看地址:Script 101
比特币使用一种极简的 基于堆栈的脚本语言(Script) 判断交易有效性:只要脚本执行完最后留在栈顶的是 true,资金就花得动。经典例子——支付到公钥哈希(P2PKH):
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG虽然可靠,但遇到多签、时间锁、哈希锁等条件,人类要读懂并手动优化几乎不可能。于是我们提出三大灵魂疑问:
- 写的逻辑正确吗?
- 字节够小吗?(关系到手续费)
- 能在所有钱包通用吗?
Miniscript 与描述符正是替我们回答这三问的答案。
Miniscript:把脚本拆成积木
Miniscript 并没有引入新操作码,而是用 6 个极简块 语句化表达任何脚本组合:
pk(key):单一私钥签名thresh(k, ...):k-of-n 多签older(T):相对 T 个区块时间锁and(expr1,expr2)/or(expr1,expr2):逻辑与或aor(left,right):权重型or,优先左侧
几行表达式即可拼出复杂场景:
| 场景 | Miniscript |
|---|---|
| 单签支付 | pk(A) |
| 2-of-3 托管 | thresh(2,pk(A),pk(B),pk(C)) |
| 金库:A 等待 30 天,B 随时能提 | aor(and(pk(A),older(4320)), pk(B)) |
这些表达式会被 Miniscript 编译器 自动翻译成最优的底层脚本,保证正确、紧凑、可验证。
描述符:让钱包说同一种语言
钱包通常对同一套私钥生成不同格式地址:pkh、wpkh、sh(WPKH)、tr 等。若不同钱包派生路径不一致,就会出现“我把币发到一个地址,但另一钱包看不见”的尴尬。
描述符 简单得像一串 DNA:既能声明地址格式,又能内嵌 Miniscript 条件,让任何支持描述符的客户端还原出完全同步的地址列表。示例:
wpkh([d34db33f/84'/0'/0']xpub6ER.../0/*)#checksum- wpkh:说明是隔离见证 v0 单签
- 中括号:给出主密钥指纹与派生路径
- xpub:主公钥
- /0/*:具体派生索引
- 校验和:防止手抖输错
一旦相同描述符被导入多款钱包,它们将永不漂移,实现 可移植性、互操作性、备份一体。
动手实验:30 分钟跑完整流程
我们将用 bitcoind、bdk-cli 做出三个成品演示:
- 保障 50 BTC 的 2-of-3 多签冷钱包
- “锁仓两个月”的员工保留奖金智能合约
- 对比
bitcoin-cli与bdk-cli生成,验证地址一致
(本地需装 Docker、bdk-cli、miniscriptc,下文演示 regtest。)
步骤 1:启动 regtest 节点
# bitcoind.conf
regtest=1
fallbackfee=0.0001
server=1
rpcuser=user
rpcpassword=passwordbitcoind -conf=$PWD/bitcoind.conf步骤 2:创建描述符钱包
生成私钥并定义描述符:
XPRV=$(bdk-cli key generate | jq -r '.xprv')
DESC="wpkh($XPRV/86'/1'/0'/0/*)"
CHECKSUM=$(bitcoin-cli getdescriptorinfo "$DESC" | jq -r '.checksum')
FULL_DESC="$DESC#$CHECKSUM"
bitcoin-cli -named createwallet wallet_name=regtest descriptors=true
bitcoin-cli -rpcwallet=regtest importdescriptors "[{\"desc\":\"$FULL_DESC\",\"timestamp\":\"now\",\"active\":true,\"range\":[0,100]}]"将同一条描述符导入 bdk-cli,两边得到的地址 100% 对应,一符走天下验证成功。
步骤 3:2-of-3 冷钱包
# 快速生成三条私钥
for i in {1..3}; do echo K${i}_XPRV=$(bdk-cli key generate | jq -r '.xprv'); done
# 组合描述符
W_DESC="wsh(multi(2,$K1_XPRV/84'/1'/0'/0/*,$K2_XPUB,$K3_XPUB))"
alias kWallet='bdk-cli -n regtest wallet -w vault -d $W_DESC'- 只需两把签名即可动用,任何一把丢失不致命
- 通过 PSBT 先后签名,广播后再通过
bitcoin-cli generate出块确认 - 三端钱包仅靠 同一条描述符字符串 保持同步
步骤 4:员工锁仓奖金
需求:公司 C 在两个月(8640 区块)后给雇员 E 发 1 BTC;期间公司需有撤回权。
Miniscript:
or(99@and(pk(E),older(8640)),pk(C))编译为描述符:
sh(wsh(andor(pk(E),older(8640),pk(C))))将描述符分别导入 C 钱包与 E 钱包。尝试在 8640 区块前广播花费,直接被网络拒绝(非 BIP68-final);模拟两个月后成功解锁。如此无需法律合同,代码即规则。
FAQ:常见疑问一次说清
Q1:Miniscript 能支持 Taproot 吗?
A:可以。Taproot 描述符使用 tr(key, tree) 指定内嵌脚本树,Miniscript 表达式作为树节点即可。
Q2:我是不是必须学 Rust 才能用 Miniscript?
A:不必。官方提供在线编译器、Python 绑定和 bdk-cli,一行命令即可输出描述符。
Q3:多签会不会让手续费翻倍?
A:相比单签名确实会多一些字节,但 Miniscript 编译会自动选择最小体积方案;同时 SegWit & Taproot 已对多签给予显著折扣。
Q4:描述符里的 xpub 泄露会不会有风险?
A:xpub 只能查看余额与收币,无法花费。为了隐私也可选用 hardened 路径或带 @ 的私有描述符。
Q5:我能直接把现有钱包转成描述符格式吗?
A:Bitcoin Core 0.21+ 已支持 CLI 命令 migratewallet,一键升级并保留历史地址。
Q6:它与以太坊智能合约有何不同?
A:比特币脚本无状态、无循环,天然适合高确定性的金融合约(托管、锁仓、支付通道),而无需担心停机问题。
从“能用”到“好用”:为什么现在就该关注
- 交易所 & 托管:利用描述符可实现冷热多签分层,夺回自控权。
- 企业财务:一键生成 2-of-3 或 3-of-5,搭配硬件签名机,灾备零单点故障。
- 普通用户:备份只需一条字符串,换手机、换桌面钱包,恢复无需找客服。
比特币不再只是转账,而是一套可组合的金融乐高。掌握 Miniscript + 描述符,你既能节省手续费,又能布署高度安全的钱包逻辑。👇 现在就动手,体验用一句话生成百万美元级别的保险库。