14 · mempool / 区块构建 / PBS:链上世界的"未来 12 秒"
第四层第一篇——MEV 开篇。01–13 解释了"链上现在有什么",14 解释**"接下来 12 秒会发生什么"**: 一笔 tx 从你按下 send 到落账之间经历了什么、谁能在这中间看到它、谁来决定它进哪一块、 顺序怎么决定。这是 MEV 全部技艺的物理基础——也是我们
mempool.ts/flashbots.ts/demo-backrun.ts/demo-flashbots.ts这些 watcher 模块直接操作的层面。 沿用 01–13 的村庄画面。结构见README.md§1。
0. 一句话本质
Mempool = 每个节点本地的"待打包 tx 临时桶",不是全网共享的单一队列; 一笔 tx 通过 P2P gossip 在节点间扩散,最终被某个 builder 选中、组进候选区块、 通过 relay 拍卖给当 slot 的 proposer。 PBS(Proposer-Builder Separation)= 把"决定块内容"和"提议块"两件事分给不同角色, proposer 不知道块里装了什么、只看价高签名——MEV 经济学全部建立在这条结构上。
1. 怎么产生的:它解决什么问题
01–13 留下的最后一类硬问题:
- 我钱包按 send 之后,tx 在变成"块里某行"之前的 12 秒到底在哪? ⇒ 在很多个节点的本地"mempool"里。没有全网统一队列——每个节点各自维护,gossip 协议互相同步。
- 谁能看到我那笔 pending tx?只有我的 RPC 节点吗? ⇒ 任何接入 P2P 网络的节点都能看到——这意味着搜寻 MEV 的人 24/7 监听所有 pending。 你的 swap 一进 mempool,可能 0.1 秒内被几百个 searcher 见过。
- 既然 12 秒后才打包,那"谁先按 send 谁先成交"成立吗? ⇒ 不成立。出块者按 priority fee(小费)排序而非时间排序(07 §4.3)。 给小费高的 tx 先打包;MEV 搜寻者还会专门搭乘你的"未来打包"赚价差。
- 04 §5 说 PBS 让 proposer 不看块内容,具体是怎么做到的?谁负责构造块? ⇒ Proposer(PoS 验证者)被随机选中后不亲自构造块。Builder 们各自从 mempool + 私有订单流 + searcher bundle 拼出候选块 → 通过 relay 出价("我出 0.05 ETH 给你 sign 我这块") → proposer 看到的只是"哪个 builder 出价最高 + 一个 header hash" → sign → relay 揭开块体 → 上链。
- Flashbots / BloXroute / Eden 这些 relay 是什么?怎么排队的? ⇒ Relay 是 builder 和 proposer 之间的可信中介。每个 relay 有自己的策略 (Flashbots OFAC-合规,Agnostic 中立,Ultra Sound 不审查等)。 Proposer 通过 mev-boost 软件同时听多个 relay → 选出价最高那个。
- 为什么用"私有 mempool"(Flashbots Protect)就能避免被 sandwich? ⇒ 你的 tx 不经过公共 P2P 网络,直接发给 builder(或 relay);公共 mempool 里 searcher 看不到 → 无法在你前面塞 frontrun tx。代价:builder 知道你的内容(信任假设转移)。
- 我们
publicnode mempool filter expired after 5s——为什么? ⇒ 公共 RPC 是无状态负载均衡的代理:你的"订阅"其实附在某一台后端节点上,请求被路由到另一台时 filter 就失效。生产 MEV 必须用自建 WSS 节点——05 §3.2 已展开过基础设施层面,14 接的是经济意义层面。 - PBS 把决定权移给 builder,那 builder 不会作恶吗? ⇒ 单个 builder 的"作恶空间"=塞自己的 MEV tx + 收 searcher 的 bundle 费用。 但 builder 之间相互竞争 → 出价更高的 builder 拿下 slot → 长期看 builder 经济收敛到 "尽量多收 MEV + 给 proposer 出价高 + 留小利润给自己"。这就是 MEV 经济学的均衡。
→ 这一篇答全部。
2. 它本质在做的"那一件事"
把"一笔 tx 从签名到上链的 12 秒生命窗口"工程化为一条流水线: mempool(每节点本地)→ gossip 扩散 → builder 抓取 + 私有订单流 + searcher bundle 拼装 → relay 拍卖 → proposer 选高价 sign(不看内容)→ slot 出块。 这条流水线的每个环节都是 MEV 经济活动的舞台:看 mempool 找 victim、抢 builder 信任、 给 proposer 加 tip、绕开 OFAC 审查、与他 searcher 拼速度……一切都在这 12 秒里发生。
→ 这是为什么 MEV 不是"找漏洞"——它是对 PBS 流水线每个环节理解 + 执行力的较量。
3. 类比:村庄"快递分拣 + 邮局拍卖"
01–13 的村庄已经有了 EVM 计算器、AMM 桶、Aave 当铺、Oracle 邮差。 14 加的是这一切之间消息传递的物流系统:
┌── 节点本地 mempool ─────────────────────────────────────────┐
│ 每户村民(节点)家门口有个收件箱(mempool) │
│ 邻居寄来的 tx 都先丢进收件箱 │
│ 你(村民)会从自己收件箱里挑、转发给邻居(gossip) │
│ │
│ **没有"全村统一收件箱"**——每家箱子内容略不同 │
│ 最新的 tx 可能 0.5 秒后才扩散到全村 │
└─────────────────────────────────────────────────────────────┘
┌── Builder(块构造者)─────────────────────────────────────┐
│ builder 是一伙专业的"装箱工" │
│ 每 12 秒装一只"未来块": │
│ - 从公共 mempool 抓便宜 + 高 tip 的 tx │
│ - 从私有 orderflow 拿独享 tx(Flashbots Protect 等) │
│ - 接 searcher 发来的 bundle(封装好的 MEV 套餐) │
│ 装好之后,把这只块**估价**:"我这块能赚 N ETH" │
│ 装箱工之间互相竞争——同一时刻有几十只候选块在拼 │
└─────────────────────────────────────────────────────────────┘
┌── Relay(中介拍卖)+ Proposer(出块者)─────────────────────┐
│ Relay = 拍卖会: │
│ 每个 builder 把自己候选块的 header(标签)+ 出价交给 relay│
│ relay 整理:"现在有这些块,最高出价是 N ETH" │
│ │
│ Proposer = PoS 抽中的村民: │
│ 他不亲自装块——他打开 mev-boost 软件: │
│ "给我现在最高价的 header" │
│ relay 给他一个标签 + 价格 → proposer sign 它 │
│ sign 完成那一刻 relay 才揭开块体 → 全村广播 → 落账 │
│ │
│ Proposer 全程不知道块里装了什么: │
│ 他只看到"这个标签价 0.05 ETH,我 sign 它能拿 0.05 ETH" │
│ 内容是不是审查 / 是不是恶意 — 全靠 relay 选择 │
└─────────────────────────────────────────────────────────────┘
→ 一图说尽 04 §5 PBS 全貌:Proposer 卖slot 上某块的签名权;Builder 出价竞争;Relay 当公证。
4. 核心关键点(5 条)
-
Mempool 是"per-node local cache",不是全网共享队列。
- 每个节点维护自己的 pending tx 集合
- tx 通过 devp2p gossip 协议向邻居广播;扩散是概率性的
- 不同节点的 mempool 内容会略不同(特别是高峰期)
- 没有"上链时间"的概念——只有"被某 builder 选进某块"的事件
-
TX 生命周期 = 7 阶段:
① 钱包构造 tx + 签名 (02) ② 钱包/dApp 通过 RPC submit eth_sendRawTransaction ③ RPC 节点把 tx 放进自己 mempool + gossip 给邻居 ④ gossip 扩散;任何监听节点 0.1-5s 看到 ⑤ builder 收纳 → 装进候选块(可能 1 个或多个 builder 同时收) ⑥ 12-second slot:relay 拍卖 → proposer 通过 mev-boost 选高价 → sign ⑦ block propagation → 全网节点验证 → 落账 → receipt- ③-⑥ 步任何一个都可能不发生(tx 被 drop / replaced / 价过低永远卡 pending)
- 当 tx 在 mempool 长时间未上链时,钱包可"replace":用相同 nonce 发新 tx 把旧的覆盖
-
PBS(Proposer-Builder Separation)= 04 §5 复习 + 经济学:
- Proposer:PoS 随机选中的 validator;负责 sign 块
- Builder:专门构造块的实体(专业,跑高性能服务器,订阅多个 mempool + 私有 orderflow)
- Relay:builder 和 proposer 之间的可信中间人
- mev-boost:proposer 节点跑的软件,连多个 relay
- 块价值流向:searcher → builder → relay → proposer
- 当前 mainnet ~92% 的块走 mev-boost (PBS) 路径
- 剩下 ~8% 是 proposer 自己装块(vanilla execution layer)
-
公共 mempool vs 私有 orderflow:
维度 公共 mempool 私有 orderflow 可见性 任何节点 仅特定 builder/relay 防 frontrun 否 是 信任 不需要 信任 builder 不偷看 例子 普通 RPC 提交 Flashbots Protect / MEV-Share / 1inch RFQ 现状 越来越少(大部分智能 router 用私有) 主流(大约 40-60% 量进入私有路径) -
Searcher 工具箱的 mempool 部分:
- 频道 1:监听公共 mempool(
eth_subscribe newPendingTransactions)→ 看 victim swap → 算 backrun → 抢 - 频道 2:监听 builder 的 hint stream(如 Flashbots MEV-Share)→ 用模糊化的提示构造 backrun
- 频道 3:与 builder 直接合作(私有 orderflow 共享,搜寻独家机会)
- 三条路径互有交叉,专业 searcher 三条都跑;普通用户/教学场景跑频道 1
- 频道 1:监听公共 mempool(
5. 必须先认识的前置名词(小词典)
| 名词 | 一句话 | 类比 |
|---|---|---|
| mempool | 节点本地待打包 tx 的临时缓存 | 收件箱 |
| devp2p | 节点间 P2P 通信协议(包含 tx gossip) | 邻居互通的传话规则 |
| gossip | 节点间扩散信息的方式 | 村民口耳相传 |
| pending tx | 已签名提交、未上链的 tx | 寄出但没到的快递 |
| eth_sendRawTransaction | RPC 提交已签 tx 的入口 | 把信投进邮筒 |
| eth_subscribe newPendingTransactions | 订阅 pending tx 流的 RPC 方法 | 实时收件箱监听 |
| priority fee / tip | 给 proposer 的小费(07 §4.3) | 加急费 |
| base fee | 每块协议自调、销毁(07 §4.3) | 村规价 |
| builder | 专门构造候选块的实体 | 装箱工 |
| relay | builder 与 proposer 之间的中介 | 拍卖会公证 |
| proposer | 当 slot 出块的 PoS 验证者 | 这一秒的执笔人 |
| mev-boost | proposer 节点跑的 PBS 软件 | 拍卖客户端 |
| bundle | searcher 提交的 tx 列表,原子打包 | 套餐 |
| frontrun / backrun / sandwich | 抢在前 / 抢在后 / 前后夹击 | 抢插队 / 收尾 / 两边夹 |
| private orderflow | 不经公共 mempool 的 tx 流 | 走 VIP 通道 |
| MEV-Share | Flashbots 推的"匿名提示 + 收益分成"方案 | 模糊化的拍卖广播 |
| OFAC compliance | 美国制裁名单合规(Flashbots 默认开 2022) | 拒收某些地址的快递 |
| commit-reveal | proposer 先 sign 标签、relay 后揭开块体的两步协议 | 蒙眼竞拍 |
| searcher | 找 MEV 机会的实体 | 战场扫荡兵(13 §5 词典) |
6. 一个完整过程走一遍:我们 demo-backrun.ts 的端到端
照搬 demo-backrun 的故事——一笔 victim swap 进 mempool、我们的 watcher 捕获、构造 backrun bundle、anvil 演示成功 wei-exact:
─── T0: anvil 启动 fork,--auto-mining off ──────────────────
─── T1: victim EOA 发出 swap ────────────────────────────────
victimTx = router.swapExactTokensForTokens(
10 WETH → USDC on Uni V2,
minOut=...
)
victimTx 进 anvil 本地 mempool (pending)
─── T2: 我们的 watcher (mempool.ts) 监听 ──────────────────
ws.subscribe('newPendingTransactions')
→ 收到 victimTx hash
→ eth_getTransactionByHash(hash) 拿到 raw tx
→ 解码 input:识别是 swap on routerX, [WETH, USDC]
─── T3: 我们的 predictBackrun.ts ───────────────────────────
根据当前 reserves 算出:
- victim swap 后 Uni V2 的新 reserves
- 与 Sushi 的价差是否值得做 backrun
- 最优 backrun amountIn (10 §4 闭式公式)
─── T4: 我们构造 backrun bundle ────────────────────────────
bundle = [
victimTx, // 先 victim
arbTx (we send to Arbitrageur.arb([Uni, Sushi], USDC, 26869e6))
]
注:在 anvil demo 里我们直接给本地 sequencing 二者
在生产里我们把这个 bundle 发 Flashbots relay (16 待写)
─── T5: anvil 通过 evm_mine 触发出块 ───────────────────────
→ 块包含 [victimTx, arbTx] 按顺序
→ victimTx 执行:Uni V2 价偏向 USDC 一边
→ arbTx 执行:闪电贷 + 借此偏离做套利 + 还款
─── T6: 验证 ───────────────────────────────────────────────
P1 = predictBackrun 预测的 profit (我们事前算的)
P2 = anvil 真实 post-tx 状态读出的 profit
P3 = arbTx 实际链上利润扣 5bps premium
P1 = P2 = 2419.7984 USDC (wei-exact!)
P3 = P2 - 5bps premium (1 wei 误差源于整数除法)
→ 这就是为什么 demo-backrun.ts 是项目里最 deterministic 的 MEV 演示:
- 不依赖公网 mempool(避开 publicnode 5s 过期问题)
- 不依赖 Flashbots(避开 relay 不可控)
- 纯 anvil + 我们的逻辑 → P1 = P2 字节级一致 → 证明 watcher + predictor + executor 三件套全对
生产 vs 教学的差异
| 维度 | 我们 demo-backrun (anvil) | 真实主网 |
|---|---|---|
| Victim 来源 | 我们自己构造 | 公共 mempool 看到(频道 1) |
| Mempool 来源 | anvil 本地 | 自建 WSS 节点(05 §3.2) |
| Bundle 提交 | 直接 evm_mine | Flashbots relay 提交 |
| 排序保证 | anvil 顺序 | builder 接受 + 包含进块 |
| 竞争 | 无 | ~100+ searcher 同时盯同一 victim |
→ 教学场景把 wei-exact 推导跑通即胜利;真实场景胜负在毫秒。
7. 常见误区(逐条拍死)
| 误区 | 实情 |
|---|---|
| "Mempool 是全网共享的" | 错。每个节点本地各一份。gossip 协议同步但不保证全网状态一致 |
| "TX 上链顺序 = 提交时间" | 错。按 priority fee 排序 + searcher MEV 竞争 + builder 自身策略 |
| "高 gas price 一定先上链" | 大概率,但 builder 可能拒收(OFAC / 计算成本高 / bundle 冲突) |
| "Flashbots 不审查" | Flashbots 自 2022 起对 OFAC 制裁地址做 filtering(默认开)。中立 relay 有 Agnostic / Ultra Sound / BloXroute(部分) |
| "私有 mempool = 匿名" | 错。Builder 看到全部内容。是"对公众观察者隐藏",不是"对所有人隐藏" |
| "Proposer 决定块内容" | PBS 下不是。Proposer 盲签 header;内容由 builder 决定 |
| "Relay 是 builder" | 不同角色。Relay 是中介公证;builder 是块装配工。一家公司可同时跑(Flashbots 跑 builder + relay) |
| "Mempool 是协议层" | 不是。它是节点实现层——不在 EVM 规范、不在 consensus 规范、各客户端实现策略可不同 |
| "Searcher 看 mempool 就够了" | 对低端 MEV 是。高端 searcher 还订阅 builder hint 流(MEV-Share)+ 私有 orderflow + ASIC 级硬件加速 |
| "我能监听 mempool 就能赚 MEV" | 监听是入门。赢的关键:基础设施延迟(毫秒)+ 算力(同时算几十种 backrun)+ 资金(高 tip 抢入)+ relay 关系 |
| "PBS 让 MEV 减少了" | 反了。PBS 正规化 + 提高效率了 MEV 提取。MEV 总量没减少;只是分配从 proposer 移到 builder/searcher 链 |
| "搭个家用机就能跑生产 searcher" | 现实不行。延迟 + 带宽 + 算力 + relay 信用都要积累。这是 05 §5 L0–L4 阶梯接此 |
8. 与本项目实践的对应
mempool.ts watcher(Phase 5 step 2)
- 用
provider.on("pending", ...)(ethers v6 内部走 eth_subscribe)订阅 pending tx - 收到 hash →
getTransaction(hash)拿 raw → 解码 input 判断是否 V2 swap _seenHashes: Set<string>去重(同一 hash 在多个节点上扩散会被反复推送)- 触发
predictBackrun算潜在收益 + 决定是否提交 bundle
publicnode mempool filter expired 的精确解释
- publicnode 是 stateless load balancer:你的 WSS subscribe 实际附在某一台后端节点
- 但同一连接的不同请求被路由到不同节点 → 第二台后端不认识你的 filter id → 5 秒后告诉你过期
- 解决方案两条:(a) 自建 geth/erigon 节点跑 WSS(05 §3.2 L1);(b) 用 alchemy/infura 的 enhanced subscription(专为 dev 提供 sticky session)
- 教学场景我们选 (a) 的简化版:用 anvil 跑 fork 演示 demo-backrun
predictBackrun.ts 中的"factory mismatch"修正
- 早期 bug:1 ETH 在 Uni V2 swap 进了 mempool → predictBackrun 盲目对每个池套用 → 误报"Sushi 也受影响"
- 根因:没区分调用 router → factory 的映射
- 修复:
predictBackrun(routerAddr, ...)内只把跟 routerAddr 同一 factory 的 pair 当 victim 影响目标 - 这是项目里 evidence-first 自我抓 bug + 修正的小例子,连回 docs 自我更正纪律
demo-flashbots.ts 真实 relay 握手
- 通过
@flashbots/ethers-provider-bundleSDK 包装 bundle - 提交到
https://relay.flashbots.net→ 收到 structured error"insufficient funds for gas * price + value: have 0 want 1050000000000000"= 0.00105 ETH = 50 gwei × 21000 (EIP-1559 ceiling × min gas) - 这条 error 是关键证据:整个 SDK / auth / transport 链路全通过 relay 验证,只差 EOA 没有真 ETH
- 16 篇 Flashbots / bundle 待写时会回到这条 → 把 protocol 层端到端讲透
04 / 05 / 06 / 07 / 11 / 12 / 13 → 14 的承接
- 04 §5 PBS 给 MEV 的结构性根;14 把 PBS 从协议结构 → 经济流水线
- 05 §3.2 mempool 给基础设施的硬件需求;14 给经济意义上的"看到/被看到"含义
- 06–07 给一笔 tx 在 EVM 里跑的细节;14 给一笔 tx 进 EVM 之前 12 秒的细节
- 11 + 12 给 MEV 机会的来源(清算 + oracle 抖动);14 给"怎么把机会变现"的执行层
- 13 给"零本金"的杠杆;14 给"找到目标 + 抢到执行权"的路径
第四层的串接
- 14 mempool 给"看到机会 + 抢到执行权"
- 15 MEV 给"策略类目"(套利 / 清算 / 三明治 / backrun 各自机制)
- 16 Flashbots / bundle 给"上线提交工具链"(demo-flashbots 接的就是这条)
- 17 跨链给"机会跨域 → 失去原子性 → 新风险新机会"
9. 自检问题(答得出才算过)
- Mempool 是全网共享队列吗?为什么不同节点看到的 pending set 会不同?
- 一笔 tx 从签名到落账经过哪 7 阶段?哪几步可能"永远没发生"?
- PBS 中 proposer / builder / relay / searcher 各自做什么?块价值的流向是?
- 为什么 proposer 盲签 header 而不看块内容?这种 commit-reveal 设计解决了什么问题?
- 公共 mempool 和私有 orderflow 在可见性、防 frontrun、信任假设上各自如何?为什么主流智能 router 都走私有?
- "publicnode mempool filter expired after 5s"在节点架构上是什么?怎么彻底解决?
- 我们
demo-backrun.ts为什么能 P1 = P2 字节级一致?这种 wei-exact 在主网上能不能成立? - PBS 让 MEV 提取量增加还是减少了?为什么?
── Q&A / 更正记录区(按日期追加)──
规范见
README.md§0。质疑/反馈/纠错按日期累积,不抹错误轨迹。
-
(2026-05-21 建立。暂无 Q&A。)
-
(2026-07-27) 问:详细讲一下交易的竞争与打包机制。
答(补充"竞争"具体竞的是什么、"打包"具体怎么排序,未更正原文;完整版含交易全流程 stepper 见
../total/Q&A/2026-07-27-链上账本手记.html第三节 "竞价广播"/"打包"两步):竞价广播:交易广播进 mempool,此刻公开可见但未生效。EIP-1559 后费用分两块:base fee(协议按 上一块拥堵程度自动设定,每块最多变动 ±12.5%,这部分被销毁,不给任何人)+ priority fee/tip (自己出的小费,真正付给打包者的钱)。
effectiveGasPrice = min(maxFeePerGas, baseFee + maxPriorityFeePerGas)。"竞争"竞的就是这笔 tip:builder 天然倾向优先打包 tip 更高的交易, 因为区块空间有限。MEV searcher 竞争的不是"谁先广播",是"谁能出更高价格/给 builder 更好的组合收益, 换取交易被排在关键位置之前或之后"——这也是大额交易走私有 orderflow 直接发给 builder、不进公开 mempool 避免被抢跑的原因。打包:一个块的总 gas 有硬上限(以太坊主网约 3000 万 gas,协议目标平均用量落在 1500 万, base fee 就是照着"上一块用量相对目标高低"调的杠杆)。builder 从 mempool(以及私有 orderflow) 里挑一批交易,目标是让这个块的总收益(tip 总和 + 可提取的 MEV)最大化,不是谁先来就排谁—— 常见误区"打包=排队窗口先来后到"是错的,实际排序逻辑更像一场组合竞价。PoS 之后这个流程进一步拆成 proposer(出块权持有者)和 builder(实际组装区块内容的专业角色),大多数区块通过 mev-boost 这类 中继完成"proposer 盲选出价最高的 builder 方案"这一步(PBS)。
与滑点的串联:竞价排序权 + 交易方设置的滑点容忍空间(
amountOutMin)合在一起,正是三明治攻击 的具体机制——完整推导见10-DEX与AMM.md同日条目。