Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
网络与协议指南阅读约 13 分钟

通过摘要和检查点解析 Sui 交易

使用 sui_getTransactionBlock 解析 Sui 交易摘要,读取其检查点和 inclusionProof,并与已认证的检查点进行核对。

TL;DR

在 Sui 上,交易由 base58 摘要标识,只有当它被提交到由单调递增序列号标识的已认证检查点中时,才成为最终状态。sui_getTransactionBlock 方法接收该摘要以及 showEffects、showObjectChanges 等选项,并返回交易块以及 checkpoint 字段和 inclusionProof。然后,你可以使用返回的检查点序列号读取检查点,并确认该摘要出现在其交易列表中。本文区分了协议文档行为与提供商特定行为,提供了成功路径和未找到路径的可运行 Node.js 示例,并提供了一个结果表,供你针对自己的端点填写。

Sui 交易标识:摘要与检查点序列

Sui 区分了两个容易混淆的标识符。交易由 base58 摘要标识,浏览器通常将其标记为“Tx hash”;这是你粘贴到查询框中的值。检查点由单调递增的序列号标识,它是一个或多个交易被提交的容器。摘要回答“哪笔交易”,而检查点序列回答“它在哪里以及何时落地”。(参见 Sui 官方 检查点概念文档)

Sui 检查点概念文档将检查点描述为承诺单位:交易被排序、批处理并认证,而认证使包含关系具有持久性。这就是为什么 Sui 上的“已确认”应理解为“已包含在已认证的检查点中”,而不仅仅是“节点接受了我的提交”。临时执行可能发生在认证之前,一笔已执行但尚未进入已认证检查点的交易,在同样意义上还不是最终状态。

这一区别驱动了整个解析工作流。你通过摘要进行解析,从响应中读取 checkpoint 字段,然后将该序列号与检查点本身进行核对。有关网络及其端点的更广泛介绍,请参阅 Sui 网络页面。

  • 摘要:base58 交易标识符,是 sui_getTransactionBlock 的查询键。
  • 检查点序列:单调递增的整数,标识已提交的容器。
  • 认证:根据 Sui 检查点概念文档,使检查点包含关系具有持久性的属性。
  • 临时执行:可能先于已认证包含的执行,不应视为最终状态。

sui_getTransactionBlock 接受和返回的内容

Sui JSON-RPC API 参考文档说明 sui_getTransactionBlock 接收一个摘要和一个选项对象。这些选项控制交易块中哪些部分被填充:showEffects、showInput、showEvents、showObjectChanges 和 showBalanceChanges。与某个选项对应的字段仅在该选项被设置时才存在,因此响应结构部分取决于你的请求。

响应包括摘要、checkpoint 字段、timestampMs 和交易主体,以及请求时的 effects、events 和 objectChanges。checkpoint 字段携带提交该交易的检查点的序列号,响应还携带一个 inclusionProof,其 digest 是交易摘要。将 checkpoint 字段视为通往检查点读取路径的桥梁。

由于选项会改变负载,它们也会改变响应大小以及节点组装响应的工作量。每次调用都请求所有内容很方便,但更重;只请求你实际使用的选项。交易效果和对象变更 一文介绍了在获得 effects 和 object changes 后如何解读它们。

  • showEffects:填充 effects,包括状态和使用的 gas。
  • showInput:填充交易输入,包括发送者和 gas 数据。
  • showEvents:填充发出的事件。
  • showObjectChanges:填充创建、修改和删除的对象摘要。
  • showBalanceChanges:填充每个地址和代币类型的余额变化。

使用可运行的 Node.js 示例解析摘要

下面的示例使用 @mysten/sui 客户端解析一个带有 effects 和 object changes 的摘要,然后打印检查点序列号和 inclusionProof 摘要。它刻意保持小巧,以便你可以将其粘贴到临时文件中,并指向你使用的端点。客户端库是一个便利包装器;底层调用与 Sui API 参考文档中记录的 JSON-RPC 方法相同。

使用来自浏览器或你自己提交的真实摘要运行它。如果你更喜欢原始 JSON-RPC,可以通过 fetch 发送相同的请求,使用 JSON-RPC 2.0 信封,JSON-RPC 2.0 规范将其定义为 jsonrpc 版本字段、method、params 和 id。

import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';

const client = new SuiClient({ url: getFullnodeUrl('mainnet') });

