基于 UTXO 的交易模型与美国使用纸币的场景相似:

  1. 每张纸币都是不可分割的整体;
  2. 使用纸币进行支付时往往都会获得找零;
  3. 需要支付小费给服务员(矿工)。
  4. 持有的未花费的纸币 = 消费的费用(转账)+ 小费(矿工费)+ 找零

账户模型和银行账户类似。

UTXO

比特币交易的核心是交易输出(transaction output)。

  • 交易输出是一份不可分割的比特币,它记录在区块链上,整个网络认可它的有效性。
    • Satoshi (SAT) 比特币的最小单位,一个 SAT 一亿分之一个比特币(0.00000001 BTC)。
    • 一个交易输出一定是 SAT 的整数倍,而且一旦创建出来,它就是不可分割的。

比特币的全节点会跟踪所有可花费的交易输出,也就是未花费交易输出(unspent transaction output,UTXO)。

  • 所有 UTXO 的集合称为 UTXO 集(UTXO set),每个全局节都会维护自己的 UTXO 集。
  • 一个 UTXO 只能作为一个整体被一个交易消费,若 UTXO 比交易值大,则交易会生成找零,交易值发给接收方,找零值发回自己的钱包,这样一来就形成了比特币的交易链。

余额的概念是钱包创建的,一个用户(地址)的比特币余额是它能花费的所有 UTXO 的总和,这些 UTXO 分散在许多交易和区块中,钱包通常用数据库记录指向账户能花费的 UTXO 的引用

  • 钱包负责组合出大于或等于交易需要的 UTXO,这一过程发生在链下。

交易输出

所有比特币交易都会创建交易输出,几乎所有的交易输出(除了 Data Recording Output (RETURN))都会创建 UTXO。

交易输出包含 2 部分:

  1. 比特币数量;

    • 单位是 Satoshi。
  2. 一个决定了花费交易输出需要满足的条件的密码学难题,称为 locking script、witness script 或 scriptPubKey

    "vout": [
        {
            "value": 0.01500000,
            "scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
            OP_EQUALVERIFY
            OP_CHECKSIG"
        },
        {
            "value": 0.08450000,
            "scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8
            OP_EQUALVERIFY OP_CHECKSIG",
        }
    ]
    
    • In the encoding shown by Bitcoin Core, the value is, shown in bitcoin, but in the transaction itself it is recorded as an integer denominated in Satoshis.

交易输入

交易输入包含 3 个部分:

  1. 指向 UTXO 的指针;

    • 由两部分组成:交易输出中包含该 UTXO 的交易的交易哈希 txid 和序列号 vout
      • 用于指示花掉 txid 这笔交易输出的第 vout 个 UTXO
  2. 一个由钱包构建的满足 UTXO 花费条件的 unlocking script(提供所有权证明);

    • 通常解锁脚本是一个数字签名(不一定包含)和公钥。
      • 被签名对象不是交易输入,而是该 UTXO 指向的交易的洁净版本这一整体,即去掉交易中包含的所有交易输入的签名部分,这样可以不用维护签名和交易输入的映射关系,方便验签。
    • 钱包通过分析 UTXO 的 locking script 创建出对应的 unlocking script。
  3. 序列号。

    "vin": [
        {
            "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18", // 包含待花费 UTXO 的交易的 ID
            "vout": 0, // 交易输出的 UTXO 的索引(此处是该交易创建出的第一个 UTXO),即待消费的 UTXO
            "scriptSig" :
            "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204
            b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL]
            0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d1
            72787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
            "sequence": 4294967295
        }
    ]
    

交易输入里没有直接包含 UTXO 的数量和 locking script,这些信息需要从对应的交易本身获取。

  • 拿到相关的交易,再去解析、汇总。

区块中的第一个交易称为 coinbase 交易,由挖到该区块的矿工放入区块,这一交易不消耗 UTXO,它的输入是一个称为 coinbase 的特殊输入,它的输出是属于矿工的 UTXO,作为挖到矿的奖励。

  • coinbase 交易创建出了新的比特币。

交易费用

大多数交易都包含交易费用。

  • 交易费用由交易的大小(kb)决定,和交易中涉及的价值大小无关。
  • 增大交易费用可以增加被加入区块的优先级。
    • 交易费用不足的交易会被延迟打包,甚至不被打包。
    • 有时不包含交易费用的交易也可能被打包进区块。
    • In Bitcoin Core, fee relay policies are set by the minrelaytxfee option. The current default minrelaytxfee is 0.00001 bitcoin or a hundredth of a millibitcoin per kilobyte. Therefore, by default, transactions with a fee less than 0.00001 bitcoin are treated as free and are only relayed if there is space in the mempool; otherwise, they are dropped. Bitcoin nodes can override the default fee relay policy by adjusting the value of minrelaytxfee.
  • 交易费用是对矿工维护网络安全的奖励,同时也是一种防止拒绝服务攻击的安全机制。
  • 大多数钱包会自动计算交易费用。
  • 表示交易的数据结构中并没有交易费用这一字段,交易费用通过计算输入的总和减去输出的总和得到。

