亚洲财经

搜索

《链上世界的形成(六)|比特币怎样运行:UTXO、交易、区块、节点与钱包》

《链上世界的形成(六)|比特币怎样运行:UTXO、交易、区块、节点与钱包》

2009 年 1 月,比特币主网高度 170 的区块里出现了一笔很适合拆解的交易。

它只有一个输入,却创建了两个输出:输入引用此前留下的一笔 50 BTC 输出;新交易把 10 BTC 写进一条新的花费条件,把剩下的 40 BTC 写进另一条条件。输入与输出金额相等,因此这笔早期交易的手续费为零。〔1〕

如果把比特币理解成银行账户之间改余额,这个结构会显得很奇怪。

为什么不是从甲账户减 10,再给乙账户加 10?为什么必须把原来的 50 整块用掉,再创建 10 和 40 两个新对象?

因为比特币的基础状态不是账户余额表,而是一组尚未被花费的交易输出。

钱包负责组合这些输出,节点负责检查交易,mempool 只是各节点自己的临时集合,区块则把其中一批交易写进一条仍可能发生重组的历史。屏幕上的“余额”,是钱包在这些底层对象之上计算出来的视图。

一、UTXO 不是账户余额

UTXO 是 unspent transaction output 的缩写,中文通常译作“未花费交易输出”。

一笔交易创建输出。只要它还没有被后续有效交易消费,它就是 UTXO;一旦被成功消费,它就从当前可用状态中移除。

每个输出至少包含两类信息:

  • 一笔以聪为单位的数值;
  • 一段规定怎样才能花费它的脚本条件。

节点不需要维护“某地址余额为多少”这一条全局账户记录。它维护的是哪些输出仍可用,以及每个输出的金额和花费条件。形式化研究和 Bitcoin Core 的 UTXO 实现都以输出是否存在于当前状态为核心。〔2〕

UTXO 有点像现金,但不是纸币。

纸币有固定面额和物理载体;UTXO 是账本里的数字对象,可以是任意协议允许的金额,还能附带单一公钥、多签、时间条件、哈希条件或 Taproot 路径。

节点识别一个 UTXO 时,使用的是“创建它的交易 ID + 输出索引”这组坐标。

高度 170 的交易正好展示了“整块消费”:旧 50 BTC 输出不能在原对象上减去 10、留下 40。新交易必须消费整个旧输出,再创建 10 与 40 两个新输出。

高度170的交易消费一个50 BTC旧输出,并创建10 BTC与40 BTC两个新输出;旧输出整体失效,新输出分别进入UTXO集合

图 1|高度 170 交易的 UTXO 变化。输入引用旧输出,不是在账户上扣款;旧 50 BTC 输出被整体消费,10 BTC 与 40 BTC 成为两个新的可花费对象。本文依据原始区块数据绘制。

10 BTC 通常被解释为支付,40 BTC 通常被解释为找零。

但“找零”不是共识数据自带的标签。它需要钱包构造记录或外部证据才能确认;只靠链上启发式推断,可能判断错误。

二、交易与钱包:从旧输出到新状态

一笔普通比特币交易主要由版本、输入、输出和锁定时间等字段组成。〔3〕

输入告诉节点:“我准备消费哪些旧输出。”

输出告诉节点:“如果这笔交易有效,接下来创建哪些金额与花费条件。”

交易里没有一个系统能够理解的自然语言字段,写着“这是货款”“这是借款”或“这是找零”。

输入也不直接保存被花费金额。节点必须沿着前一交易 ID 与输出索引找到旧输出,取得其金额和脚本,再确认它当前仍未被消费。

这解释了为什么下面三句话完全不同:

  • 交易字节可以解析;
  • 签名或脚本条件成立;
  • 交易在完整区块上下文中有效。

一串字节可以格式正确,却引用不存在的输出;可以引用真实 UTXO,却提供错误签名;也可能满足共识规则,却不符合某个节点当前愿意放入 mempool 的本地政策。

金额守恒也不是“输出必须等于输入”。输入总额不能小于输出总额;两者的差额就是手续费。手续费不是某个特殊输出,而是区块生产者可以在合法 coinbase 奖励中领取的差额。〔4〕

高度 170 的例子中,50 正好拆成 10 与 40,所以差额为零。

