教程区块链区块链技术ch066.4 区块与交易中继策略

本页目录

区块和交易从出块节点到达全网的数万个节点,需要经过精妙的"中继策略"——如何优先传播高手续费交易?如何避免带宽浪费?如何确保全网对区块的接受时间尽可能一致?本节深入比特币与以太坊的消息中继经济学。


6.4.1 "首次传播"优先与库存向量的防重机制

在 P2P 网络中,同一个交易或区块可能通过多条路径到达同一个节点。为避免重复处理与传输,比特币网络为每个节点维护一个库存向量(Inventory Vector)

Inv={(type,hash):已见过}\text{Inv} = \{(\text{type}, \text{hash}): \text{已见过}\}

每个传入的 inv 消息都会通过该集合过滤。如果哈希已存在,则静默丢弃,不发 getdata

首次传播(First-Seen)优先规则

  • 同一个交易哈希首次到达时,该节点将其标记为"已知";
  • 如果同一笔交易稍后以不同版本(如 malleated 版本)到达,由于签名不同导致哈希不同,通常被视为新交易——但这恰好是交易延展性(Malleability)的核心风险;
  • 在 SegWit 激活后,签名精确性消除了大部分延展性空间,使得"首次传播"规则更加可靠。
flowchart TD
    A[收到 inv 消息] --> B{hash 在 inventory 中?}
    B -->|是| C[丢弃]
    B -->|否| D[加入 inventory]
    D --> E[发送 getdata 请求]
    E --> F[收到完整数据]
    F --> G[验证通过后转发 inv 给邻居]
    style B fill:#ffff99

6.4.2 交易池(Mempool)管理与手续费率排序

全节点接收到通过验证的交易后,将其存入本地内存池(Mempool)。Mempool 不是简单的 FIFO 队列,而是按手续费率(sat/vByte or gwei/gas)排序的优先级队列

Bitcoin 的 Mempool 排序规则

Priority(tx)=feesvirtual size (vByte)\text{Priority}(tx) = \frac{\text{fees}}{\text{virtual size (vByte)}}

其中 virtual size 在 SegWit 后按字节计,见证字节更便宜(75% 折扣)。

矿工从 Mempool 中按此优先级选取交易构建区块,直到填满 1-4MB 的区块空间。这形成了一种实时市场竞价

以太坊的 Mempool 排序规则

以太坊采用 gas price 排序,自 EIP-1559 后简化为优先费(priority fee)

Priority(tx)=maxPriorityFeePerGas\text{Priority}(tx) = \text{maxPriorityFeePerGas}

基础费用(base fee)会被销毁,不进入矿工钱包——这是为了消除矿工激励与交易包含之间的博弈。

最大容量与驱逐策略

Mempool 内存有限。当接近上限时,节点采用最低费率驱逐(Lowest-fee-rate eviction)

Evict=argmintxMempool{Priority(tx)}\text{Evict} = \arg\min_{tx \in \text{Mempool}} \left\{\text{Priority}(tx)\right\}

新交易的优先级必须严格高于被驱逐交易的最低值,否则直接拒绝。这确保了网络资源始终被"最有价值的交易"占用。

ts
// mempool-priority-sim.ts
// 纯内置:模拟按手续费率排序的 mempool 与区块构建

class Mempool {
  private txs: Array<{ id: string; feeRate: bigint; size: number }> = [];
  private maxSize: number;
  constructor(maxSize: number) { this.maxSize = maxSize; }
  
  addTx(tx: { id: string; feeRate: bigint; size: number }): 'accepted' | 'rejected' {
    if (this.currentSize() + tx.size > this.maxSize) {
      // 驱逐最低费率交易
      this.txs.sort((a, b) => (a.feeRate < b.feeRate ? -1 : 1));
      const victim = this.txs[0];
      if (!victim || tx.feeRate > victim.feeRate) {
        if (victim) this.txs.shift();
      } else {
        return 'rejected';
      }
    }
    this.txs.push(tx);
    this.txs.sort((a, b) => (a.feeRate < b.feeRate ? 1 : -1)); // 降序
    return 'accepted';
  }
  
  buildBlock(maxBlockSize: number): string[] {
    const selected: string[] = [];
    let size = 0;
    for (const tx of this.txs) {
      if (size + tx.size > maxBlockSize) break;
      size += tx.size;
      selected.push(tx.id);
    }
    return selected;
  }
  
  currentSize(): number { return this.txs.reduce((s, t) => s + t.size, 0); }
  
  dump() {
    console.log(`Mempool: this.txs.lengthtxs,size:{this.txs.length} txs, size:{this.currentSize()} / ${this.maxSize}`);
    for (const tx of this.txs.slice(0, 5)) {
      console.log(`  tx.id:{tx.id}:{tx.feeRate} sat/vB, ${tx.size} vB`);
    }
  }
}

// 模拟
const pool = new Mempool(5000); // 5,000 vByte 容量
const txs = [
  { id: 'txA', feeRate: 10n, size: 500 },
  { id: 'txB', feeRate: 30n, size: 250 },
  { id: 'txC', feeRate: 5n,  size: 1000 },
  { id: 'txD', feeRate: 50n, size: 300 },
  { id: 'txE', feeRate: 20n, size: 400 },
];
txs.forEach(tx => pool.addTx(tx));
pool.dump();
const block = pool.buildBlock(1000); // 1,000 vByte 区块
console.log('Selected for block:', block);
// 输出:txD (300) + txB (250) + txE (400),总 950 vByte,
// 验证了按费率排序而非按到达时间排序

6.4.3 交易验证层级:从语法到共识

交易在进入 Mempool 前必须通过至少三层验证:

层级检查项开销/严重性
语法检查签名格式、脚本语法、字段长度极低 / 低
上下文无关检查双重花费(输入引用的 UTXO 是否已被用?)中 / 高
上下文相关检查输入引用的 UTXO 是否在主链上、是否被确认高 / 极高
共识规则检查时间锁、脚本执行结果、区块大小等极高 / 致命
graph LR
    A[收到交易] --> B[语法校验]
    B --> C[签名验证]
    C --> D[UTXO 检查<br>双花检测]
    D --> E[脚本/合约执行]
    E --> F[通过?]
    F -->|是| G[加入 Mempool]
    F -->|否| H[拒绝并惩罚来源]
    style F fill:#ff9900,color:#fff

6.4.4 紧凑区块(Compact Block):带宽优化极限

当矿工出块后,全网多数节点的 Mempool 中已经包含该区块的大部分交易。比特币 BIP152 引入了紧凑区块编码,避免在区块中附带完整交易数据:

字段说明大小
Header80 字节标准区块头80 B
Short IDs6 字节短标识符(短哈希/随机种子)6 B × tx_count
Prefilled不在收件方 Mempool 中的交易(完整数据)可变

接收方根据短标识符从本地 Mempool 中"配对"交易,只需请求缺失的几笔交易。带宽从 ~1-4MB 降至 ~10KB:

Reduction=Full Block10KB100400×\text{Reduction} = \frac{\text{Full Block}}{10KB} \approx 100\text{–}400\times

关键认知:中继策略不是简单的"尽快发出去",而是经济驱动的优先级排序。Mempool 的费率排序揭示了区块链的微观经济学——区块空间是最稀缺的资源,交易手续费是其价格信号。


← 6.3 Gossip 协议 | 前往 → 6.5 网络层攻击与防御

评论

0

评论加载中…

发表评论

0/2000