---
title: "使用 gas 优化交易扩展 Smurfs' Society"
description: "Smurfs' Society 使用 Alchemy 的 gas 优化交易，在 Polygon 上 gas 价格剧烈波动期间保证交易被打包。"
---

## 与 Alchemy 合作扩展链上交易规模

**作者：** **The Smurfs' Society 团队**

[The Smurfs' Society](https://thesmurfssociety.com/) 是 Smurfs 的官方 web3 项目。该项目是一个仅限邀请的全链上游戏化平台，于 2022 年 12 月上线，不到一个月内产生了超过 30,000 个钱包连接和 150 万笔链上转账，跻身 DappRadar 最常用应用 TOP 100。

在本文中，其 CTO 兼联合创始人探讨了扩展大量链上交易所面临的技术挑战，以及团队如何与 Alchemy 合作，为使用 [Transact API suite](https://www.alchemy.com/transact) 的数万名玩家提供流畅、稳定的用户体验。

## **区块链语境下"可扩展性"的相对性**

我们大多数人（包括我自己）都不会认为每分钟 100 笔交易是个"规模"或"体量"问题。过去，我曾与多家公司合作优化 Cassandra 部署，管理跨多个数据中心、拥有 TB 级数据、要求低延迟高吞吐的集群；那时我从未想过，在处理区块链基础设施时，这么低的交易量反而会难以实现。

这个挑战分为两部分：

1. 我们需要能够物理执行交易
1. 我们需要[确保交易的正确性](https://alchemy.com/blog/data-accuracy)，更准确地说，是其最终数据一致性和准确性。

对于第一个挑战，这和在 k8s 中部署任何具备自动扩缩容能力的平台集群进行容量规划基本相同。一个小的区别在于我们对负载分片的方式：使用 HD wallet 结合 StateFulSet，让每个 pod 直接管理自己的钱包。而且，要记住区块链要求交易必须按顺序执行（针对特定钱包的顺序而言）。

对于第二个挑战，可以想象一笔[交易进入 mempool](https://www.alchemy.com/overviews/transaction-propagation) 但迟迟未被挖出（gas 问题）。

**我们的选择有：**

1. 等待网络降温（如果可能的话），让交易被挖出
1. 用新交易覆盖原交易（强制使用相同 nonce），并提高 gas 设置
1. 直接换一个钱包

显然，在我们的场景中，第 1 种和第 3 种都行不通。所以第 2 种是我们唯一的选择，而这也带来了自身的复杂性。

以下是我们与 Alchemy 合作，从 [Reinforced Transactions](https://www.alchemy.com/docs/reference/mev-protection) 过渡到 [Gas Optimized Transactions](https://www.alchemy.com/docs/reference/mev-protection) 的简要经验分享。

### **在每日挖出 20,000 笔交易的同时最大化正确性**

为什么一个以区块链为核心支柱的应用或游戏，扩展起来会如此困难？

- 我们是否受限于单个区块能挖出的交易数量？
- 我们是否受限于整个网络的容量？
- 我们是否受限于网络拥堵以及特定的日内使用模式？
- 我们是否受限于区块链上交易的执行方式？
- 我们是否受限于 gas 价格的波动？

经过数周的运营，以及对各项控制手段的大量迭代，我们现在拥有了一个能让游戏在最佳条件下运行的平台。

在解释我们为达到这一步所克服的所有障碍之前，让我先介绍一下游戏机制，并从区块链角度概述我们自动化的操作及其挑战。然后我会说明我们如何与 Alchemy 合作解决这些问题。

## **Smurfs 的链上游戏是如何运作的？**

目前的游戏是对传统"等待列表"概念的颠覆：玩家混合原料，尝试找出能制作药水的配方，其中部分药水可以获得晶体（保证以折扣价获得 mint 资格）。

游戏中使用的所有资产都以 NFT 形式表示。对于我们认为可替代、可消耗的物品（例如原料、药水、蓝色黏土、小雕像等），使用 ERC-1155 代币；对于不可替代的物品（例如晶体），使用 ERC-721 代币。

### Smurfs 游戏的交互

以下是我们平台为让游戏运行而与 Polygon 网络进行的交互：

1. **领取由原料组成的掉落箱** - 玩家每天都可以领取包含 3 种原料的箱子
1. **铸造小雕像（游戏的核心组件）** - 所有玩家都必须拥有一个才能完成游戏中的操作。玩家登录游戏时会免费获得小雕像。雕像的作用会在游戏后续阶段公布。
1. **销毁黏土** - 当玩家尝试的配方失败时，会销毁蓝色黏土（销毁 1 个）

另一方面，玩家在 Polygon 网络上执行一个操作：

1. **混合配方** - 玩家混合 3 种原料来创建配方（此操作的 gas 费由玩家支付）。

<ImageBlock
  src="https://media.alchemy.com/1704556400-player-mixing-a-recipe.png"
  alt="《The Smurfs' Society》游戏画面,展示玩家将三种材料混合成一个配方"
  width={654}
  height={319}
  caption="图 1:玩家混合配方"
/>

对于前两个功能，我们可以完全以异步方式运行，即使某笔交易长时间未被挖出，对游戏本身也没有实际影响。当然，从体验的角度来看，我们希望这个时间尽可能短。

销毁黏土则更有挑战性，其实现方式主要由游戏本身决定。当玩家实际提出一个配方时，他们会对一个包含所有想要用来混合的原料的 EIP-712 结构体进行签名，并设定 3 小时的截止时间，如下图所示。

<ImageBlock
  src="https://media.alchemy.com/1704556456-player-signs-eip-712-to-propose-a-recipe.png"
  alt="图 2:玩家签署 EIP-712 以提交配方"
  width={354}
  height={499}
  caption="图 2:玩家签署 EIP-712 以提交配方"
/>

如果没有找到与该组合对应的配方，这个签名将被用作销毁授权。我们代表玩家执行这笔 burnClay 交易，并承担相应的交易手续费。

**从这里开始，我们需要管理多种状态：**

1. 交易处于传输中 - 存储在链下 -\> 正在转移到链上。用于对账。
1. 交易处于 mempool 中，等待被挖出 - 这是一个过渡状态，需要我们对账：核对我们认为用户正在进行中的操作与实际正在处理的操作之间的差异——而且无法保证需要多长时间
1. 交易已被挖出 - 屏幕上显示的蓝色黏土数量现已准确。这是最终状态，不构成任何挑战——区块链即为真实来源
1. 交易已被挖出但被视为已中止

### 为什么 Smurfs 团队选择了 Polygon

在理想情况下，我们希望所有状态都能在 1 分钟以内收敛，以保证操作的正确性和游戏体验。针对这个使用场景，我们决定在游戏化阶段使用 Polygon 网络。以下是帮助我们[选择 Polygon 作为网络](https://www.alchemy.com/polygon)的一些重要标准：

- 快速的最终确认时间，保证反应速度
- 较低的交易费用，便于控制运营成本
- 与 Ethereum 的互操作性，支持长期规划

**我们面临的挑战：在每日挖出 20,000 笔交易的同时最大化一致性**

<VideoCta
  title="查看 Alchemy 控制台实际运行效果"
  description="30 分钟引导演示:现场演示控制台中的每一项工具。"
  ctaHref="/resources/dashboard-demo"
  thumbnail={{
    src: "https://media.alchemy.com/alchemy-dashboard-demo-thumbnail.png",
    alt: "Alchemy Dashboard Demo",
  }}
/>


## **在保持高成功率的同时降低 Polygon gas 波动的影响**

Polygon 可能会出现拥堵，这会直接影响我们之前描述的各项操作，导致延迟。我们可以采取一些基本措施来应对：

1. **分片** - 让多个钱包与区块链交互。只要有一个可用钱包（类似数据库的连接池），交易就能正常进行。
1. **提高出价** - 为了保证交易能被及时处理，我们可以提高[优先费（EIP-1559）](https://www.alchemy.com/docs/how-to-send-transactions-on-ethereum)来增加激励。

我们最初的方案是使用 [**Reinforced transaction**](https://www.alchemy.com/docs/reference/mev-protection) 方案，并在 gas 费上高于市场价出价，以优化交易的最终确认时间。

<ImageBlock
  src="https://media.alchemy.com/1704556545-example-of-extreme-gas-prices-on-polygon.png"
  alt="Polygon 上极端 gas 价格的示例。"
  width={558}
  height={199}
  caption="Polygon 上极端 gas 价格的示例。"
/>

<ImageBlock
  src="https://media.alchemy.com/1704556581-example-of-dramatic-gas-price-volatility-on-polygon.png"
  alt="Polygon 上 gas 价格剧烈波动的示例。"
  width={546}
  height={191}
  caption="Polygon 上 gas 价格剧烈波动的示例。"
/>

这两张截图是在几分钟内（约 5 分钟）拍摄的。可以看到在很短的时间内 gas 出现了很大的波动，这对我们造成了直接影响：市场上 gas 价格的任何快速波动，都可能让我们的交易卡在那里，占用我们其中一个钱包！

### 如何在 gas 波动期间优化 Polygon 交易

我们开始着手优化 gas 波动期间的交易处理，具体做法包括：

- 增强应用的韧性，并在更长的时间内更好地追踪交易状态
- 追踪并在出现征兆时发出告警——我们通过追踪消息被处理所需的时间来实现这一点

**当一切在微观层面看起来正常时，我们看到的是这样：**

<ImageBlock
  src="https://media.alchemy.com/1704556646-processing-time-that-varies-but-below-20-second-mark.png"
  alt="一个健康的处理流程,处理时间有所波动,但保持在 20 秒以内。"
  width={1600}
  height={432}
  caption="一个健康的处理流程,处理时间有所波动,但保持在 20 秒以内。"
/>

**而从宏观层面看，当情况变得更"有意思"时，是这样：**

<ImageBlock
  src="https://media.alchemy.com/1704556694-messages-that-are-older-than-200-seconds.png"
  alt="超过 200 秒的消息示例。"
  width={1600}
  height={436}
  caption="超过 200 秒的消息示例。"
/>

有时，某些消息的滞留时间接近 200 分钟（上面的例子来自我们最艰难的一天）。当这个时间差变得太大时，玩家就会开始察觉到，最明显的标志就是蓝色黏土计数器不再减少。

在我们最糟糕的一天，也就是 Polygon 升级之后，由于部分交易无法被挖出，我们不得不暂停游戏 30 分钟。

自那以后，我们一直在积极与 Alchemy 合作，利用他们的一项新服务来应对这一挑战，并决定加入 [**Gas Optimized transactions**](https://www.alchemy.com/docs/reference/mev-protection) 的 beta 测试。

**Gas Optimized transactions 的核心理念是管理不可预测的异常值。**

想象一下：与其用某种硬编码逻辑来确定 gas 并签署一笔交易，不如签署 5 到 10 笔具有不同 gas 价格条件的交易，然后交由 Alchemy 自动逐步提高 nonce 出价！

在我们的场景中，我们选择了以下递增策略：1.25、1.5、1.75、2、2.25、2.5

到目前为止，我们已经取得了不错的效果。

我们已经成功运行了多项优化措施，并在系统中实际观察到了效果。我们期待与 Alchemy 团队继续合作，也要特别感谢他们在出问题那天的快速响应和高效处理。选对合作伙伴真的很重要！

Smurfily,

The Smurfs' Society 团队。
