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

NEAR Scan:使用浏览器、RPC 和合约验证读取 NEAR 链上数据

一份实用的 NEAR 区块链扫描指南:浏览器展示什么、如何用 RPC 和索引器复现它们的查询,以及如何验证合约源代码。

TL;DR

“NEAR scan”是指从 NEAR Protocol 区块链读取状态和历史的任何工作流程,无论是通过托管浏览器、区块浏览器 API,还是直接调用 JSON-RPC。浏览器对人类来说很方便,但可复现的分析需要底层的 RPC 方法:block、chunk、transaction status、account state 和 contract calls。本文解释了 NEAR 扫描背后的思维模型,提供了可运行的 RPC 流程,展示了如何对照已部署代码验证合约源代码,并涵盖了导致扫描结果看似错误的故障模式。它将已记录的协议行为与建议以及您应自行运行的测量区分开来。

NEAR 扫描实际读取什么

“NEAR scan”一词描述的是从 NEAR Protocol 网络读取数据:区块、分块、交易、收据、账户余额、访问密钥和合约状态。区块浏览器是这些数据之上的 UI。在底层,浏览器和索引器调用 NEAR JSON-RPC 端点,通常辅以它们自己的数据库进行历史聚合和搜索。

这一点很重要,因为浏览器视图是产品决策,而不是协议。如果一笔交易在一个浏览器中缺失,该交易可能仍然在链上最终确定。如果两个工具之间的余额看起来不同,一个可能显示的是流动余额,而另一个包含了质押或锁定的金额。可靠的扫描工作流程从 RPC 响应开始,并将浏览器视为表示层。

范围:本文涵盖 NEAR 主网和测试网数据的只读扫描、合约源代码验证概念以及诊断程序。不涵盖交易、代币价格分析或钱包托管。

  • 浏览器:面向人类的搜索和显示。
  • RPC:面向机器的对规范节点状态的访问。
  • 索引器:基于 RPC 或流数据构建的数据库,用于快速历史查询。
  • 合约验证:将已部署的 Wasm 与从仓库编译的源代码进行比较。

先决条件和假设

您需要一个 NEAR RPC 端点 URL,本文将其称为 RPC_URL。您可以使用公共端点进行轻量测试,但公共端点有速率限制,并且可能滞后。对于重复扫描或生产索引器,请使用托管或专用端点;有关容量如何配置,请参阅多链 RPC 端点指南和 RPC 定价。

您还需要 curl 或脚本运行时,例如 Node.js 或 Python。示例使用 HTTPS 上的 JSON-RPC 2.0,方法名在请求体中。NEAR RPC 方法在 NEAR API 参考中有记录;下面的方法名和参数形状遵循该记录的接口。

假设:您正在扫描公共链数据。不要将私钥发送到 RPC 端点。读取方法不需要签名。

思维模型:区块、分块、交易和收据

NEAR 产生区块。每个区块包含一个或多个分块,每个分块属于一个分片。交易包含在一个分块中,但其效果由收据承载,收据可以在后续区块和不同分片中执行。这就是为什么一笔交易可以显示最终状态,而其收据仍在处理中,以及为什么仅查看交易自身区块的扫描可能会错过下游效果。

账户状态按分片存储。一个账户有余额、锁定金额、存储使用量、代码哈希和访问密钥。合约状态是通过视图调用或状态查询访问的键值存储。当您扫描一个账户时,请确定您需要其中的哪些;一个单一的“余额”数字很少能说明全部情况。

最终性:NEAR 有乐观和最终区块引用。对于不可逆报告,请使用 finality 参数查询,而不是特定区块高度,或等待区块最终确定。浏览器通常会标注这一点,但原始 RPC 响应需要您主动请求。

  • 区块:包含区块头和分块头的容器。
  • 分块:区块中特定分片的部分。
  • 交易:包含在分块中的签名请求。
  • 收据:执行产生的跨合约或跨分片效果。
  • 结果:附加到交易或收据的执行结果。

