Taproot 第1部分:生成 P2TR KeyPath Witness 程序 🚀
Source: Dev.to
欢迎回来,亲爱的读者们!如果你看到这里,说明你已经顺利完成了环境搭建,准备好动手玩点真正的比特币内部魔法了。
在我的上一篇日志中,我们已经把 Signet 节点启动、运行,并且为 BOSS(Bitcoin Open Source Software)挑战 暗中“伪装”。现在,是时候迎接第一个真正的考验了:Challenge 1 – Recover Wallet State。
任务是什么?手动扫描区块链来计算你的钱包余额。难点在哪里?评估环境中已 禁用 Bitcoin Core 钱包。没有 getbalance,也没有任何捷径。只有你、你的代码和原始区块。出发吧! ⚡️
🛠 步骤 0:“合理性检查”(CLI)
在我们开始自动化之前,需要一个“北极星”来确保我们没有在追逐幻影。我们将使用 Bitcoin CLI 查看我们的余额 应该 是多少。这是你的基准!
1. 创建本地钱包
docker exec bitcoin_signet bitcoin-cli -signet -datadir=/home/bitcoin/.bitcoin \
createwallet "boss" false false "" false true true
2. 导入该描述符
docker exec bitcoin_signet bitcoin-cli -signet -datadir=/home/bitcoin/.bitcoin \
-rpcwallet=boss importdescriptors '[{ "desc": "tr(tprv8ZgxMBicQKsPfCkDmSmHXuKAVA8zwwXLWTHEgyyisMioZ8gn3nTmmNwUzBMKWnNMkhRYN3E9qVCZrZ6MC645cqYdpy9jTYHhBwG1KhpNAMd/86h/1h/0h/0/*)#hjz07900", "timestamp": 0, "active": true }]'
3. 查看结果
docker exec bitcoin_signet bitcoin-cli -signet -datadir=/home/bitcoin/.bitcoin \
-rpcwallet=boss getwalletinfo
如果你看到余额,轰!💥 现在你已经知道要达到的数值了。让我们手动编写代码来找到它。
🧬 深入探讨:P2TR 推导
要找到我们的币,需要 Witness Program。在 Taproot(BIP 341)的世界里,地址是由“调校”(tweaked)后的公钥派生的。即使我们只使用 Key Path(不涉及复杂脚本),也必须对脚本路径进行一次提交。
“黄金”基准脚本
我们使用 bitcoinjs-lib 和 tiny-secp256k1 来处理繁重的椭圆曲线运算。
重要提示: 你 不能 在最终提交中使用此 JavaScript 程序!BOSS 挑战严格要求使用 Python、C、C++ 或 Rust。仅将此 JS 脚本用作 基准,用来验证你的逻辑。如果你的 Python/Rust 代码生成的字符串与此脚本相同,说明你走在正确的道路上!
import { BIP32Factory } from "bip32";
import ECPairFactory from "ecpair";
import * as ecc from "tiny-secp256k1";
import * as bitcoin from "bitcoinjs-lib";
import fs from "fs";
// Initialize the ECC library—Taproot needs this!
bitcoin.initEccLib(ecc);
export const bip32 = BIP32Factory(ecc);
export const ECPair = ECPairFactory(ecc);
const net = bitcoin.networks.testnet;
const xpriv = bip32.fromBase58(
"tprv8ZgxMBicQKsPfF4wki3EzsSYvohmC5z2B92m74LscyiFAHwZUtn4Lhbfosc1zCQRzN4aXiPqiH64xbTbsnRCgTskJWspELwAYSdyZSekqyp",
net,
);
// Derive the path from the descriptor: m/86'/1'/0'/0
const derived = xpriv.derivePath("m/86'/1'/0'/0");
const addresses = [];
const internals = [];
const witnesses = [];
console.log("🚀 Starting derivation for 2000 keys...");
for (let i = 0; i < 2000; i++) {
const current = derived.derive(i);
// Extract the X‑only internal pubkey (32 bytes)
const internalPubkey = current.publicKey.slice(1, 33);
// Generate the P2TR payment—bitcoinjs handles the TapTweak automatically!
const { address, pubkey } = bitcoin.payments.p2tr({
internalPubkey,
network: net,
});
addresses.push(address);
witnesses.push(pubkey?.toHex()); // This is your Witness Program!
internals.push(internalPubkey.toHex());
}
// Write to files so you can 'diff' against your main submission code
fs.writeFileSync("addresses.json", JSON.stringify(addresses, null, 2));
fs.writeFileSync("witnesses.json", JSON.stringify(witnesses, null, 2));
fs.writeFileSync("internals.json", JSON.stringify(internals, null, 2));
console.log("✅ Done! Check your JSON files and compare them with your challenge code.");
🎯 为什么这是你的秘密武器
BOSS 挑战要求你:
- 推导 2000 个密钥。
- 为每个密钥计算 P2TR 见证程序。
- 扫描 Signet 链的前 300 个区块。
Witness Program(上面脚本中的 pubkey)是你将在链上交易输出的 scriptPubKey 中寻找的实际十六进制字符串。使用此 JS 基准测试可以帮助你将推导错误与扫描错误分离。
⏭ 接下来是什么?
现在你已经在 witnesses.json 中拥有了 2000 条见证程序的列表,是时候去搜寻了!获取区块,遍历交易,并开始统计余额。
你是用 Rust 还是 Python 来攻克这个挑战的?在下方留言,让我们一起聊聊 TapTweak 数学! 🚀🔥