钱包做的远不止“保管余额”

用户输入收款信息和金额后,钱包通常会完成四项工作。

第一,选择 UTXO。

支付 0.6 BTC,可以消费一个 0.7 BTC 输出,也可以组合多个更小的输出。选币会影响手续费、隐私、找零和以后还能怎样花费,但共识不会规定唯一选法。

第二,创建收款与找零输出。

找零通常回到钱包控制的新脚本,但链上没有通用的“找零”标记。

第三,生成满足花费条件所需的签名、见证或 scriptSig

签名只能证明:在特定哈希、脚本规则和上下文下,某种签名能力被用于这次花费。

它不能自动证明按键的是哪位自然人,不能证明组织内部授权有效,也不能证明签名者在法律上拥有资产。密码学控制、现实身份、组织授权与法律所有权必须分开。〔5〕

第四,把交易交给节点。

节点可能就在用户设备上,也可能属于钱包服务商。所谓钱包余额,是钱包根据描述符、密钥范围、已识别脚本、确认深度和节点状态算出来的结果。

Output Script Descriptor(输出脚本描述符)可以更明确地描述钱包要观察哪些脚本、怎样派生密钥,但描述符依然不是现实身份或法律权属证明。〔6〕

所以,钱包不是链上的账户对象。

它更像一组密钥与脚本观察规则,加上一套选币、构造交易和解释状态的软件。

三、节点面对的是三套不同问题

钱包交出交易以后,“节点是否接受”仍不是一个总开关。

1. 共识验证

共识验证问:如果把交易放进某个候选区块,在给定父区块、UTXO 状态和激活规则下,它能否成为有效历史的一部分?

节点需要检查格式、金额范围、输入是否存在且未花费、脚本或见证是否成功,以及区块级限制。

缺少父状态时,不能只验证一枚签名就宣布“交易有效”。

2. 本地 Policy

Policy 问:即使这笔交易可能被合法写入区块,本节点现在是否愿意把它放进自己的 mempool,并转发给同伴?

标准性、最低费率、未确认祖先和后代结构、替换规则、节点版本与配置,都可能影响答案。

Policy 可以变化,它不是全网共识规则。Bitcoin Core 也把标准性、mempool 接纳和完整区块验证放在不同代码路径中。〔7〕

3. 钱包视图

钱包视图问:当前钱包是否把某些输出认作自己的,交易显示为待确认、已确认、冲突还是已被重组移出,以及这些状态怎样进入余额。

这三套问题不能互相替代。

本地 mempool 接受,不等于已经确认;某节点 policy 拒绝,不等于违反共识;进入区块,也不证明所有钱包已经同步到同一状态。

钱包构造、节点共识检查、本地policy与mempool、点对点传播、区块确认和钱包显示依次分层;每层之间都标有“不能自动推出”

图 2|一笔交易穿过的是多层状态,而不是一个“成功/失败”开关。钱包构造不保证节点接纳,mempool 接纳不保证传播或确认,确认也不保证绝对不可逆。本文绘制。

三列分别展示共识规则、本地policy与钱包视图:共识决定区块能否有效,policy决定本地mempool和relay,钱包决定脚本归属与显示;箭头显示三者有关但不等价

图 3|共识、policy 与钱包视图是三套不同判断。最常见的误读,是用本地 mempool 结果替代完整共识验证,或把钱包标签当成链上身份事实。本文绘制。

四、Mempool 不是全网共享的候车室

Mempool 是节点暂存未确认交易的本地数据结构。

“候车室”这个比喻很直观,却容易让人误以为所有节点看见同一队列。

实际上,甲节点可能已经收到一笔交易;乙节点尚未收到;丙节点可能因为费率或结构限制拒绝它;丁节点则保留着与它冲突的另一笔交易。

BIP 35 允许同伴请求某节点的 mempool 清单,BIP 133 允许节点根据费率向特定同伴过滤交易通告。这些协议本身就说明,“某节点知道”不能改写成“全网都有”。节点 churn 研究也观察到节点间交易集合可能不同,但具体程度受时期、版本和测量方法限制。〔8〕

传播通常也不是把完整交易无条件推给所有人。

