Repository navigation
TapeAPI 1.5.0
中文
TapeAPI 1.5.0:在 1.x 基础上只做新增,按 1.0 文档写的代码无需修改。TAP-10 一致模式依然是实验性的,默认关闭;1.5 把它补全到解析与消息两条路径。
安全修复(建议所有用流式 AI 回执核验的用户升级)
- 流式 AI 回执核验可被绕过(1.0.0–1.4.0):
ai.createVerifyingFetch和tapeapi-verify会让一个被截断或被注入内容的 OpenAI Chat / Responses 流显示为“已核验”。需要的条件是:数据路径上有人能改字节(代理、CDN,或服务方自己),并且把结束标记和后面的内容放在同一个网络分块里;另有两种流形态(行首 U+FEFF 的行、流结束时没写完的事件)会让官方 SDK 渲染回执没有覆盖的内容。1.5.0 已全部改为失败关闭;严格模式在结束点切断流,离线核验和核验页面也会报告这两种形态。回执哈希(TAPI-21 §3.5)和测试向量不变,规范只在 §8 增加了一条说明。详见 CHANGELOG 的 Security。 - 用量核验不再被回执里的一句话关掉:核验方以前无条件信任回执里的
usageInjected标记,拿到完整回答也不比对用量;现在非流式回答一律比对,流式只在请求本身没要用量且格式确实会注入时才认这个标记,站点核验页也补上了用量比对,并拒绝“把整段 JSON 冒充成注入流”。 - MCP 工具描述里的隐藏指令:不可见字符检查以前漏掉变体选择符、蒙古文自由变体选择符等;现在按 Unicode 的 Default_Ignorable 属性一并拒绝(emoji 后的单个变体选择符仍允许,常见的中日韩与 emoji 描述不受影响)。代价:已经钉住、含日文异体字序列的工具集会被拒,需要改后重新发布。
- 其余加固:路径里的
%2F、id里的孤立代理项、单个 JSON-RPC 请求核对回答id、上游isError非布尔、限流键的 IP 规范化等,详见 CHANGELOG。X Layer 只有两家运营方,一家宕机或作恶会把钉块拖到旧块上,指南里已写明并建议加第三家节点。 - 代价:极少数诚实流也会被拒(例如上游在事件中途断开)。
- 感谢独立审查发现这些问题。
新增
- 一致模式的无链输入(
allChains: true):容器地址或“处理器合约#ID”在 BNB Smart Chain、Base、X Layer 上各自钉块解析;多条链命中得到ambiguous(附候选),某条链读不到就报那条链的状态,而不是误报not-tapeout。它会向 Base 和 X Layer 的节点发请求,所以单独开关,默认不开;不开时绝不访问别的链的公共节点。 - 容器地址反查处理器号:SDK 随版本带每条链的处理器表快照(BSC 1,174、X Layer 263、Base 101 个),命中后必须在钉块上用
cpuAt读回核实;没命中就分页续扫(每页 8 个、每次最多 256 个),冷启动不会向节点发上千个请求。因此容器地址现在能得到链上名字和完整的激活检查。新增脚本node scripts/gen-processors-snapshot.mjs可复查快照。 - 消息与通道路径(一致模式):
tapeSendKey、channelKeys按 TAP-10 读取:每次新钉一块、每个读取都用 strict 共识并检查eth_chainId;判定hub-changed、circuits-changed(TAP-10 §13.8)和公钥检查(§14.4)。未激活的容器,resolve报unpaid,它的通道记录和 TapeSend 密钥照常可读(§12.2)。新增可选的sealStatusStore,让封存状态跨重启保留。tapesend的一致模式限制 chainId 不超过 2^53−1。 - 解析路径的授权读取用 strict 共识(TAP-11 §2.2):持有人
ownerOf、合约钱包持有人的eth_getCode与isValidSignature(委托与 contentSig)要求足够多的运营方都作答且一致,eth_chainId检查也是 strict。代价要说清楚:默认节点下,BSC 有 3 家运营方,一个节点宕机或落后于钉块,一致模式的resolve就是unavailable;Base 有 4 家(需要 3 家),X Layer 有 2 家(与以前相同)。siteStatus和默认模式不受影响。 tap10-gap在一致模式并开启allChains时,23 个可离线判断的 TAP-10 测试用例全部一致(1.4 是 18 个)。
变更
siteStatus(任何模式):容器地址与“处理器合约#ID”现在能得到名字和处理器号,冷启动多读几次cpuCount、cpuAt;默认模式的resolve与chain.*不变,我们用差分测试逐请求验证过。- 一致模式下,不开
allChains时“处理器合约#ID”字符串直接unsupported(TAP-10 §4.1 只在恰好一条链命中时才解析它);对象形式{ circuits, tokenId }不受影响。一致模式现在只接受 TAP-10 列出的 hub、factory 和 opener。 - TAPI-26 勘误:经 TapeSend 发送的邀请只封给收件方在 hub 上可用的 TAP-10 密钥,不封给通道密钥;此前没有任何实现发送或接收过这种邀请。
你会注意到的变化
- 我们自己的两个服务
11.1013.tape和12.1013.tape已在 2026-10-01 由持有人激活(付到 2036-08-09),在一致模式下都能解析。
安装
npm install https://github.com/BruceLanLan/tapeapi/releases/download/v1.5.0/tapeapi-sdk-1.5.0.tgz如果要单独安装 server,先装同一版本的 SDK tgz。完整变更见 CHANGELOG。本项目未经第三方审计。
English
TapeAPI 1.5.0 is additive over 1.x: code written against the 1.0 docs keeps working unchanged. The TAP-10 conformance mode is still experimental and off by default; 1.5 completes it for both the resolution and the messaging path.
Security (users of streamed AI receipt verification should upgrade)
- Streamed AI receipt verification could be bypassed (1.0.0–1.4.0):
ai.createVerifyingFetchandtapeapi-verifycould report a truncated or content-injected OpenAI Chat / Responses stream as verified. It needs a party on the data path who can change bytes (a proxy, a CDN, or the service itself) and puts the end marker and the content after it in one network chunk; two further stream shapes (a line led by U+FEFF, and an event left unfinished when the stream ends) could make the official SDKs render content the receipt does not cover. 1.5.0 fails closed on all of them; strict mode cuts the stream at its end, and the offline check and the verification page report both shapes. The receipt hash (TAPI-21 §3.5) and the test vectors are unchanged; the spec only gains an informative note in §8. Details in the CHANGELOG under Security. - Usage verification can no longer be switched off by one line in a receipt: the verifier used to trust the receipt's
usageInjectedflag unconditionally and skip the usage comparison even with the full answer in hand; now a whole answer is always compared, a stream only when the request itself did not ask for usage and the format really injects it, the verification page gained the usage comparison, and it refuses a whole JSON answer dressed up as an injected stream. - Hidden instructions in MCP tool descriptions: the invisible-character check missed variation selectors, Mongolian free variation selectors and more; it now rejects everything with the Unicode Default_Ignorable property (a single variation selector after an emoji is still allowed, and ordinary CJK and emoji descriptions are unaffected). Cost: an already pinned tool set containing Japanese ideographic variation sequences is refused and has to be changed and republished.
- Other hardening:
%2Fin paths, lone surrogates inid, the answeridchecked for a single JSON-RPC request, a non-boolean upstreamisError, rate-limit keys with canonical IPs, and more in the CHANGELOG. X Layer has two operators by default, so one that is down or hostile can hold the pinned block back; the guide says so and suggests a third node. - Cost: a few honest streams are refused too (for example an upstream that disconnects in the middle of an event).
- Thanks to the independent review that found these.
Added
- Input without chain information in conformance mode (
allChains: true): a container address or a processor contract#ID is resolved on BNB Smart Chain, Base and X Layer, each at its own pinned block; two chains resolving it isambiguous(with candidates), and a chain that cannot be read is reported with its own status instead of a falsenot-tapeout. It sends reads to the nodes of Base and X Layer, so it is a separate switch and off by default; without it no other chain's public node is ever contacted. - Processor number from a container address: the SDK ships a snapshot of each chain's processor table (BSC 1,174, X Layer 263, Base 101), and a hit is used only after one
cpuAtat the pinned block returns the same address; otherwise it scans in pages (8 per page, at most 256 per resolution), so a cold client never sends a thousand requests to one node. A container address now gets its on-chain name and the full activation check.node scripts/gen-processors-snapshot.mjslets anyone recheck the snapshot. - The messaging path in conformance mode:
tapeSendKeyandchannelKeysread as TAP-10 says: a fresh pinned block per lookup, strict agreement on every read and oneth_chainId,hub-changedandcircuits-changed(TAP-10 §13.8) and the public-key checks (§14.4). The same unactivated container isunpaidtoresolveand still has its channel record and TapeSend key read (§12.2). The new optionalsealStatusStorekeeps the seal status across restarts.tapesendin this mode refuses a chainId above 2^53−1. - Strict agreement for the reads that authorise a signer (TAP-11 §2.2): the holder's
ownerOfand, for a contract-wallet holder,eth_getCodeandisValidSignature(delegation and contentSig) need enough operators to answer, all equal; theeth_chainIdcheck is strict too. The cost, plainly: with the default nodes BNB Smart Chain has 3 operators, so one node down or behind the pinned block makes a conformance-moderesolveunavailable; Base has 4 (3 needed), X Layer 2 (no change).siteStatusand the default mode are unaffected. - With
allChains, all 23 TAP-10 Test Cases thattap10-gapjudges offline conform (18 in 1.4).
Changed
siteStatus(any mode): a container address or processor contract#ID now gets its name and processor number, and a cold client readscpuCountandcpuAtto find them.resolveand thechain.*reads of the default mode are unchanged; a differential test checks every request.- In conformance mode without
allChains, a processor contract#ID string isunsupported(TAP-10 §4.1 resolves it only when exactly one chain does);{ circuits, tokenId }is unaffected. The mode now accepts only the hub, factory and opener TAP-10 lists. - TAPI-26 erratum: an invite sent through TapeSend is sealed to the recipient's usable TAP-10 key on the hub, never to the channel key; no implementation had sent or received one.
What you will notice
- Our own
11.1013.tapeand12.1013.tapewere activated by their holder on 2026-10-01 (paid until 2036-08-09); both resolve in conformance mode.
Install
npm install https://github.com/BruceLanLan/tapeapi/releases/download/v1.5.0/tapeapi-sdk-1.5.0.tgzTo install the server alone, install the SDK tgz of the same version first. Full changes in the CHANGELOG. This project has not been audited by a third party.