跳至内容

Hummingbot Gateway 架构 - 第一部分

cover

作者:Martin Kou

更新(2023 年 2 月): Hummingbot Gateway v2 现已作为独立的 Github 仓库发布:https://github.com/hummingbot/gateway。本文中列出的大部分功能现已实现,我们欢迎社区贡献。

引言

Hummingbot Gateway 是一款使 Hummingbot 能够连接到 Uniswap 等去中心化交易所的软件。

Hummingbot Gateway 是一个独立于 Hummingbot 的软件组件,因为访问去中心化交易所所需的软件库(例如 Uniswap 智能订单路由器)通常不是用 Python 编写的。网关通过向 Hummingbot 提供安全且统一的 API 接口,使其能够访问这些具有不同技术栈的去中心化交易所。该 API 接口也可供其他潜在的网关客户端使用,例如专有交易软件。

在本系列关于 Hummingbot Gateway v2 架构的博客文章中,我们将概述为提升 Gateway v2 至生产级质量而进行的架构变更——以及为何需要这些变更。

历史

gate-img1Hummingbot Gateway 最初于 2020 年中期构想,旨在让 Hummingbot 与 Celo、Balancer 和 Terra 进行交互。尽管当时去中心化交易所的概念已经广为人知,但与如今相比,当时的交易活动仍处于早期阶段。

因此,最初的 Hummingbot Gateway 架构相对简单,并未考虑到现代 DEX(如 Uniswap)中常见的许多故障模式,例如区块链交易卡顿。结果导致原始版本无法满足生产级交易系统对可靠性的要求。

我们决定对 Hummingbot Gateway 架构进行一次重大重构。我们将重新设计后的 Hummingbot Gateway 称为 Gateway v2。

Gateway V2 设计目标

gate-img2Gateway v2 是对原始 Hummingbot Gateway 的重新设计,其设计目标如下:

稳健性与可靠性: 网关在遇到错误和故障时应仍能正常运行;当网关中的某个操作必须失败时,应以优雅的方式失败,而非灾难性地崩溃。

用户体验: 网关应易于设置和配置;一旦完成设置,它应在后台可靠运行,使用户能够专注于交易。

开发者体验: 尽管 gateway v2 的初始版本将内置一些去中心化交易所(DEX)连接器,但我们预计随着时间推移,社区将主导 DEX 连接器的开发、功能请求和缺陷修复。这意味着 gateway v2 应便于社区开发者进行开发和测试。

稳健性与可靠性

gate-img3Hummingbot Gateway 和 Hummingbot 本身在本质上更类似于后端系统而非前端系统。特别是,这些系统处理的交易可能带来重大的财务后果。因此,Hummingbot 网关必须具备与大规模后端系统相同甚至更高的可靠性保障:

  • 高可用性以及对错误的弹性应对能力
  • 良好的测试覆盖率和监控机制
  • 信息安全

错误应对能力

所有依赖其他网络组件的大规模后端系统都会频繁遭遇错误。然而,即使其部分依赖组件发生故障或返回错误,后端系统本身也不应发生灾难性失败。例如,Google 数据中心每天都有数千个硬盘发生物理损坏;但作为整体服务的 Google 并不会因为某周六有一千个硬盘损坏而停止服务。

Hummingbot 及其网关面临类似的挑战,尽管规模较小。交易所 API 和区块链交易经常出现失败,而区块链交易由于系统架构不同于传统的客户端-服务器模式,具有独特的失败模式。然而,Hummingbot 和 Hummingbot 网关的弹性要求是相同的——即便以太坊网络拥堵,或内存池丢弃了你的交易,机器人和网关也不应发生灾难性故障。

Nonce

大多数区块链(包括以太坊及所有基于 EVM 的链)都强制要求交易按顺序执行。这一点通过用户交易中唯一的 nonce(随机数)来实现。具体而言,每个由以太坊地址签名的交易必须拥有唯一且单调递增的 nonce 值。一个地址发出的第一笔交易 nonce 必须为 0,第二笔为 1,依此类推。

网关客户端可能请求 EVM 交易的速度快于区块链网络能够确认和处理的速度。因此,网关不能依赖以太坊节点 API 报告的最后一个 nonce 来创建新交易,否则可能会因重复使用 nonce 而覆盖最近已发送的交易。

在 Hummingbot 网关的原始版本中,所有触发交易的 API 调用都会直接创建新的区块链交易;并且假设底层区块链能够极快地处理这些交易,从 Hummingbot 的角度来看几乎是“即时”完成的。然而,在实际的主网环境中,这两个假设通常并不成立,网络拥堵反而是常态。这种不切实际的假设导致原始网关在以太坊测试网或出块速度快的网络上看似通过测试,但在以太坊主网上却频繁失败。

