> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tenderly.co/llms.txt
> Use this file to discover all available pages before exploring further.

# State Sync

> 使用 State Sync 让 Virtual Environment 与其父网络实时同步，以读取实时预言机价格、资金池数据和余额。

State Sync 让您的环境与父网络的状态实时同步。这有助于确保您可以访问 Virtual Environment 创建后产生的所有区块。

<Note>
  State Sync 仅在付费计划中可用。要为您的账户启用它，请[联系我们的销售团队](https://tenderly.co/contact-us)。
</Note>

您在创建 Virtual Environment 时通过选择 **State only sync** 网络同步模式启用 State Sync。

<Note>
  网络同步模式在创建时固定，并在 Virtual Environment 的整个生命周期内保持不变。之后无论从仪表板还是 API 都无法启用、禁用或切换。要以其他模式运行，请创建一个新的 Virtual Environment。
</Note>

<Tip>
  需要与父网络逐块对齐并具有可见的内存池？请参见 [Network Mirror Mode](/virtual-environments/network-mirror-mode)，它比 State Sync 提供更强的保证，具有时间控制和用于将您的 Virtual Environment 与 Mainnet 进行比较的状态漂移视图。
</Tip>

<Warning>
  在运行 Virtual Environment 交易时，缓存 `block.number` 的 Mainnet 合约的行为是不可预测的，因为在 Mainnet 和 Virtual Environment 上[区块号的增长速率不同](#how-state-sync-works)。
</Warning>

## 何时激活 State Sync

此选项在以下几种场景中非常有用：

* Virtual Environment 合约和交易可以**访问原始链上存在的当前预言机值**。
* 在测试合约和构建概念验证交易时，从 Virtual Environments 访问 Uniswap 资金池。
* 构建一个没有陈旧数据的 subgraph。
* 在与真实网络条件一一对应的情况下测试您的 dapp 和协议的行为和性能

## State Sync 如何解决写入冲突

State sync 允许您在 Mainnet 上存储槽和账户余额更新时访问它们的最新值。当您在 Virtual Environment 上写入特定存储槽时，该槽的同步会停止，但对所有未修改的槽仍然处于活动状态。

以下是 state sync 的更多细节：

* 初始区块号与创建时原始链的最新区块相匹配。
* 每次您通过 `eth_sendRawTransaction` 和 `eth_sendRawTransaction` 向 Virtual Environment 发送交易时，都会挖掘一个区块，区块号加 1，与原始网络无关。
* *在 Virtual Environment 上写入变量之前*，Virtual Environment 会跟踪来自原始网络的当前值。
* *在 Virtual Environment 上写入合约的变量后*（例如 `C.X=100`），任何后续读取都将产生该值（`100`）。
* 合约的所有*未修改状态变量*（`C.Y`）都将反映来自原始网络的值。
* 在 Virtual Environment 上挖掘新区块之前，最新的虚拟区块会与父链上的最新区块同步。
* Virtual Environment *在每次状态修改后挖掘一个区块*（`sendTransaction`、`setBalance` 等）。
* Virtual Environment 上的区块号和原始网络上的区块号*将以不同的速率变化*。

<img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/testnets/state-sync.png?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=1be8389e63eee964e42290d9f28dafb5" alt="" width="1920" height="1312" data-path="images/testnets/state-sync.png" />

为了更好地理解，让我们探究一个示例：

## 示例

该示例展示了以下内容：

* Virtual Environment（Virtual Sepolia）访问来自原始网络（Sepolia）的最新状态。
* 在一次 Virtual Environment **`write`** 之后，被修改的变量与其 Sepolia 对应变量分离。

您可以在 Github 上找到该示例：

<Card title="State Sync Example" href="" />

该示例使用一个修改版的 [Counter 合约](https://github.com/Tenderly/tenderly-examples/tree/master/virtual-environments-state-sync/contracts/src/Counter.sol)，其中包含一个计数器映射。它部署在 Sepolia 上，地址为 `0xd01dF6d2354c5A869265dC9a9561E3544ac53262`。[测试脚本](https://github.com/Tenderly/tenderly-examples/tree/master/virtual-environments-state-sync/src/index.ts)将同时与 Sepolia 以及一个基于 Sepolia 的 Virtual Environment `Virtual Sepolia` 交互。

该脚本在计数器映射中随机取一个条目，然后：

* 在 Sepolia 上设置该值，然后在 Sepolia 和 Virtual Sepolia 上都读取值，表明可以读回相同的值。
* 在 Virtual Sepolia 上设置该值，然后在 Sepolia 和 Virtual Sepolia 上都读取值，表明读到的是不同的值。
* 再次在 Sepolia 上设置该值，然后在 Sepolia 和 Virtual Sepolia 上都读取值，表明 Sepolia 上的修改对其虚拟对应体不可见。

<Steps>
  ### 创建 Virtual Environment

  基于 Sepolia 创建一个[新的 Virtual Environment](/virtual-environments/quickstart)，使用 `735711155111` 作为自定义 Chain ID。

  ### 环境设置

  复制 `.example.env` 模板并替换以下内容：

  * **`TENDERLY_VIRTUAL_TESTNET_CHAIN_ID`** Virtual Environment 的链 ID。使用 `735711155111`
  * **`TENDERLY_VIRTUAL_TESTNET_RPC_URL_SEPOLIA`** Virtual Environment 的 RPC URL
  * **`PRIVATE_KEY`** 用于签署测试交易

  ```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  cp .example.env .env
  vi .env # modify environment variables
  ```

  ```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  cd virtual-environments-state-sync
  source .env
  yarn install
  npx ts-node src/index.ts
  ```

  ### 结果

  关于 **`write`** 操作需要注意的关键点：

  1. 在写入 Sepolia（`1`）后，Sepolia 和 virtualSepolia 都读取到值 `1` —— 即原始网络的最新状态。
  2. 在写入 Virtual Sepolia（`10`）后，从 Sepolia 读取会得到先前设置的值（`1`），从 virtualSepolia 读取会得到最近设置的值（`10`）。
  3. 再次写入 Sepolia（`100`）后，从 Sepolia 读取会得到最新设置的值（`100`），从 virtualSepolia 读取会得到先前设置的值（`10`）。

  ```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  Playing with Counter(0xd01dF6d2354c5A869265dC9a9561E3544ac53262).numbers[3788720642447205]
  State:
    sepolia: 0
    virtualSepolia: 0

  ================================================================================================
  Write: Counter(0xd01dF6d2354c5A869265dC9a9561E3544ac53262)@Sepolia.numbers[3788720642447205] = 1
  Tx hash: 0xe57c5da70c68d55f86957f7a2fc2644670b032fe5f972b9e9ccc2774cd2ba352
  State:
    sepolia: 1
    virtualSepolia: 1

  ================================================================================================
  Write: Counter(0xd01dF6d2354c5A869265dC9a9561E3544ac53262)@Virtual Sepolia.numbers[3788720642447205] = 10
  Tx hash: 0x56099d89c1d6fd001a1e9a0cecca13e13c04013b473acb6a48cd61a4b988696c
  State:
    sepolia: 1
    virtualSepolia: 10

  ================================================================================================
  Write: Counter(0xd01dF6d2354c5A869265dC9a9561E3544ac53262)@Sepolia.numbers[3788720642447205] = 100
  Tx hash: 0xc3c37e912bfa4fca9b980339fa2c95dbef75d6c605f0df831ca985b0ef3b61ec
  State:
    sepolia: 100
    virtualSepolia: 10
  ```
</Steps>
