教程区块链区块链技术ch077.7 交易生命周期与确认

本页目录

一笔以太坊交易从用户点击"发送"到被全网最终确认,要经历构造、签名、广播、入池、排序、执行、出块、收据生成、执行状态确认等十余个环节。理解这一完整生命周期,是理解以太坊用户体验、交易延迟以及矿工/提取者可提取价值(MEV)的前提。


7.7.1 交易构造与签名

发送者使用私钥对交易的RLP 编码哈希进行签名。以太坊使用 ECDSA(secp256k1),与比特币相同曲线,但签名字段包含 v, r, s,其中 v 编码链 ID 和奇偶性。

交易字段(EIP-1559 类型 2 交易)

字段类型说明
chainIduint64链 ID(主网=1)
nonceuint64发送者账户序号
maxPriorityFeePerGasuint256给验证者的小费
maxFeePerGasuint256最高可接受单价
gasLimituint64交易消耗的 Gas 上限
toaddress / null接收者地址或 null(表示合约创建)
valueuint256转移的 ETH(Wei)
databytes调用输入数据(calldata)
accessList列表EIP-2930 热状态预声明(可选)
v, r, s签名组件ECDSA 签名
graph LR
    A[用户私钥] -->|签名| B[RLP 编码交易 + v,r,s]
    B --> C[广播到 P2P 网络]
    C --> D[节点接收]
    D --> E{签名验证通过?}
    E -->|是| F[加入 mempool]
    E -->|否| G[丢弃]
    style A fill:#ffcccc
    style F fill:#ccffcc

7.7.2 Mempool 与交易选择

交易进入各全节点的 内存池(mempool/txpool)。按前述 EIP-1559 规则,交易池按有效价格排序:

sortKeyj=min(maxFeePerGasj, baseFee+maxPriorityFeePerGasj)\text{sortKey}_j = \min(\text{maxFeePerGas}_j, \ \text{baseFee} + \text{maxPriorityFeePerGas}_j)

交易池的复杂性

  • 地址内顺序:同一地址的 tx 必须按 nonce 严格顺序执行,nonce 不连续时后续交易挂起;
  • 链上状态依赖:若某交易的 to 字段是合约,其执行结果(如 SSTORE)影响后续从同一地址发出的交易 Gas 估算;
  • PBS(Proposer-Builder Separation):在 PoS 中,Builder 专门构建最优价值区块(含 MEV 提取),而 Proposer(验证者)仅选择最高价值区块头,自己无法查看交易内容(防止时间窃贼攻击)。

7.7.3 区块纳入与状态执行

Builder/验证者从交易池中选择交易,按顺序逐个执行:

  1. 对每笔交易
  • 检查 nonce 匹配;
  • 检查签名有效性;
  • 检查余额 >= GasLimit × MaxFeePerGas + value;
  • 按当前 stateRoot 执行 EVM(更新内存、堆栈、存储、返回数据);
  • 生成交易回执(Receipt)。
  1. Gas 累积:所有交易 GasUsed 之和不超过区块 GasLimit(30M)。
  1. 状态提交:执行完所有交易后,计算新 stateRoot。
  1. 区块打包:将交易列表、交易根、收据根、新 stateRoot、时间戳、parentHash 封装为新区块。
graph TD
    A[mempool 排序] --> B[选择前 N 笔]
    B --> C[逐笔执行 EVM]
    C --> D{执行成功?}
    D -->|是| E[更新状态树]
    D -->|否| F[回滚该交易状态\n但仍收取已耗 Gas]
    E --> G[生成回执]
    F --> G
    G --> H[计算新 stateRoot]
    H --> I[封装区块]
    style E fill:#ccffcc
    style F fill:#ffcccc

7.7.4 交易回执与状态确认

每笔交易都有一个回执(Receipt),包含:

字段说明
status1(成功)或 0(失败/回滚)
gasUsed该交易实际消耗的总 Gas
logsBloom256 字节过滤器,加速日志查询
logs交易执行中触发的所有事件(LOG0-LOG4 输出)
cumulativeGasUsed区块中截止该交易的累计 Gas

用户如何确认交易成功?

  1. 钱包向 RPC 节点查询 eth_getTransactionReceipt
  2. 检查 status === 1
  3. 可选:监听 logs 中合约触发的事件(如 Transfer 事件)确认具体业务逻辑。
ts
// tx-receipt-verify-sim.ts
// 纯内置:模拟交易生命周期状态检查

interface TxReceipt {
  status: 0 | 1;
  gasUsed: number;
  logs: Array<{ topic0: string; data: string }>;
  blockNumber: number;
  blockHash: string;
}

function confirmTransaction(
  receipt: TxReceipt | null,
  currentBlock: number,
  requiredConfirmations: number
): { confirmed: boolean; safe: boolean; reason: string } {
  if (!receipt) return { confirmed: false, safe: false, reason: '交易尚未入块' };
  if (receipt.status === 0) return { confirmed: true, safe: false, reason: '交易执行失败(回滚)' };
  
  const confs = currentBlock - receipt.blockNumber + 1;
  const safe = confs >= requiredConfirmations;
  return {
    confirmed: true,
    safe,
    reason: safe 
      ? `已确认 confs个区块,达到安全阈值{confs} 个区块,达到安全阈值{requiredConfirmations}` 
      : `已入块但仅有 confs个确认,建议等待{confs} 个确认,建议等待{requiredConfirmations} 个`,
  };
}

const receipt: TxReceipt = {
  status: 1, gasUsed: 21000, logs: [], blockNumber: 100, blockHash: '0xabc...',
};
console.log(confirmTransaction(receipt, 101, 12));
// 输出: 1 确认,未达 12 安全阈值
console.log(confirmTransaction(receipt, 112, 12));
// 输出: 12 确认,安全

7.7.5 最终性确认:LMD-GHOST + Casper FFG

在 PoS 以太坊中,"多少确认才算安全"的标准与 PoW 不同。

  • 区块 head:区块已被提出并传播;
  • Justified:2/3 验证者对该区块的 epoch 投票确认;
  • Finalized:该区块及其所有祖先区块被 2/3 验证者"最终化",理论上不可被回滚(除非 1/3+ 质押被罚没)。
graph LR
    A[已提出] --> B[已证明<br>Attestation 2/3]
    B --> C[已确定<br>Justified]
    C --> D[已最终化<br>Finalized]
    D --> E[不可逆转<br>除非 1/3+ 罚没]
    style D fill:#ccffcc
    style E fill:#ccffcc
  • 交易所通常等待 12-20 个 slot(约 2.5-4 分钟)视为"入账确认";
  • 开发者的用户体验建议:finalized 块前不要视为最终(但大多数日常应用 1-2 slot 即可)。

关键认知六:交易不是"发送即完成"。从用户签名到链上可见(~12 秒),从可见到不易回滚(~2 分钟),从不易回滚到最终化(~13 分钟)——每个阶段有不同的安全假设。理解这个阶梯,才能设计不会在高并发场景下出错的 DApp。


← 7.6 预编译合约 | 前往 → ch07-summary

评论

0

评论加载中…

发表评论

0/2000