Gateway v2 将引入以下架构变更,以适配真实世界中以太坊区块链的实际运行方式:

  1. 所有产生交易的 API 都将具备 nonce 意识,以便能够对未确认或卡住的区块链交易进行重试(通过提高 Gas 费)或取消。
  2. 当 Hummingbot 或 gateway 客户端快速批量发送交易时,gateway 将在本地跟踪最新的 nonce,确保新交易使用递增的 nonce 发出,而不是相互覆盖。
  3. 本地 nonce 跟踪管理器会将最新 nonce 存储在一个高速的本地数据库中,以确保在 gateway 崩溃并重启后仍能正确自我恢复。

卡住和被丢弃的交易

如今几乎所有区块链都使用交易费和内存池(mempool)机制来优先选择要打包进新区块的交易。由于矿工或验证者会自动倾向于优先处理手续费更高的交易,因此手续费较低的交易常常会被延迟甚至被丢弃。

这在考虑区块链交易必须串行执行时会引发额外问题。例如,我向以太坊网络发送了 nonce 为 3、4、5 的三笔交易。如果第 3 笔交易卡住了,那么第 4 和第 5 笔交易也必须等待第 3 笔交易处理完成后才能被处理。因此,只要有一笔交易在链上卡住或被丢弃,就可能导致后续所有交易都被阻塞或丢弃。

这种交易语义与常见的服务器 API 调用语义有很大不同。Gateway 的作用正是弥合区块链交易不可靠的语义与传统 API 调用可靠语义之间的差距,使得 API 客户端既可以将部分处理复杂性交由 gateway 处理,也能及时获知并响应交易事件(包括错误和卡顿情况)。

Gateway v2 将进行以下改进,以支持取消或重试卡住的交易:

  1. /poll API 将携带额外的响应字段,用于反映尚未进入内存池的交易、在内存池中卡住的交易,以及已确认的交易。
  2. 新增 /cancel API,允许取消卡住的交易。

所有产生交易的 API(包括 /cancel)都将接受 maxFeePerGas

maxPriorityFeePerGasnonce 参数,以便 Hummingbot 可以使用不同的 Gas 成本重试卡住的交易。

  1. 此外,正如 maxPriorityFeePerGas 参数所暗示的,我们将增加对 EIP-1559 交易的支持。

区块链节点错误

区块链节点的 API 调用(例如所有 ethers.js 调用)可能会失败,最常见的原因是网络中断。面对节点 API 错误时,gateway 应该优雅地失败,而不是灾难性崩溃。同时应在日志中提供有意义的错误信息,使 Hummingbot 用户或独立运行的 gateway 用户能够清楚了解问题所在。

在原始的 Hummingbot gateway 中,来自区块链节点 API 交互的错误通常会产生晦涩难懂的日志,令用户困惑。虽然原始 gateway 在执行区块链操作时确实捕获了错误,但并未明确针对常见错误类别(如节点错误)进行捕获,也没有为此类情况提供易于理解的日志消息。

Gateway v2 将增加对区块链节点错误的测试覆盖率,并改进节点错误情况下的日志记录,确保 Hummingbot 用户能够收到清晰且可操作的错误提示。

节点 API 速率限制

这是一个更具体但同样常见的节点错误场景。Infura 等节点服务设有 API 调用速率限制,一旦超出限制,gateway 客户端将被临时封禁。我们可以采取两个主要措施来减少对区块链节点的 API 调用次数:减少调用数量和加强监控。

最初的 Hummingbot 网关未考虑 Infura 等常见服务的节点 API 调用频率限制,因此超出 API 调用限制并被封禁成为原始 Hummingbot 网关中最常见的错误之一。

网关 v2 将采用以下架构改进,以减少对 Infura 等节点服务的 API 调用次数,并监控随时间推移的 API 调用数量:

  1. 针对 Hummingbot 重复轮询区块链信息的缓存逻辑,可在新区块到达前节省节点 API 调用。
  2. 每 5 分钟监控一次对区块链节点的 API 调用次数的指标,有助于发现 Hummingbot 或网关内部未被察觉的高频率 API 调用行为。

测试覆盖与监控

gate-img4测试用例和监控指标是构建任何具备弹性和可靠性的软件的两个关键方面。通常来说,只有通过测试用例和指标持续衡量软件在不同场景下的行为,我们才能真正提升软件的可靠性。

虽然原始的 Hummingbot 网关包含了一些测试用例,但由于几乎所有测试都仅关注正常情况(happy cases),无法有效揭示问题。结果导致大多数错误路径未被测试,实际测试覆盖率很低。