可运行的扫描:通过 RPC 查询区块、交易和账户

以下 curl 调用使用占位符。将 RPC_URL 替换为您的端点。区块查询请求最新的最终区块。交易查询使用交易哈希和发送方账户,因为 NEAR 的交易状态方法需要两者。账户查询返回余额和存储字段。

按顺序运行这些命令,并将交易响应中的区块高度与您获取的区块高度进行比较。如果交易比您的区块查询更新,请使用 finality 重新查询。

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":"block","method":"block","params":{"finality":"final"}}'

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":"tx","method":"tx","params":{"tx_hash":"TRANSACTION_HASH","sender_account_id":"SENDER.near","wait_until":"FINAL"}}'

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":"acct","method":"query","params":{"request_type":"view_account","finality":"final","account_id":"ACCOUNT.near"}}'

预期验证结果及其解读

成功的区块响应包含一个带有区块头和分块的结果。区块头包括高度、哈希和时间戳。成功的交易响应包含最终执行状态和一个或多个结果收据。成功的账户查询包含 amount、locked、code_hash、storage_usage 和 storage_paid_at。

验证清单:交易包含的区块高度应小于或等于您获取的最终区块高度。对于已完成的调用,交易的最终执行状态应为 SuccessValue 或 SuccessReceiptId。如果是 Failure,响应包含错误对象;在假设扫描损坏之前先阅读它。

对于结果表,为每个查询记录一行,列包括:查询类型、请求 ID、区块高度、最终性、状态和由您的客户端测量的延迟。不要复制其他环境的延迟数字;从您实际将使用的机器和网络路径进行测量。

  • 区块高度单调递增;在较高高度之后出现较低高度表示端点滞后。
  • 交易状态 FINAL 意味着在请求的最终性下交易不可逆。
  • 当合约部署或升级时,账户 code_hash 会变化;使用它来检测升级。

使用 JavaScript 和 Python 进行脚本化扫描

对于重复扫描,将 RPC 调用包装在具有重试和显式最终性的函数中。JavaScript 示例使用 fetch 和一个小型重试循环。Python 示例使用 urllib 并打印紧凑摘要。两者都使用 RPC_URL 和 ACCOUNT_ID 占位符。

保持每次调用的请求 ID 唯一,以便日志可以关联。将 HTTP 429 和 5xx 响应视为可重试并采用退避;将带有代码和消息的 JSON-RPC 错误视为需要检查的应用程序错误。

// scan.mjs
const RPC_URL = process.env.RPC_URL;
const ACCOUNT_ID = process.env.ACCOUNT_ID || 'ACCOUNT.near';

async function rpc(method, params, id) {
  const res = await fetch(RPC_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ jsonrpc: '2.0', id, method, params })
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const json = await res.json();
  if (json.error) throw new Error(`${json.error.code}: ${json.error.message}`);
  return json.result;
}

const block = await rpc('block', { finality: 'final' }, 'b1');
const acct = await rpc('query', {
  request_type: 'view_account', finality: 'final', account_id: ACCOUNT_ID
}, 'a1');
console.log({ height: block.header.height, account: ACCOUNT_ID, amount: acct.amount, code_hash: acct.code_hash });

# scan.py
import json, os, urllib.request
RPC_URL = os.environ['RPC_URL']
ACCOUNT_ID = os.environ.get('ACCOUNT_ID', 'ACCOUNT.near')

def rpc(method, params, req_id):
    body = json.dumps({'jsonrpc': '2.0', 'id': req_id, 'method': method, 'params': params}).encode()
    req = urllib.request.Request(RPC_URL, data=body, headers={'Content-Type': 'application/json'})
    with urllib.request.urlopen(req, timeout=15) as resp:
        data = json.load(resp)
    if 'error' in data:
        raise RuntimeError(data['error'])
    return data['result']

