<aside> 💡 UTXO、Account、签名、重放攻击、Rollup、隐私

</aside>

模型基础

区块链的tx分为两种模型,分别是比特币为代表的UTXO(Unspent Transaction Output)模型,和以太坊为代表的Account模型。前者适用于货币记账,后者适用于链上应用。

UTXO模型

  1. 类似于现金的交易模型

Untitled

  1. 比特币的tx结构(Github

    const std::vector<CTxIn> vin;
    const std::vector<CTxOut> vout;
    const int32_t nVersion;
    const uint32_t nLockTime;
    
  2. 一个tx包含一个或多个输入(Input)、一个或多个输出(Output)。以币安热钱包地址为例:

    1. 每个Output包含了转账的目标Address和Value,拥有这个Address的私钥即可花费这个Output
    2. 每个Input通过(txid, index)指向了之前一笔tx的一个Output,通过Output私钥签名将这个Output花费掉
    3. 未被花费的Output称作UTXO,一个UTXO只能被花费一次
    4. 一笔tx的Input金额之和会略大于Output金额之和,差值是付给矿工的Fee
    5. Fee的多少和tx的size正相关

    UXTO模型

    UXTO模型

  3. 支付流程:用户A支付金额n给用户B

    1. 用户A会维护自己所拥有的UTXO集合(比如币安热钱包地址的UTXO集合
      1. 遍历链上的历史tx得到
    2. 用户A从集合中选取一个或多个UTXO作为tx的Input
      1. 这些UTXO的金额之和为m,m大于n
    3. 用户A为tx设置两个Output
      1. 一个Output支付给B的地址,金额是n
      2. 另一个Output支付给A的一个找零地址,金额为m-n-fee
    4. 同样以币安热钱包地址举例
      1. 这个tx支付2 BTC给热钱包并找零
      2. 这个tx把热钱包的一个1 BTC的UTXO支付给多个地址

UTXO selection

UTXO selection

  1. UTXO模型的特点

    1. 隐私性强

      1. 用户的钱包由多个地址组成:默认找零给新地址,默认每个地址只用一次

      比特币的多地址钱包

      比特币的多地址钱包

    2. 并发容易

      1. 支持一对多转账
      2. 一个地址的两个UTXO可以独立花费
    3. 结论

      1. UTXO模型是符合“去中心化账本”需求的最简设计
      2. 简洁意味着安全,比特币运行十余年未出过问题
      3. UTXO的设计和钱包里的一堆coin相似,印证了Bitcoin的起名
  2. 例子回顾:双花攻击(Double-spending Attack)

    Untitled

Account模型

  1. 类似于银行的交易模型
  2. UTXO模型的应用场景受限
    1. 人们不满足于将区块链用于记录账本,而想要在其上搭建应用
      1. 区块链需要成为“可编程数据库”
    2. UXTO模型不是数据库 → State的概念
      1. UTXO的节点仅记录转账,却没有记录最终余额
        1. 一个地址的余额,需要遍历该地址的所有UTXO,然后求和得到
        2. 类比数据库:仅记录对数据的增删改的操作,却没有记录数据的最终状态
    3. 为什么UTXO设计上没有考虑记录State?因为区块链仅用作账本的情况下记录State会:
      1. 增加成本
        1. 记录每个地址的余额需要额外的存储空间
        2. 余额的更新和回退需要加大节点的计算量
      2. 不需要
        1. 由于隐私性的考虑,用户的钱包默认由多个地址组成,且每个地址只有很少的交易
        2. 因此获取钱包的总余额,需要遍历UTXO,和遍历各个地址余额的难度是接近的
        3. 仅有转账没有应用,是不需要获取他人地址的余额的
    4. 需要一种记录State的交易模型

tx和state

tx和state

  1. 以太坊的tx结构(Github

    1. From可以从签名V,R,S中算出来
    2. To是目标地址
    3. Value是转账金额
    4. Data字段会在调用合约的时候用上,记录调用的method和输入的参数
    5. Gas相关的字段是付给矿工的手续费
    Type hexutil.Uint64 `json:"type"`
    
    // Common transaction fields:
    Nonce                *hexutil.Uint64 `json:"nonce"`
    GasPrice             *hexutil.Big    `json:"gasPrice"`
    MaxPriorityFeePerGas *hexutil.Big    `json:"maxPriorityFeePerGas"`
    MaxFeePerGas         *hexutil.Big    `json:"maxFeePerGas"`
    Gas                  *hexutil.Uint64 `json:"gas"`
    Value                *hexutil.Big    `json:"value"`
    Data                 *hexutil.Bytes  `json:"input"`
    V                    *hexutil.Big    `json:"v"`
    R                    *hexutil.Big    `json:"r"`
    S                    *hexutil.Big    `json:"s"`
    To                   *common.Address `json:"to"`
    
  2. 记录State

    Untitled

    1. State是个key-value的数据库
      1. key是地址:既可以是普通用户地址,又可以是合约地址

      2. value的结构(Github

        Nonce    uint64
        Balance  *big.Int
        Root     common.Hash // merkle root of the storage trie
        CodeHash []byte
        
        1. 普通地址只用到
          1. Nonce :从0开始,每发出一个tx,记录进tx,然后加1;用来保证tx的顺序执行和签名的唯一性
          2. Balance :该地址的余额
        2. 合约地址还会用到
          1. Root:合约的数据库的hash
          2. CodeHash :合约的源码
    2. 数据库的存储结构叫做“Merkle Patricia tree”,会在后续课程中解释
    3. State的hash(通过Merkle Patricia tree计算得到)记录进Block Header的stateRoot字段,用于验证State
      1. 注意State的内容不像交易那样,并不是区块链的一部分,不会出现在Block Body里
      2. 当前高度的State是在上个高度的State基础上,使用当前高度的tx list更新得到,再用stateRoot验证通过
  3. tx花费的gas主要取决于:新增存储空间+验证所需计算

  4. Account模型的特点(用富豪榜Polygon的地址观察)

    1. 有各种小缺点
      1. 一个地址发出去的tx是按照Nonce串行的、顺序的,无法并发
      2. tx作用于State进行更新,但tx构建时候作用的State可能和上链的时候不一样
        1. tx上链时的State变化会改变tx执行的结果
        2. 多个tx上链作用State的顺序会影响tx执行的结果
        3. tx会存在“执行失败”的链上状态
      3. 余额用不完:tx花费gas的取决于上链时作用的State,所以tx构建时无法准确预估gas,所以无法构建交易正好把Balance用完
    2. 适于构建应用
      1. 任何地址的当前状态可以快速retrieve到