在接下来的部分中,我们将讨论:(1) 需要测试的内容,(2) 如何构建测试,以及 (3) 应实施哪些类型的监控。

需要测试什么

我们无法从一开始就为每一个逻辑路径实现测试,尤其是在项目初期。因此,明确哪些类型的测试应优先进行及其原因非常重要。

正常用户流程:包括测试 Hummingbot 和网关在正常运行时使用的所有逻辑路径。例如但不限于:获取 gas 成本、获取资产价格、创建订单、查询交易状态等操作的正常流程测试。

常见错误流程:包括测试 Hummingbot 和网关在正常运行过程中常遇到的错误路径。例如但不限于:调用节点 API 时的网络错误、交易未成功上链、ETH 余额不足支付 gas 费用、资产余额不足以创建订单等情况。

回归测试:对于缺陷修复,尤其是涉及代码逻辑问题(而非拼写错误等)的修复,应附带单元测试用例,以确保后续代码变更不会再次引入相同问题。尽管在早期开发阶段这可能看似繁琐,但回归测试能为工程团队节省大量后期重复修复问题的时间。

测试固件(Test fixtures)

除非我们有可靠的方法在测试用例中复现或模拟常见错误流程,否则很难对其进行有效测试。目前尚无可靠方法让区块链持续返回错误——因此模拟是唯一可行方式。这意味着我们需要构建一些测试固件,用于模拟来自区块链或相关库(例如 Uniswap 订单路由)的各种响应。

未来我们可能还需要扩展这些测试固件以覆盖成功场景——原因同样在于区块链操作本质上不可靠,因此也无法保证其不会产生错误。

我们将首先构建一组小型原型单元测试用例,并配备能够模拟失败情况的测试固件。一旦完成,便可基于相同的固件架构编写更多单元测试用例。

监控

仅依靠用户提交的错误报告,并不足以评估复杂后端系统的稳定性。现代系统通常还需要被动监控指标来确保其质量。除了可靠性监控外,这些指标还能帮助我们更好地了解网关在实际使用中的情况,从而为后续产品路线图的制定提供依据。

单元测试覆盖率监控:Gateway v2 在早期阶段的目标是实现 30% 到 40% 的单元测试覆盖率,并随着项目成熟逐步提升至 60% 以上。这与我们在 Hummingbot 项目中采用的测试覆盖率路径相似。

重要逻辑流程的使用和错误指标

这些指标包括错误计数、错误日志,或可能导致错误的其他度量数据(例如前文提到的每 5 分钟节点 API 调用次数)。Gateway v2 将收集匿名遥测数据以跟踪使用情况和错误指标,使得 Hummingbot 团队能够在用户报告漏洞之前就发现新版本中的潜在问题。

遥测功能仅在获得用户同意后才会在 Gateway v2 中启用,且所有收集到的指标数据都将进行匿名化存储。

信息安全

gate-img5由于网关 API 调用通常以明文形式携带钱包私钥,因此在发送任何信息之前,确保网关与网关客户端(包括 Hummingbot)相互认证至关重要。

原始的 Hummingbot 网关已支持双向 SSL 认证,这已在一定程度上防止了恶意软件在传输过程中截取私钥。然而,原始网关对 SSL 私钥密码的保护机制较弱,因此我们将在 Gateway v2 中加强 SSL 私钥相关的安全防护。

以下是 Gateway v2 在信息安全方面将做出的改进:

加强对 SSL 私钥密码的保护

  • Hummingbot 端:密码将使用 Hummingbot 主密码加密,而不是像以前那样以明文形式保存在配置文件中。
  • 网关端:密码将被隔离存放在独立文件中,并设置 UNIX 权限 0600,而非与其他配置混合存放。这种做法类似于 Web 服务器中保护 SSL 私钥密码的标准方式。

消除在网关 API 调用中传递钱包私钥的需求

  • 我们将最终迁移到使用 Hummingbot 与 Gateway v2 共享的加密钱包文件,而不是通过 API 请求传递钱包私钥。该功能将在 Gateway v2 首次公开发布后的后续版本中推出。
  • 由于加密钱包文件仍依赖密码,因此上述第 1 点中提到的密码安全机制仍将适用。

结论

至此,Hummingbot Gateway v2 架构系列博客的第一部分结束。本文讨论了我们在 Gateway v2 的健壮性和可靠性方面的改进目标。我们的最终目标是将其打造为可用于构建高价值加密交易系统的生产级软件。

在本系列的下一部分中,我们将探讨 Gateway v2 在用户体验和开发者体验方面的优化计划。

参见本文的第二部分