交易脚本

比特币的交易脚本语言叫作 Script,它是一门基于栈的语言,UTXO 中的锁定脚本和解锁脚本都是用这一语言编写的。

  • When you encounter ordinary data, you’ll put it on the stack. An operator makes calculations based on items on the stack and, in some cases, the transaction being verified.
  • Script 语言没有循环和复杂的流控制,这样就确保了它不是图灵完备语言,因此降低了复杂度,执行时间也变得可预测,避免了交易中出现死循环等其他逻辑漏洞造成拒绝服务攻击(每个交易都会在所有全节点上被校验)的后果。
  • Script 语言是无状态的,交易在一个节点上校验通过,在任何其它节点上也必定会校验通过。

要校验一笔交易依赖于一个锁定脚本和一个解锁脚本。

  • 一个交易的锁定和解锁脚本执行结果是 TRUE,就认为这一交易时合法的。
    • Transactions are valid if the top result on the stack is TRUE (noted as {0x01}), any other nonzero value, or if the stack is empty after script execution.
    • Transactions are invalid if the top value on the stack is FALSE (a zero-length empty value, noted as {}) or if script execution is halted explicitly by an operator, such as OP_VERIFY, OP_RETURN, or a conditional terminator such as OP_ENDIF.
  • 锁定脚本也称为 scriptPubKeywitness script;解锁脚本也称为 scriptSigwitness

早期比特币客户端是将解锁脚本和锁定脚本串联起来按顺序执行,存在安全隐患,解锁脚本可以将脏数据压栈,从而破坏锁定脚本。

# 锁定脚本
3 OP_ADD 5 OP_EQUAL

# 解锁脚本
2

# 将两个脚本结合,结果是 TRUE
2 3 OP_ADD 5 OP_EQUAL 

现在的实现则是解锁脚本和锁定脚本分别执行,然后在两次执行之间传递栈数据。

  1. First, the unlocking script is executed, using the stack execution engine.
  2. If the unlocking script is executed without errors (e.g., it has no “dangling” operators left over), the main stack (not the alternate stack) is copied and the locking script is executed.
  3. If the result of executing the locking script with the stack data copied from the unlocking script is TRUE, the unlocking script has succeeded in resolving the conditions imposed by the locking script and, therefore, the input is a valid authorization to spend the UTXO. If any result other than TRUE remains after execution of the combined script, the input is invalid because it has failed to satisfy the spending conditions placed on the UTXO.

比特币网络中的绝大多数交易的格式都类似“给 Bob 的比特币地址支付款项”,它们是基于一种称作 Pay-to-Public-Key-Hash(P2PKH)的脚本。

  • 对于用 P2PKH 脚本锁定的输出,输出被锁定在一个比特币地址上,包含了对应的公钥和私钥签出的数字签名的解锁脚本可以将其解锁

    # Alice 用于支付给 Bob 咖啡钱的交易的锁定脚本
    OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
    
    # Bob 的解锁脚本
    <Cafe Signature> <Cafe Public Key>
    
    # 结合后的校验脚本
    <Cafe Signature> <Cafe Public Key> OP_DUP OP_HASH160
    <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
    
    • Bob 给出自己的公钥(供后续验签用),验证 HASH(<Cafe Public Key>) 和 Alice 提供的 <Cafe Public Key Hash> 相等,若相等则后续将用 <Cafe Public Key> 进行后续验签;
      • 公钥的哈希就是比特币地址。

UTXO 优点:

  • UTXO 模型下校验交易所需的数据全都包含在锁定脚本和解锁脚本中,无需其它外部状态(如世界状态),构造交易的时候可以选择合适的交易输入(避免多个交易引用到相同的输入),同一个地址可以并行发起多笔交易,从底层原理上就决定了它比账户模型在并发性能上更好;
  • 用户可以用新地址进行转账,新地址和原地址之间的关系很难被追踪,隐私性高。
    • 攻击手段:监视者向用户的一个地址转入少量比特币,当该用户发起交易时,监视者转入的少量比特币就有可能和该用户其它地址上的比特币拼凑出 UTXO 的输入,这样一来该用户的多个地址就都暴露了。

账户模型

Ethereum 状态机的状态由一个个账户组成,每个账户都包含 nonceether_balancecontract_codestorage 四个字段。

账户模型优点:

  • 创建时无需回溯 UTXO,可以从任意时间节点开始同步世界状态,便于编写轻量级客户端;
  • 区块链层级上就没有币的来源的概念,难以追踪;
  • 交易的输入和输出都是地址,能节省存储空间;
  • 易于理解和实现。

References