TON 有内存池吗?进入区块之前能看到什么
TON 有内存池吗?没有像 Bitcoin 那样的单一全局池。节点在出块前看到的是什么,为什么 toncenter 的 pending 是一次模拟,以及内存池流能展示什么、不能展示什么。
在开发者群里问一句“TON 有内存池吗?”,你会得到两个都很笃定的答案。一个是:“没有,TON 没有内存池。”另一个是:“有,这不是 toncenter 的 pending 交易吗。”两边各有一半道理。TON 没有像 Bitcoin 那样由每个节点共同持有、彼此一致的全网未确认交易池。但一条消息在进入区块之前确实存在,节点确实能看到它,也有几个 API 能让你窥见这个窗口。
本文解释这个词在 TON 上的含义,为什么 toncenter 的“pending”是一次模拟,出块前消息流能告诉你什么、不能告诉你什么,以及 TONNode 内存池流是如何工作的——先讲限制。
“内存池”在 TON 上意味着什么
在 Bitcoin 或 Ethereum 上,内存池是一个实实在在的东西:每个全节点保存一组未确认交易,向对等节点广播,出块者从中挑选,通常按手续费排序。
TON 的出发点是另一种单位。用户从来不会发送一笔“交易”。钱包应用签署一条外部消息(external message),交给某个节点。按 docs.ton.org 的说法,“外部消息从区块链之外发出,因此只有一个可选的外部发送方地址”。接收合约——对用户而言就是钱包合约——检查签名和序列号,调用 ACCEPT,直到这时交易才真正产生:“处理传入的外部消息时,只有合约接受该消息,才会创建交易。”
由此得出三个结论,它们正是“TON 内存池”只是一个宽泛说法、而非协议对象的原因。
- 没有可以竞价的东西。 外部消息不携带发送方的任何支付。目标合约在接受之后才支付 gas,依靠的是一笔让它先检查消息的 gas 信用。消息本身没有价格,所以不存在按价格排序的队列。
- 没有单一队列。 TON 是分片的:账户归属于其地址前缀所对应的分片链,发给某个钱包的消息只对出产该分片区块的节点有意义。收到外部消息的节点会把它广播到公共 overlay 网络,文档也指出“验证者之间会相互分享这些消息,可能意外(或有意)地多次投递”。每个节点只保存自己听到的内容;任何地方都不存在一个被一致认可的集合。
- 被拒绝的消息不留痕迹。 如果合约不接受——签名错误、seqno 已被使用、
valid_until已过期或没有余额支付——就不会创建交易,也没有任何区块记录这次尝试。
所以当有人说“TON 内存池”时,诚实的展开是:某个节点已经收到并广播、但尚未被任何区块收录的外部消息。 它是一个几秒钟的窗口,从每个节点看都不一样,而其中一部分永远不会被执行。内存池流展示给你的,就是这个窗口。
为什么 toncenter 的“pending”是一次模拟
toncenter 的 v3 API 提供 GET /api/v3/pendingTransactions,文档描述为“查询符合指定过滤条件的 pending 交易”,可按账户或 trace id 过滤。它的 Streaming API 投递的事件带有 finality 字段,取值为 pending、confirmed 或 finalized,并对第一级给出了精确定义:“pending——模拟或推测执行的结果。该状态可能被作废。”
toncenter 上的 pending 交易并不是从节点队列里捞出来的。索引器拿到外部消息,像验证者那样在当前账户状态上执行它,然后发布预测的交易及其将产生的动作。真实区块到来时,事件会以 confirmed 再次发出,之后是 finalized;预测落空时,会跟着一条 trace_invalidated 通知。订阅按地址进行:WebSocket 的 subscribe 操作接受一个 addresses 列表,它“只有在仅订阅 trace 时可以留空,对其他事件类型是必填的”。
对于多数产品关心的问题——我的用户付款到账了吗,能不能提前一秒展示出来——这是极好的答案。它不提供的是网络在出块前的原始流:每个钱包的每条消息,在任何模拟发生之前。这是两种不同的产品。
TON 内存池流能展示什么、不能展示什么
内存池流是另一种产品:节点一听到外部消息就把它转发出去。在它之上构建任何东西之前,限制比功能更重要。以下内容取自内存池文档的“数据质量”一节。
覆盖是部分的。 流里只有一个节点从公共 overlay 收到的内容。从未到达该节点的消息不在流中,而不在流中也证明不了任何事。TONNode 不发布完整度或速度数据,也不声称自己最先看到消息。
pending 不等于已收录。 checked 消息通过的是节点的广播检查,而不是验证者的执行。在 2026 年 10 月的一个 90 分钟样本中,大约每五条 checked 消息就有一条从未被链上接受。
早期消息未经验证。 节点最早的钩子在其广播签名检查之前运行,此时任何 overlay 对等节点都能注入字节。流默认把它们以 "path":"early","unverified":true 投递,因为对某些用途来说,抢先一步比确定性更重要。任何自动执行的东西,要么发送 "include_unverified":false,要么等待同一 cell_hash 的 checked 副本。
parsed 是尽力而为。 解码出的钱包消息体(v4r2、v5r1、highload_v3、一次 jetton 转账、一次 DEX 兑换)仅由消息字节推断而来,模仿钱包布局的合约可能被错误标记。
会出现重复。 同一个 cell_hash 可能先以 early 到达、再以 checked 到达,重连后再来一次,偶尔还会在去重窗口之后再次出现。处理必须按 cell_hash 幂等。
有些消息被有意丢弃: 超过 65,535 字节的 BoC、不是外部消息的 BoC,以及非普通 addr_std 的目标地址。
只要其中任何一条会破坏你的用例,你需要的就是已确认交易,而不是内存池。检测入账 USDT 付款是最典型的例子:付款是区块里的一笔交易,在此之前的任何东西都不该把订单标记为已付。
TONNode 内存池流的工作方式
TONNode 的流是一个 WebSocket:wss://mempool.tonnode.io/v1/stream。服务器用 Authorization: Bearer tnmp_… 认证;浏览器无法设置请求头,所以由持有密钥的后端向 POST /v1/ticket 申请一张有效期 30 秒的一次性票据,并把返回的子协议传给 new WebSocket(url, subprotocols)。每个连接的第一条消息是 hello,以下从文档原样复制:
{"v":1,"type":"hello","contract":"1.1","epoch":"9f3c1a7be2d04c11","head_seq":123456,"oldest_seq":118020,
"ts_gw_us":1791322891600000,"key_id":"0123456789ab",
"limits":{"max_conn":3,"max_filters":null,"delay_ms":0,"replay_limit":null}}客户端订阅之前不会投递任何内容。过滤器是可选的,并以 OR 组合:dest(发送方钱包)、out_dest(钱包要发往的地址)、op(操作码,例如 jetton 转账的 0x0f8a7ea5)和 pool(DeDust 池)。"filters":{} 表示整个流;一个订阅最多容纳 10,000 个条目,后续的 subscribe 会替换过滤器且不重放。一个用到全部四种过滤器并排除早期消息的订阅:
{"v":1,"type":"subscribe",
"filters":{"dest":["0:2a18ac1734f34579e6a6c2a9e738bb5799d21e7a73ef106895c00c34549a9167"],
"out_dest":["EQB3ncyBUTjZUA5EnFKR5_EnOMI9V1tTEAAPaiU71gc4TiUt"],
"op":["0x0f8a7ea5"],
"pool":["0:a0d1bc3a139cbc6b39a3e3633f74476be441343f9d0fd88b949fca0327b65a75"]},
"include_unverified":false}服务器用生效的去重条目数和投递起点来确认:
{"v":1,"type":"subscribed","filters":4,"include_unverified":false,"from_seq":123451}此后每条消息对应一个 JSON 对象,按 seq 顺序到达:原始 boc、它的哈希(cell_hash、TEP-467 规范化的 norm_hash、sha256)、目标钱包、path 与 unverified、两个时间戳,以及在消息体布局被识别时的 parsed——钱包类型、seqno、valid_until 和发出的转账与兑换。
重放。 服务器保留最近约 60 秒的事件,上限 64 MiB。断线后重新连接,携带 epoch 和最后处理的 seq 发送 resume,就能通过新过滤器收到错过的内容。gap 事件说明跳过了什么以及原因:slow、source_reconnect 或 ring。
套餐。 除了一个密钥上的并发连接数,什么都不计量:Test,7 天,1 个连接,$5;Start,30 天,1 个连接,$15;Pro,30 天,3 个连接,$30;Business,30 天,10 个连接,$100;更多连接按需洽谈。没有消息配额,没有额外延迟,没有免费档。密钥在控制台用与节点套餐相同的余额购买;完整表格见价格页。
流里没有的东西。 通过 TONNode 自己的 liteserver 发送的消息不会回传给内存池订阅者。如果你用 TONNode 节点密钥发送,这些交易不会出现在这个流中;要观察自己控制的钱包,请走其他路线发送,或从链上读取自己的发送记录。
Node.js、Python 和 Go 的完整消费端、使用票据的浏览器流程以及错误码都在内存池流文档中。
TonAPI streaming 与 toncenter streaming 的坦诚比较
触及出块前窗口的服务有三个,它们不可互换。TonAPI 的 Streaming API 曾提供 GET /v2/sse/mempool 和带可选账户过滤的 WebSocket subscribe_mempool 方法;如今它自己的文档开篇就写着“Streaming API is deprecated — please use Webhooks API for real-time updates”。Toncenter 的 Streaming API 位于 wss://toncenter.com/api/streaming/v2/ws,投递交易、动作、trace 和状态变化,并带有最终性级别;pending 事件是模拟出来的,可能被作废,而且除 trace 之外的所有订阅都要求提供地址。
| TonAPI streaming | Toncenter streaming | TONNode 内存池流 | |
|---|---|---|---|
| 其自身文档中的状态 | 已弃用;建议改用 webhooks | 现行 | 现行 |
| “pending”是什么 | 一条内存池消息 | 一笔模拟出的交易或动作;可能被作废 | 一条原始外部消息;未执行 |
| 范围 | 内存池馈送,账户过滤可选 | 除 trace 外必须提供地址 | 整个流,或最多 10,000 条过滤条目 |
| 最终性 | 对内存池馈送不适用 | pending、confirmed、finalized | 无;请在链上确认 |
| 断线后重放 | 未见文档说明 | 未见文档说明 | 通过 resume 重放最近约 60 秒 |
三者都没有公布可用于比较覆盖率的数字。做决定之前,请用你自己的流量测一测。
谁需要内存池流,谁不需要
你很可能需要它,如果:
- 你运营 DEX 或交易机器人,从兑换被广播到被执行之间的几秒钟就是你的优势——前提是在任何资金动作之前使用
include_unverified:false或加一步确认; - 你盯着一组钱包或一个池子,想在转账或兑换被广播的那一刻就看到,而不是等区块落地;
- 你在研究网络:消息速率、钱包版本、哪些 DEX 路由繁忙、有多少消息永远不会执行。
你不需要它,如果:
- 你在检测付款。付款是区块里的一笔交易;用
get_transactions读取它,绝不要凭 pending 消息把订单标为已付; - 你在展示余额或历史。内存池没有状态;请用 LiteServers 章节和按 lt 与哈希查询交易历史;
- 你需要每一条消息,或需要看到自己通过 TONNode liteserver 的发送。覆盖率因 overlay 的本质而只是部分的,而你自己的发送按设计就不在流中。
至于交易场景,构建 TON 交易代理完整讲述了读取、报价、兑换的循环——内存池馈送正是放在这个循环前面的那一环。
FAQ
TON 有内存池吗?
没有单一的全局内存池。TON 不存在一个由每个节点共同持有、彼此一致的全网未确认交易池。存在的是某个节点从公共 overlay 收到、但尚未在区块中看到的外部消息集合;它因节点而异,只持续几秒,并且包含永远不会执行的消息。
能看到 TON 的待处理交易吗?
能,有两种意义。Toncenter 展示的是按地址、通过在当前状态上模拟外部消息得到的 pending 交易和动作,之后可能作废。像 TONNode 这样的内存池流展示的是原始外部消息本身,也就是节点听到的那样,在任何执行之前。两者都不是已确认交易;只有区块才是。
为什么 pending 消息没有进入区块?
因为只有接收合约接受了消息,交易才会被创建。钱包会拒绝错误的签名、已用过的 seqno、过期的 valid_until 或它无力支付的消息,而被拒绝的消息在链上不留任何痕迹。消息也可能在到达出产该分片区块的节点之前就丢失。在 2026 年 10 月的一个 90 分钟样本中,大约每五条 checked 消息就有一条从未被接受。
TON 内存池流是完整的吗?
不是,也没有任何流能做到完整。TONNode 的流只包含一个节点从公共 overlay 收到的内容;从未到达它的消息不在流中。TONNode 不发布完整度或速度数据,也不声称自己最先看到消息。不在流中永远不能证明某件事没有发生。
流中的“unverified”是什么意思?
这是一条早期消息,写入于节点的广播签名检查之前,此时任何 overlay 对等节点都能注入字节,所以它可能是垃圾数据或伪造品。早期消息默认投递;使用 "include_unverified": false 订阅则只收到 checked 消息——它们通过了节点的广播检查,但尚未被验证者执行。
TONNode 内存池流多少钱?
套餐按一个密钥上的并发连接数定价:Test 为 7 天 1 个连接 $5,Start 为 30 天 1 个连接 $15,Pro 为 30 天 3 个连接 $30,Business 为 30 天 10 个连接 $100。没有消息配额,没有额外延迟,也没有免费档。
连接之前
再读一遍“数据质量”一节,决定你到底需不需要早期消息,把处理做成按 cell_hash 幂等,并在资金动作之前在链上确认。如果这些都合适,价格页上的 Test 密钥是 7 天 $5。如果不合适,读取已确认状态的私有 liteserver 访问才是大多数产品真正需要的工具。

