Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
集成与开发阅读约 11 分钟

加密网关架构:可靠地接受链上支付

一份实用的工程指南,介绍加密网关如何检测、确认和结算链上支付,包含可运行的检查与故障模式诊断。

TL;DR

加密网关是监控区块链上入账转账、判断支付何时足够最终可入账,并向你的订单系统下发结算指令的软件层。难点不在于结账按钮,而在于地址派生、事件检测、重组处理和幂等入账。本文解释心智模型,演示一套可运行的检测与验证流程,并说明如何诊断最常见的集成故障。它将有文档记录的链行为与你必须做出的选择以及必须在自有技术栈上运行的测量区分开来。

范围与直接答案

加密网关是链上价值的支付处理器:它生成存款地址或发票,监控链上匹配的转账,应用确认策略,并向商户报告已结算的支付。部分网关还会转换为稳定币或法币并处理出款,但不可削减的核心是检测、最终性策略与对账。

本文涵盖工程侧:检测如何工作、如何集成而不重复入账,以及如何验证你的网关确实看到了链上发生的事。提供商选择和端点选择在此有意不在范围内;具体端点推荐请使用 RPC Assistant,网络层面的背景请参阅多链 RPC 端点指南。

  • 范围内:地址派生、事件检测、确认深度、重组处理、幂等性、对账。
  • 范围外:许可、卡收单、税务处理和供应商定价。
  • 假设:你控制一个订单系统,并且可以调用 RPC 端点或网关 API。

先决条件与假设

以下流程假设你拥有目标链的 RPC 端点、一个对交易标识符有唯一约束的数据库,以及一个可以轮询或订阅的任务运行器。它们还假设你将网关视为不可信输入:每一笔入账支付都应能独立对照链上数据验证。

如果你运行自己的基础设施,专用节点可以消除日志查询中的吵闹邻居效应;请参阅专用节点选项。如果你依赖托管端点,在设计回填之前确认其速率限制和归档深度,并查看 RPC 定价,以免轮询频率成为意外成本。

心智模型:发票、监视器、账本

将网关分为三个组件。发票服务创建支付意图,包含金额、资产、到期时间和存款地址。监视器读取区块并提取触及你活跃地址集合中任一地址的转账。账本记录每笔支付的状态机:已创建、已看到、已确认、已入账或已过期。

监视器绝不应直接写入账本的已入账状态。它发出观察结果;单独的策略步骤决定观察结果是否满足确认规则。这种拆分让你无需重写检测即可按资产更改确认深度,并使重放历史变得安全。

地址策略很重要。每张发票使用唯一地址使匹配变得简单,但会成倍增加密钥管理。共享地址需要按金额和备注匹配,当两个客户支付相同金额时很脆弱。大多数生产网关使用 HD 派生的唯一地址,并将派生索引与发票一起存储。

  • 发票服务:意图、金额、资产、到期时间、地址。
  • 监视器:区块扫描或日志订阅,按活跃地址过滤。
  • 策略:确认深度、价值容差、重组响应。
  • 账本:以链上交易哈希和日志索引为键的幂等状态转换。

检测机制:区块、日志与原生转账

EVM 链上的代币转账通常以事件日志形式出现,因此监视器可以按代币合约和转账主题过滤,而不必扫描每笔交易。原生转账不发出日志,因此需要区块级检查或返回余额变化的提供商方法。在没有日志的账户型链上,你通常需要对比余额或使用节点的交易索引。

轮询比订阅更易于运维,也更容易实现可恢复:存储最后完全处理的区块号并从那里继续。订阅降低延迟,但必须视为提示,因为连接断开会静默丢失事件。稳健的设计使用订阅来提速,并定期进行区块范围扫描以确保完整性。

curl -s RPC_URL \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "0x0",
      "toBlock": "latest",
      "address": "TOKEN_CONTRACT_ADDRESS",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        null,
        "0x000000000000000000000000YOUR_DEPOSIT_ADDRESS"
      ]
    }]
  }'

单笔支付的可运行验证

在信任任何网关 webhook 之前,请自行验证底层交易。下面的脚本获取交易及其收据,检查收款人和金额,并打印结论。替换占位符;切勿提交真实密钥。

针对网关声称使用的同一条链运行它。网关报告的网络与你的 RPC 返回的链不匹配,是幽灵入账最常见的原因之一。

import json, urllib.request

RPC_URL = "RPC_URL"
TX_HASH = "0xTRANSACTION_HASH"
EXPECTED_TO = "0xDEPOSIT_ADDRESS".lower()
EXPECTED_WEI = 10**16  # 0.01 native unit

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

tx = rpc("eth_getTransactionByHash", [TX_HASH])
receipt = rpc("eth_getTransactionReceipt", [TX_HASH])

if tx is None or receipt is None:
    print("NOT_FOUND: gateway may be reporting a different chain")
else:
    ok_to = (tx.get("to") or "").lower() == EXPECTED_TO
    ok_value = int(tx["value"], 16) >= EXPECTED_WEI
    ok_status = int(receipt["status"], 16) == 1
    print({"to_ok": ok_to, "value_ok": ok_value, "success": ok_status,
           "block": int(receipt["blockNumber"], 16)})