节点可以先通告交易标识,同伴再按需请求数据;现代节点还可能协商用 wtxid 通告 SegWit 交易。连接拓扑、费率过滤、重启、带宽和本地 policy 都会影响传播。白皮书所说的 best-effort broadcast,重点同样是消息不必同时抵达所有节点。〔9〕

因此,看见一笔零确认交易,只能说明某条传播路径已经把它带到当前观察点。

它可能尚未到达任何区块生产者,也可能与另一笔交易冲突,或者在替换、重启和 policy 变化后离开本地 mempool。

五、区块提交的是一批交易,不是永久印章

区块把一批交易放进共同上下文。

传统交易 ID 经 Merkle 树汇总成 Merkle 根,根进入区块头;区块头还包含前一区块哈希、时间字段、难度目标编码和 nonce 等信息。

改变交易集合,通常会改变 Merkle 根,进而改变区块头与区块哈希。

SegWit 又增加了见证承诺。

txid 不包含见证序列化部分;wtxid 覆盖包含见证的完整序列化。传统 Merkle 根使用 txid,见证数据则通过 coinbase 中的 witness commitment 进入区块承诺。〔10〕

交易基础序列化产生txid,含见证序列化产生wtxid;txid汇入Merkle根,wtxid汇入见证承诺,Merkle根和前块哈希进入区块头

图 4|交易标识与区块承诺。SegWit 后,txidwtxid、传统 Merkle 根和 witness commitment 各自覆盖不同字节域;“哈希相同或不同”必须先说明计算对象。本文绘制。

节点收到区块后,也不会因为工作量证明正确就跳过交易验证。

它仍要在父区块状态上应用交易,确认输入存在、没有被重复消费、脚本通过、金额和区块级规则成立。有效区块把旧 UTXO 移出集合,把新输出加入集合。

这才是交易从“候选”进入某条有效分支的关键一步。

六、确认不是绝对最终性

钱包通常把交易所在区块称为第一次确认;后面每增加一个区块,确认数再加一。

它表达的是交易在当前最佳链中被后续工作覆盖了多深,不是中央结算机构发出的不可撤销证书。

如果节点后来看到累计工作量更大的有效分支,就可能切换过去。

原分支中的交易可能也存在于新分支,可能重新回到 mempool,也可能因为与新分支交易冲突而失去确认状态。白皮书在网络步骤中已经描述了并行分支与后续切换;Bitcoin Core 的钱包和 mempool 也要处理断开区块后的交易恢复与冲突。〔11〕

所以,“六次确认”是常见风险惯例,不是适用于所有金额、攻击者和业务场景的法律最终性常数。

确认越深,竞争性改写通常越困难;应该等多久,还取决于交易价值、攻击动机、当前链状态、风险承受能力和链外补救机制。

七、升级没有取消 UTXO,角色也没有合并

从早期公钥脚本到 P2SH、SegWit,再到 Taproot,比特币的交易编码和花费条件不断变化。

SegWit 把见证数据移入独立结构,引入 wtxid 与见证承诺;Taproot 允许输出承诺一个聚合公钥和可选脚本树,花费时可以走 key path,也可以走 script path。〔12〕

但它们没有把比特币改成账户系统。

Taproot 输出仍然是带金额与花费条件的交易输出;花费它仍要引用旧 outpoint,创建新输出,并由节点按相应规则验证。

也不能只看地址前缀判断实际花费路径。P2SH 可能包裹 SegWit;Taproot 输出可能走 key path,也可能揭示 script path。准确分类要看被花费输出的脚本和实际输入见证。

谁验证,谁控制,谁能补救

一笔交易背后至少有五类角色:

  • 钱包使用者与钱包软件:选币、构造输出、调用签名能力;
  • 验证节点:依据本地软件和当前链状态检查交易与区块;
  • 对等节点:决定连接谁、通告和请求哪些对象;
  • 区块生产者:选择候选交易、排序并提出区块;
  • 浏览器、远程节点、托管钱包和交易所:替用户提供可见性与便利,也可能重新集中操作权。

这些角色可以由同一主体兼任,也可以分散在不同主体手中。

运行自己的钱包与全节点,可以减少对他人“告诉你规则和历史”的依赖;但它不会自动解决设备安全、现实身份、交易对手风险和法律救济。