async function resolve(digest) {
  const tx = await client.getTransactionBlock({
    digest,
    options: {
      showEffects: true,
      showInput: true,
      showObjectChanges: true,
    },
  });

  console.log('digest        :', tx.digest);
  console.log('checkpoint    :', tx.checkpoint);
  console.log('timestampMs   :', tx.timestampMs);
  console.log('status        :', tx.effects?.status?.status);
  console.log('inclusionProof:', tx.inclusionProof?.digest);
  console.log('objectChanges :', tx.objectChanges?.length ?? 0);
  return tx;
}

resolve(process.argv[2]).catch((err) => {
  console.error('resolve failed:', err.message);
  process.exitCode = 1;
});

将摘要与其检查点进行核对

一旦你有了检查点序列号,就读取检查点并确认交易摘要出现在其交易列表中。这就是核对步骤:它将“节点告诉我一个检查点编号”转换为“我在该检查点中观察到了该摘要”。Sui 检查点概念文档解释说,检查点是承诺单位,因此这个检查是有意义的包含测试。

旧版 sui_getCheckpoint 方法被记录为已弃用,推荐使用检查点读取路径,因此在硬编码之前,请对照 Sui 文档验证当前方法名称。提供商对任何给定方法的支持因提供商而异,因此请在你使用的端点上确认可用性,而不是假设所有节点都一致。

下面的示例读取检查点并检查成员资格。它使用相同的客户端,并假设你已经从上一步获得了检查点序列号。

import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';

const client = new SuiClient({ url: getFullnodeUrl('mainnet') });

async function reconcile(digest, checkpointSeq) {
  const cp = await client.getCheckpoint({ id: String(checkpointSeq) });

  const digests = (cp.transactions ?? []).map((t) =>
    typeof t === 'string' ? t : t.digest,
  );

  const included = digests.includes(digest);
  console.log('checkpoint seq :', cp.sequenceNumber);
  console.log('tx count       :', digests.length);
  console.log('included       :', included);
  return included;
}

reconcile(process.argv[2], process.argv[3]).catch((err) => {
  console.error('reconcile failed:', err.message);
  process.exitCode = 1;
});

摘要解析与检查点和游标枚举的对比

通过摘要解析和通过检查点或游标枚举回答的是不同的问题。sui_getTransactionBlock 是点查询:你已经知道摘要,想要其详细信息及其检查点。suix_queryTransactionBlocks 是枚举:你想要按条件过滤的一页交易,并使用游标向前遍历。选择错误的方法会导致代码笨拙,例如为了找到你已经拥有摘要的一笔交易而翻遍数千笔交易。

当你有一笔特定交易要检查、当你正在核对用户报告的哈希、或当你正在确认单次提交的包含关系时,使用摘要解析。当你想要已知容器中提交的所有内容时,使用检查点读取。当你正在构建信息流、回填历史或按过滤器扫描时,使用游标枚举。queryTransactionBlocks 游标分页 一文详细介绍了枚举路径,检查点流和账本服务 一文介绍了如何将检查点作为流来消费。

  • 按摘要点查询:sui_getTransactionBlock,最适合已知交易。
  • 容器读取:检查点读取路径,最适合已知检查点中的所有内容。
  • 过滤枚举:带游标的 suix_queryTransactionBlocks,最适合信息流和回填。
  • 流式处理:检查点流,最适合持续摄取。

使用有界轮询查询刚提交的交易

刚提交的交易在检查点包含它之前可能返回未找到。这是预期行为,不一定是错误:摘要从交易提交那一刻起就存在,但节点可能还无法将其解析为已提交的交易块。正确的模式是按摘要进行有界轮询,在尝试之间退避,并在截止时间后放弃,而不是无限循环。

使用最大尝试次数和延迟来限制轮询,并将持续未找到视为检查摘要字符串、网络和端点的信号。如果交易提交到的网络与你查询的网络不同,它永远不会在错误的网络上解析。Sui RPC 指南 是端点选择和方法可用性的有用伴侣。

  • 使用固定延迟和最大尝试次数进行轮询。
  • 在截止时间之前将未找到视为临时状态,然后进行调查。
  • 确认摘要是完整的 base58 值,而不是截断的浏览器标签。
  • 确认网络和端点与提交目标匹配。

处理未知摘要的未找到情况

伪造的摘要应产生未找到错误,而不是交易块。这是证明你的解析代码区分真实交易和伪造交易的负面测试。JSON-RPC 2.0 规范定义了方法失败的错误语义,因此对未知摘要的格式良好的请求会返回错误对象,而不是成功负载。

下面的示例包装了 resolve 调用,并为未找到路径打印清晰的消息。使用故意无效的摘要运行它,以确认你的错误处理按预期工作,然后再在生产中依赖它。