block = rpc('block', {'finality': 'final'}, 'b1')
acct = rpc('query', {'request_type': 'view_account', 'finality': 'final', 'account_id': ACCOUNT_ID}, 'a1')
print({'height': block['header']['height'], 'account': ACCOUNT_ID, 'amount': acct['amount'], 'code_hash': acct['code_hash']})

合约验证:将源代码与已部署的 Wasm 进行比较

合约验证回答的是与交易扫描不同的问题:仓库中的源代码是否编译为当前部署在账户上的 Wasm?提供验证合约功能的浏览器通常会在受控环境中编译提交的源代码,并将生成的 Wasm 哈希或字节码与链上代码哈希进行比较。

您可以在没有浏览器的情况下复现核心检查。通过 RPC 获取账户的 code_hash 和合约代码,然后使用项目文档中记录的相同工具链和构建标志在本地编译仓库。比较哈希。不匹配可能来自不同的编译器版本、不同的功能标志或不同的源代码修订版,而不一定是恶意代码。

已记录的行为:NEAR 账户暴露 code_hash 字段,合约代码可以通过 RPC 检索。确切的编译配方是项目特定的;不要假设通用构建能复现已部署的工件。

  • 在仓库中固定编译器和构建工具的版本。
  • 将源代码提交和构建命令与已部署的代码哈希一起记录。
  • 比较哈希,而不是文件大小,作为主要信号。
  • 将不匹配首先视为可复现性问题,其次才是安全问题。

排查常见的 NEAR 扫描问题

大多数扫描差异属于几类:最终性、分片、索引滞后和表示选择。在假设数据丢失之前,按此顺序逐一排查。

如果找不到交易,请确认哈希和发送方账户。NEAR 的交易状态方法需要发送方,仅凭哈希是不够的。如果交易非常新,请使用 wait_until 设置为 FINAL 查询,或在短暂延迟后重试。

如果工具之间的余额不同,请检查该工具显示的是流动金额、锁定金额还是两者,以及是否包含存储成本。如果合约调用返回意外状态,请确认视图调用使用的区块高度或最终性;在较旧区块的视图可以合理地与当前状态不同。

如果端点返回速率限制或超时错误,请降低并发并添加退避。对于持续扫描,请迁移到专用端点;请参阅专用节点和区块链节点托管指南。

  • 交易缺失:验证哈希加发送方,然后使用最终性重试。
  • 高度滞后:比较两个端点,优先选择更接近最终确定的那个。
  • 视图结果意外:明确固定区块高度或最终性。
  • 频繁 429:降低请求速率或使用托管端点。

基于浏览器的扫描的局限性和权衡

浏览器针对人类查找进行了优化,而不是批量提取。它们可能分页、隐藏内部收据,或以方便但非规范的方式聚合代币转账。它们的历史数据库可能滞后于链尖,其搜索索引可能不覆盖每个账户或合约方法。

直接 RPC 是规范的,但不是数据库。它很好地回答点查询;它不提供跨所有账户的高效全历史搜索。对于分析,将 RPC 与您控制的或您理解其数据模型的索引器配对。对于一次性检查,浏览器通常更快。

成本和可靠性权衡在大规模下很重要。公共端点免费但共享;托管端点花钱但提供可预测的容量。测量您自己的延迟和错误率,而不是依赖已发布的声明。

可靠 NEAR 数据工作流程的后续步骤

首先在每个查询中标准化最终性,然后添加重试和请求 ID。构建一个小型扫描脚本,为您关心的账户记录区块高度、账户代码哈希和交易状态。按计划运行它并存储结果,以便您可以检测随时间的变化。

当您需要生产吞吐量时,通过 OnFinality 的 API 服务选择端点,并查看支持的网络。对于端点选择指导而非实现细节,RPC Assistant 涵盖具体的提供商和网络建议;有关通用框架,请参阅 RPC 端点指南。

最后,记录您的验证配方:编译器版本、构建命令、源代码提交和预期代码哈希。正是这份记录使得 NEAR 扫描在数月后仍可复现。

永远不用担心基础设施

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

开始