
读《精通比特币》第3版读到第6章交易这一章才真正摸到了比特币的内核。前面几章讲的密钥、地址、钱包本质上都是在为交易做铺垫——地址是交易的收件箱私钥是交易的签名笔而交易本身才是比特币账本上唯一可写入的数据。我见过不少朋友跳过这一章直接去查区块浏览器后来做链上量化分析时才发现连找零和真实转账都分不清统计口径自然一团糟。这一章最厉害的地方是用极其扎实的细节把交易的整个生命周期、内部结构、脚本和手续费机制讲透了。读完这一章你至少能回答三件事一笔交易从构想到上链经历了什么交易里的输入输出为什么不能理解成账户转账手续费到底是怎么算出来的。无论你是做钱包开发、节点运维还是时下很多人关注的比特币量化这章都是绕不过去的地基。接下来我按自己的阅读节奏把这章的核心拆开讲一遍顺便聊一些实际操作中容易踩的坑。1. 交易章节为什么是整本书的枢纽1.1 区块只是容器交易才是血液很多人看比特币第一反应是看区块好像区块链就是一长串块。但打开一个区块看里面装的其实就是一组交易。所谓账本并没有一张账户表这个地址有多少钱指的是这个地址在历史交易输出中能支配多少UTXO。所以交易才是比特币真正流通的血液矿工打包区块本质也是在从内存池里挑选合法交易。我自己早期做开发时一直以为钱包余额是节点帮忙维护的账户数据后来才发现钱包只是扫描属于自己的UTXO把金额加起来汇总。这个理解在第6章里讲得非常清楚属于看完整章才会彻底转过来的弯。1.2 承上启下的位置第6章正好夹在密钥、钱包和脚本、共识之间。拿它和第4章连起来看你会理解地址背后其实是一把锁定脚本拿它和第7章连起来看你会发现标准脚本只是抛砖引玉现代脚本体系要复杂得多拿它和第10章连起来看交易的规则就是共识的一部分改变交易结构就等于改变共识。所以这一章不读透后面每一章都会觉得缺了一块。做比特币量化也是同理。你在交易所或链上拉到的每一行K线、每一笔成交最终源头都是链上交易。如果不理解交易的结构、字段语义和确认边界你在跑统计模型时很容易把已经被RBF替换掉的旧交易也当成实际转账或者把找零地址当成活跃用户。这个道理第6章读完之后自然就明白了。2. 交易生命周期一笔钱是怎么走起来的2.1 构造交易的三个基本动作一笔交易不是凭空产生的它通常由钱包完成三个动作。第一步是选择UTXO作为输入。钱包会扫一遍自己控制的UTXO集合挑出金额足够的若干UTXO凑出需要花费的总额加手续费。第二步是构建输出。给收款地址指定一个金额给自己找零地址写回剩余的金额多出来的差额就是手续费。第三步是签名。对交易内容做哈希摘要用私钥签上然后把解锁数据和交易一起组装起来。这里要注意一个看似反直觉的点一笔交易有多个输入时所有输入都必须签名解锁。如果其中一个输入的脚本验证失败整个交易就是非法的。就像你花钱时不可能拿一张真钞配一张假钞交易是整体有效或整体无效的。2.2 广播、内存池和确认构造好的交易要广播给节点。节点收到后第一件事是验证结构、签名、引用的UTXO是否未被花费。验证通过就放进本地内存池同时继续转发给相邻节点。此时交易是0确认状态。矿工从内存池里挑交易打包成候选区块挖出后广播新区块这笔交易才算获得第1个确认。每个新区块加在它上面确认数就加一。需要特别注意的是内存池是节点本地的不同节点的内存池内容可能不一样。你在一台机器上看到一个待确认交易另一台机器可能根本不知道它。这也是为什么一些基础设施服务商会维护全网的内存池快照做量化分析时不能把本地内存池里有多少笔交易当作全局事实。2.3 双重支付怎么被拦住双重支付说白了就是同一笔钱想花两次。由于每笔输入必须引用特定的一笔未花费输出一旦某个UTXO被某笔交易引用其他合法交易就不能再引用它。第一个进入内存池的交易会被节点接受第二个引用同一UTXO的交易会被当成冲突交易拒绝除非第一笔被RBF替换或超时过期。最终矿工打包时也只能选其中一个另一笔会被丢出内存池。这个机制跟现金完全不同。现金是同一张钞票可以反复花UTXO模式是一张票撕掉就没了。你花0.3 BTC时钱包会把一个0.5 BTC的UTXO整个花掉拆成0.3给收款方、0.2找回自己。这种整进整出的模式如果不精读第6章一开始真不容易拐过弯来。3. 解剖交易结构输入输出是怎么组织的3.1 一张完整的交易字段表交易数据可以看成几个连续拼接的字段。最前面是版本号然后是输入数量、输入列表、输出数量、输出列表最后是锁定时间。网上很多资料喜欢画大图其实用一张表看更清晰字段长度作用version4字节版本号当前普遍为2input count1或更多字节输入数量用可变长整数编码inputs不定每个输入包含txid、vout、scriptSig、sequenceoutput count1或更多字节输出数量outputs不定每个输出包含金额、锁定脚本locktime4字节最早可被打包的区块高度或时间每个输入里txid占32字节vout占4字节解锁脚本是变长的sequence占4字节。输出则是8字节金额加变长锁定脚本。所以交易体积大多被输入引用和脚本占掉。搞清楚这个表后面解析原始交易数据时就不会发怵。3.2 UTXO概念再展开UTXO全称是Unspent Transaction Output未花费交易输出。你可以把它想成一张张记录在链上的支票。某笔交易给地址A写了一张0.5 BTC的支票这笔钱的记录就是那个输出的金额和锁定脚本。地址A要花这笔钱就是出示这张支票并在背面签名然后把整张支票拆成新面额写给别人。全节点维护的UTXO集合就是所有还没被花掉的输出。比特币的账本本质不是地址余额列表而是这个集合。区块浏览器显示的地址余额是程序扫出该地址相关UTXO后加总的结果。这个区别极其关键做量化的人如果直接拿地址余额变化来推资金流向会发现对不上账原因就在这里。3.3 关于交易ID的字节序问题交易ID是交易数据的double-SHA256哈希但呈现的时候有个坑区块浏览器和RPC里显示的txid是原始哈希字节反转后的结果所以看起来跟你在代码里自己算出的哈希是反的。这个反转约定来自比特币特定的序列化格式。很多人第一次对着区块数据做校验时都卡在这里。读这一章时我建议你直接拿一笔真实交易手工算一遍sha256d再把字节逆序跟浏览器的txid对比。亲自动手做一次比看十遍文档都管用。想验证自己算得对不对也可以去区块浏览器找一个交易把它的hex拉下来自己hash一下。3.4 SegWit带来的ID变化隔离见证之后交易有了两个ID不含见证数据的txid和包含全部见证数据的wtxid。前者不随签名变化解决了早期交易延展性问题。你看到一笔交易的txid不变但witness变了不代表交易数据没变只是txid故意不涵盖这部分。对做底层开发的人来说区分txid和wtxid是必修课。另外SegWit交易在序列化去掉了scriptSig签名挪到见证数据里。这个设计的直接收益是交易体积减少因为见证数据在区块里按四分之一权重计费。后续我们聊手续费率时会再碰这个点。4. 输出脚本决定谁有权动用这笔钱4.1 用密码锁来理解脚本每笔交易输出里有一段锁定脚本相当于给硬币上了一把密码锁。要想花这笔钱输入里必须提供对应的钥匙也就是解锁脚本或见证数据。比特币脚本执行时先把解锁脚本压入栈再执行锁定脚本最后看栈顶是否为真。返回真就能花这笔钱返回假就无效。脚本语言不图灵完备没有循环和跳转是为了保证任何一笔交易的验证都能快速终止。你可以把脚本想象成自动售货机的投币流程按键是固定的但你把不同操作码组合起来可以做出多重签名、时间锁、条件支付等复杂收款条件。第7章会展开讲高级脚本第6章只需要理解这个锁和钥匙模型就够了。4.2 常见标准输出类型对比目前常见的标准输出类型不止五种我整理了一份更完整的对照类型地址形态锁定内容解锁条件P2PK早期1开头公钥对应私钥签名P2PKH1开头公钥哈希签名加公钥P2SH3开头脚本哈希签名加赎回脚本P2WPKHbc1q公钥哈希签名加公钥见证数据中P2WSHbc1q脚本哈希签名加赎回脚本见证数据中P2TRbc1p公钥TaprootSchnorr签名从P2PKH到P2SH再到SegWit和Taproot本质上是不断把验证逻辑从明文脚本中抽象出去同时把空间从区块数据中省出来。哈希锁定让输入方不需要暴露完整脚本Taproot又进一步让复杂条件看起来和普通支付一样。对照第4章的地址知识把这两章合并起来看最有效。4.3 Taproot与输出描述符第3版花了很大篇幅讲Taproot。P2TR的优势在于无论你是单个签名还是复杂的多签、时间锁脚本链上看到的都只是一个公钥和一把Schnorr签名外部没人能分辨你的实际收款条件。这个隐私提升和交易体积的节省是同步的Taproot还支持批量签名聚合多签场景下能显著降低手续费。配套出现的还有输出描述符。以前钱包备份恢复靠扫地址但地址类型五花八门不同钱包对脚本表述不统一。描述符用一串文本把类型、路径、公钥或密钥信息完整描述出来比如pkh、wpkh、tr这些前缀再配合BIP32派生路径跨钱包迁移就稳了。第6章虽然讲交易但书中会把描述符和交易脚本串起来理解了描述符再看现代钱包代码会轻松很多。5. 手续费那些事如何让交易被更快确认5.1 手续费的本质是差值比特币交易里没有专门的手续费字段。手续费就是输入总额减去输出总额的差值。钱包选择输入时会把想付的金额加上期望的手续费一起凑数。比如输入一个0.5 BTC的UTXO输出0.3 BTC给收款人、0.1999 BTC找零回自己那0.0001 BTC就是手续费等于10000聪。在交易数据里你看不到fee xxx这样的字段只能自己减出来。这个设计很巧妙矿工不需要信任钱包报了多少钱直接从输入输出总量就能推导手续费。也正因为手续费是差值构造交易时如果不留差值交易会被节点当作输出超过输入而拒绝。有些钱包报错说交易金额无效其实根因就是手续费没留够。5.2 手续费率的计算矿工排序不是按手续费总额排而是按每vB的费率排。SegWit引入了vBytes概念把witness部分按四分之一权重计入体积。所以同样一笔交易SegWit版本比普通版本更便宜这就是为什么现在钱包普遍优先走P2WPKH或P2TR。举个例子一笔输入2 BTC、输出1.9995 BTC的交易手续费是0.0005 BTC即50000聪。如果交易的vsize是250 vB费率就是200 sat/vB。矿工优先打包费率高的交易当内存池拥堵时费率低的交易可能几小时甚至几天都出不去。这个位次竞争每天在内存池里反复上演研究它本身就是很有意思的微观经济学样本。5.3 手续费太低卡住了怎么办如果一笔未确认交易因费率过低卡在内存池有两个常见补救思路。RBF是用更高费率的同类型交易替换原来的交易前提是钱包在构造交易时把sequence设成可替换值。CPFP则是花掉那笔卡住交易的某个输出发起一笔新交易用子交易的高费率吸引矿工把父子交易一起打包。这两个机制在书里都有涉及但我真正想强调的是产品层面的教训钱包如果没在构造交易前给用户留好可升级费率的选项一旦网络拥堵用户就只能干等。等久了用户就会跑掉。手续费设计不只是技术问题更是产品体验的第一道门。6. 链上量化视角交易数据究竟能告诉我们什么6.1 常见的链上观测指标比特币量化这个领域很多人只盯着价格数据其实链上数据也是重要输入。比如活跃地址数、交易笔数、手续费总量、大额UTXO移动、UTXO年龄分布本质上都是对交易数据的聚合统计。一笔交易从广播到被打包的时间差也能刻画网络拥堵程度。手续费总额是我觉得最被低估的指标。它同时包含了交易数量和网络规模的信息手续费总额快速抬升时通常意味着网络活跃度在升高。UTXO年龄分布则能反映长期持有者是否在移动币——如果大量五年以上的老UTXO开始频繁出现链上分析师就会重点关注。这些都是第6章交易知识直接延伸出来的应用。6.2 量化建模前必须先处理好三个口径问题第一找零和真实转移要分开。找零地址往往有规律比如金额结构固定、脚本类型单一、极少被再花。如果不做找零识别统计的净转账量会明显偏大。第二交易所地址要打标签。很多数据服务商提供地址标签但自己最好也设一套规则否则无法区分交易所内部转账和真实的用户提取。第三未确认交易与重组问题。链上数据不是一成不变的节点同步时间差、短分叉、重组都会造成短期视图不一致所以数据快照的时间点必须固定。这些算法本身不复杂难点在于对交易结构底层的理解。理解了交易的输入输出、找零逻辑和确认机制才知道哪些字段可信哪些字段需要二次加工。6.3 量化特征构造的一点实操思路从交易数据构造特征因子时我习惯分三层。第一层是绝对量比如交易笔数、活跃地址数、手续费总量。第二层是比率比如某个年龄带UTXO的消费占比、大额转账笔数占比。第三层是交叉信号比如价格走势与链上活跃度的偏离。每一层建立之前都要先跑一遍数据清洗。这里不讨论买卖方向只强调一点特征算得准不准首先取决于你对交易原始数据有没有吃透。很多人上来就用第三方API拉现成指标结果不同的API口径还不一样最后只能一个一个对齐。与其这样不如先把第6章的数据结构学扎实自己写清洗脚本才能对数据质量有底。7. 精读实操这些方法让第6章真正变成自己的7.1 起一个regtest本地环境光看书不实操交易结构永远是抽象的。我建议搭一个regtest环境用Bitcoin Core的RPC接口自己走一遍完整流程bitcoind -regtest -daemon bitcoin-cli -regtest createwallet test bitcoin-cli -regtest getnewaddress alice bitcoin-cli -regtest generatetoaddress alice 101先用generatetoaddress挖出101个区块获得币再用getnewaddress生成收款地址调用sendtoaddress发起转账最后再用generatetoaddress打包一个区块让交易被确认。整个过程不到五分钟但对交易如何产生、如何确认会有非常直观的感受。regtest的好处是出块秒级想怎么折腾都行。7.2 用RPC解剖一笔交易有了交易就能用getrawtransaction拿到原始hex再用decoderawtransaction解析字段bitcoin-cli -regtest getrawtransaction txid bitcoin-cli -regtest decoderawtransaction hex把输出里的vin、vout逐字段对照第6章看一遍再手动算一下输入总额减输出总额你会第一次真切理解手续费是差值。如果想再深入一步可以手动构造一笔裸交易指定输入脚本、签名后再广播。那个过程比点钱包按钮要深刻得多做完一次transaction结构基本就刻进脑子里了。7.3 对照源码加深理解第6章讲到的很多细节在Bitcoin Core源码里有清晰对应。脚本执行逻辑看interpreter.cpp里的EvalScript交易合法性检查看validation.cpp里的CheckTransaction交易数据结构看primitives/transaction.h里的CTransaction。不要求全都看懂关键是在读到一个概念时能去源码里找到一个位置锚定下来。我自己的经验是很多东西只看书容易忘但如果你能在regtest上亲手把一笔交易从构造、广播到打包走一遍半年后再回来这些字段的名字和含义都会记得很牢。再遇到钱包报错或者链上数据对不上你会比身边人多一种排查问题的直觉。8. 常见误区与问题排查速查8.1 常见问题速查表整理了几个做开发和分析时最容易遇上的问题一张表说清现象典型原因解决思路交易长时间0确认手续费率过低、网络拥堵等待或启用RBF/CPFP提高费率钱包余额和浏览器对不上UTXO扫描范围不全、描述符缺失重新扫描所有脚本类型和派生路径手动构造交易总验证失败签名hash类型不对、脚本类型不匹配检查SIGHASH类型和脚本执行返回值txid在代码里与浏览器显示不一致字节序反转把哈希字节逆序后再比较自己做链上统计和浏览器差异大找零没识别、未确认交易统计不一致固定快照时间点、加入找零识别规则这些问题大多不是算法多难而是底层细节没吃透。排查时先从第6章的几个关键词入手UTXO、锁定脚本、sequence、字节序大多能定位到问题所在。8.2 几个容易被忽略的细节sequence字段在很多交易里就是0xFFFFFFFF很多人觉得它没意义但它和RBF、锁时都有关系。locktime字段也不总是0有些隐私钱包会故意设置它如果你做量化统计时不解析这个字段可能漏掉一类特殊交易。另外解析输入数据时要区分P2PKH和P2SH的解锁脚本P2PKH的scriptSig里直接放着公钥和签名而P2SH的scriptSig里放的是赎回脚本看长度就能分辨。还有一个很容易绕晕的细节地址本身并不存在于交易数据里交易输出中存的只是脚本。区块浏览器把脚本转成地址只是为了显示方便。你从交易数据里解析出来的地址其实是你自己把脚本哈希格式化成地址的结果。这个逻辑不搞清楚写解析程序时会被各种库搞得一头雾水。其实读到第6章之前我也觉得比特币的核心难点是密码学和共识算法。真的把这一章嚼透之后才发现日常开发中90%的疑难杂症最后都归结于对交易结构的理解不到位。无论是钱包的UTXO扫描还是链上量化里的找零识别或者是SegWit的vB计算根子都在这章里。我个人习惯是每读完一章就在regtest上把书里的例子原样跑一遍然后写下三个自己觉得最容易出错的概念。这一章我的三个关键词是UTXO是唯一状态、手续费是差值、txid和wtxid是两个东西。几年后再回忆这本书脑海里剩下的就是这些扎在实处的概念。也建议你精读时不要只画线试着用代码把每一笔交易都拆开看一次那才算真的读懂了。