密钥泄露、误付或诈骗发生时,协议层有效不等于现实争议已经解决。软件没有一个全网客服按钮,可以把已经按规则确认的交易撤销。追索、赔偿与协商属于另一套制度。

高度 170 的交易最终给出的,不是“甲账户向乙账户转了 10 BTC”这句简单故事。

底层发生的是:一个 50 BTC 输出被引用并满足花费条件,旧状态被消费,10 与 40 两个新状态被创建;节点在特定历史和规则下验证它,区块把它纳入工作量链,钱包与后来研究者再为这些字节赋予支付、找零和参与者关系的解释。

理解这条路径之后,下一篇的问题才真正出现:既然交易和区块要由不同节点验证并竞争写入,为什么有人愿意付出算力和能源?难度、区块奖励、减半与手续费,又怎样共同构成比特币的经济安全?

本章要点

  • 比特币的基础状态是 UTXO 集合,不是账户余额表。
  • 交易消费完整旧输出,再创建一个或多个新输出;输入减输出的差额是手续费。
  • 钱包负责选币、找零、签名与显示,但钱包标签不是链上身份。
  • 共识验证、本地 policy 和钱包视图是三套不同判断。
  • Mempool 属于单个节点,不是全网共享队列。
  • txidwtxid、Merkle 根与 witness commitment 覆盖不同字节域。
  • 确认积累置信度,但不构成绝对或法律最终性。
  • SegWit 与 Taproot 改变编码与花费条件,没有取消 UTXO 状态模型。

参考资料与外链

〔1〕Bitcoin mainnet block 170,block id 00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee,Blockstream raw block,Blockchain.com hex;其输入引用的 50 BTC 前序输出见 Blockstream transaction endpoint(访问日期:2026-08-24)。

〔2〕Nicola Atzei et al., “A Formal Model of Bitcoin Transactions,” Financial Cryptography and Data Security, 2018,DOI;Bitcoin Core contributors, src/coins.h and src/coins.cpp, v31.1,source tree(访问日期:2026-08-24)。

〔3〕Bitcoin Core contributors, src/primitives/transaction.h and transaction.cpp, v31.1,transaction.h,transaction.cpp(访问日期:2026-08-24)。

〔4〕Satoshi Nakamoto, “Bitcoin: A Peer-to-Peer Electronic Cash System,” 2008, §§6, 9,PDF(访问日期:2026-08-24)。

〔5〕Satoshi Nakamoto, “Bitcoin,” §2;Marwah Alhabardi et al., “Verification of Bitcoin Script in Agda Using Weakest Preconditions,” 2022,DOI(访问日期:2026-08-24)。

〔6〕Andrew Chow, “BIP 380: Output Script Descriptors General Operation,” versioned BIP;Bitcoin Core contributors, “Output Script Descriptors,” v31.1,documentation(访问日期:2026-08-24)。

〔7〕Bitcoin Core contributors, v31.1, policy.cpp, validation.cpp, mempool RPC(访问日期:2026-08-24)。

〔8〕Jeff Garzik, “BIP 35: mempool message,” BIP;Alex Morcos, “BIP 133: feefilter message,” BIP;Muhammad Anas Imtiaz et al., “Improving Bitcoin Resilience to Churn,” 2021,DOI(访问日期:2026-08-24)。

〔9〕Satoshi Nakamoto, “Bitcoin,” §5;Gleb Naumenko and Pieter Wuille, “BIP 339: WTXID-based transaction relay,” BIP;Bitcoin Core contributors, net_processing.cpp(访问日期:2026-08-24)。

〔10〕Eric Lombrozo, Johnson Lau, and Pieter Wuille, “BIP 141: Segregated Witness,” versioned BIP;Bitcoin Core contributors, merkle.cpp(访问日期:2026-08-24)。

〔11〕Satoshi Nakamoto, “Bitcoin,” §5;Bitcoin Core contributors, mempool_reorg.py and wallet_reorgsrestore.py, v31.1,functional tests(访问日期:2026-08-24)。

〔12〕BIP 141;Pieter Wuille, Jonas Nick, and Anthony Towns, “BIP 341: Taproot,” versioned BIP;Pieter Wuille, “BIP 342: Tapscript,” versioned BIP(访问日期:2026-08-24)。