确认策略与重组处理

确认计数是风险调节旋钮,而非保证。正确的深度取决于链上观察到的重组行为、涉及的价值以及你对延迟履约的容忍度。有文档记录的最终性规则因网络而异:一些链暴露显式的 finalized 区块标签,另一些则依赖概率深度。在存在显式标签的地方使用它,在不存在的地方使用测量出的深度。

当重组使先前看到的转账失效时,你的账本必须能够将支付从已确认回退到已看到。这意味着入账在最终性阈值之前应可逆,或者履约应延迟到阈值跨越之后。绝不要删除观察结果;追加更正,以便审计可以重建发生了什么。

  • 为每个观察结果存储区块哈希,以便检测父块变化。
  • 在同一高度哈希不匹配时,回退到最后一个共同祖先并重新扫描。
  • 在配置中而非代码中维护按资产的确认表。
  • 记录产生每个入账决策的策略版本。

幂等性与对账

网关会重试 webhook,链上偶尔会通过订阅和扫描同时暴露同一笔转账。唯一持久的防御是在观察表中对 (chain_id, tx_hash, log_index) 设置唯一约束,外加一个拒绝非法转换的状态机。webhook 处理器应查找观察结果,而不是创建新的入账。

对账是一个计划任务,将你的账本与链上状态进行比较,针对所有超过阈值且处于非终态的支付。输出是你审查的表,而不是自动变更。有用的对账报告每笔支付一行,列包括网关状态、链上状态、确认深度以及预期值与观察值之间的差异。

CREATE TABLE observations (
  chain_id      INTEGER NOT NULL,
  tx_hash       TEXT    NOT NULL,
  log_index     INTEGER NOT NULL,
  invoice_id    TEXT    NOT NULL,
  block_number  BIGINT  NOT NULL,
  block_hash    TEXT    NOT NULL,
  value_wei     NUMERIC NOT NULL,
  seen_at       TIMESTAMPTZ NOT NULL DEFAULT now(),
  PRIMARY KEY (chain_id, tx_hash, log_index)
);

INSERT INTO observations (chain_id, tx_hash, log_index, invoice_id, block_number, block_hash, value_wei)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (chain_id, tx_hash, log_index) DO NOTHING;

用于自有测量的结果表流程

不要从博客文章(包括本文)采用确认深度。要测量它们。对你接受的每种资产运行以下流程,并将结果记录在包含这些列的表:资产、链、观察窗口、在深度 N 观察到的重组、在深度 N+1 观察到的重组、达到深度 N 的中位时间、达到深度 N 的 p95 时间。

流程:(1) 运行一个监视器,至少 30 天按高度存储区块哈希;(2) 每晚将存储的哈希与规范链比较,并按深度统计不匹配;(3) 从区块时间戳计算达到深度的时间;(4) 选择在窗口内观察到的重组为零的最小深度,然后为价值层级增加余量。内部发布该表并每季度重新审视。数字是你的;方法是交付物。

常见网关故障排查

大多数事件属于少数几种模式。按顺序处理它们,因为链不匹配会使所有下游检查失效。

如果网关报告了你的 RPC 找不到的支付,先确认链 ID,再确认交易哈希格式。如果支付存在但收款人不同,检查网关是否使用了转发合约。如果金额不足,检查发送方是否在可能这样做的链上从转账金额中支付了网络费用。如果支付被重复入账,检查 webhook 处理器是否缺少唯一约束,而不是责怪网关。

  • 链不匹配:比较双方的 eth_chainId。
  • 日志缺失:确认代币合约地址和主题哈希。
  • 监视器停滞:将存储的最后处理区块与链头比较。
  • 速率限制:按区块范围批量查询日志,并对 429 响应退避。
  • 时钟偏差:在假设延迟之前,将网关时间戳与区块时间戳比较。

局限性与权衡

唯一地址改善匹配,但如果使用转发合约,会增加密钥管理面和链上部署成本。共享地址降低成本,但将复杂性推给金额匹配和备注。轮询更简单且可恢复,但增加延迟;订阅更快,但需要完整性扫描。托管转换消除波动性,但增加交易对手和监管风险。

还有一个测量注意事项:监视器的延迟受你的 RPC 提供商的链头滞后限制,你无法控制这一点,且它随网络负载变化。将观察到的延迟视为整个路径的属性,而不仅仅是网关的。关于端点级可靠性特征,请咨询 RPC Assistant,而不是假设各提供商行为一致。

后续步骤

先进行观测再优化:记录每个观察结果的区块哈希和策略版本,然后运行对账任务两周并审查报告。一旦基线稳定,使用你自己的表按资产调整确认深度,然后才考虑订阅等延迟改进。

关于基础设施方面,请查看区块链节点托管如何工作和 RPC 端点指南,以使你的监视器与可靠的数据源对齐。如果你在托管和自建基础设施之间选择,API 服务概览和网络列表描述了每条链可用的内容。关于给定网络使用哪个端点的具体问题,请询问 RPC Assistant;该决策因提供商而异,不在本方法论的范围内。

永远不用担心基础设施

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

开始