import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';

const client = new SuiClient({ url: getFullnodeUrl('mainnet') });

async function tryResolve(digest) {
  try {
    const tx = await client.getTransactionBlock({
      digest,
      options: { showEffects: true },
    });
    console.log('resolved:', tx.digest, 'checkpoint:', tx.checkpoint);
    return tx;
  } catch (err) {
    console.log('not found or error for', digest);
    console.log('message:', err.message);
    return null;
  }
}

// A fabricated digest should not resolve.
tryResolve('0x' + '0'.repeat(64));

供读者验证的测量结果表

下表是一个模板,不是一组已发布的数字。请针对你自己的端点和摘要填写它,以便值反映你实际运行的环境。记录摘要、检查点序列、timestampMs、摘要是否出现在检查点交易中以及最终状态。

由于提供商行为因提供商而异,你的表可能与其他人在不同端点上的表不同。这正是重点:该表使差异可见且可复现,而不是断言。将原始响应与表一起保存,以便以后可以重新检查任何行。

  • digest:你解析的完整 base58 交易摘要。
  • checkpoint seq:sui_getTransactionBlock 返回的 checkpoint 字段。
  • timestampMs:随交易块返回的 timestampMs。
  • included-in-checkpoint:是或否,来自核对步骤。
  • status:effects 状态,例如 success 或 failure。
  • endpoint:你查询的 RPC URL,以便行可归因。

限制、权衡和提供商差异

有几个诚实的限制适用。摘要必须是完整的 base58 值;截断或复制错误的摘要将无法解析。选项会改变负载大小和组装响应的成本,因此每次调用都请求所有选项是便利性与开销之间的权衡。对于尚未认证的交易,checkpoint 字段可能为 null,这就是为什么核对步骤很重要,而不是仅信任该字段。

方法可用性因提供商而异。旧版 sui_getCheckpoint 方法被记录为已弃用,推荐使用检查点读取路径,因此在依赖它之前,请对照 Sui 文档验证当前方法名称。这些都不能替代阅读主要来源:Sui JSON-RPC API 参考文档了解方法语义,Sui 检查点概念文档了解承诺语义。

有关通常伴随交易解析的对象级推理,例如版本控制和排序,请参阅 对象版本和 Lamport 排序 一文。

  • 需要完整的 base58 摘要;截断值会失败。
  • 选项会增加负载大小和组装成本。
  • 认证前 checkpoint 可能为 null。
  • 已弃用的方法可能被移除;验证当前名称。
  • 提供商支持各不相同;在你的端点上确认。

排查摘要、检查点和方法错误

摘要未找到是最常见的症状。检查摘要是否为完整的 base58 值,你查询的网络是否为交易提交的网络,以及是否已过去足够时间让检查点包含它。如果它持续超过你的轮询截止时间,请将其视为真正的解析失败,而不是时间问题。

checkpoint 为 null 意味着交易尚未在检查点中认证。不要将 null 检查点视为成功的最终解析;使用有界轮询再次轮询,或稍后核对。错误的方法名称,尤其是围绕已弃用的检查点方法,会产生方法未找到错误;对照 Sui 文档验证当前名称,并确认你的提供商支持它。

对于端点级问题和方法可用性,Sui RPC 指南 和 API 服务 页面是正确的起点。

  • 摘要未找到:验证完整 base58 值、网络和经过时间。
  • checkpoint 为 null:尚未认证;使用有界轮询或稍后核对。
  • 方法名称错误:对照 Sui 文档验证;确认提供商支持。
  • 意外负载:检查你设置了哪些选项。
  • 持续失败:捕获原始 JSON-RPC 错误对象以寻求支持。

后续步骤和相关阅读

有了摘要解析和检查点核对,自然的后续步骤是枚举、流式处理和效果解读。queryTransactionBlocks 游标分页 一文介绍了交易分页,检查点流和账本服务 一文介绍了持续摄取,交易效果和对象变更 一文介绍了如何读取交易做了什么。

有关端点选择和容量规划,请查看 RPC 定价 和 API 服务 概述,并浏览 OnFinality Learn 中心 获取相邻指南。Sui 网络页面 是网络特定详细信息的入口点。

  • 当你需要信息流或回填时,使用游标枚举。
  • 当你需要持续摄取时,流式处理检查点。
  • 解析效果和对象变更以了解结果。
  • 在扩展之前查看定价和 API 服务页面。

永远不用担心基础设施

OnFinality 消除了 DevOps 的繁重工作,让您能够更聪明、更快地构建。

开始