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

# 区块上下文与路由

> 请求如何声明“要哪个区块的状态”：blockCtx 的 Equals 与 Contains 语义、标准 eth_* 方法的区块参数，以及 nodex-proxy 据此在 State、Archive、Native 节点之间路由的规则。

不同查询节点保留的状态范围不同，所以每个请求都要回答一个问题：**你要的是哪个区块的状态？** 这个答案叫**区块上下文**。leafage-evm 用它决定在哪一层状态上执行，nodex-proxy 用它决定把请求发给哪个节点池。

## 两种语义：Equals 与 Contains

DeBank 命名空间的方法（`contractMultiCall`、`estimateGas`、`getAddressBalance` 等）接受一个可选的 `blockCtx` 参数：

```json theme={null}
{ "block_id": "latest", "type": "Equals" }
```

| `type`     | 语义                        | leafage-evm 的行为    | nodex-proxy 的路由                         |
| ---------- | ------------------------- | ------------------ | --------------------------------------- |
| `Equals`   | 精确要 `block_id` 这个区块的状态    | 在该区块的状态层上执行；没有则报错  | 按 `block_id` 与已确认链头的距离选 State 或 Archive |
| `Contains` | 任何已经包含了 `block_id` 的状态都可以 | 直接在 `latest` 状态上执行 | 始终选 State 节点                            |

`Contains` 适合“数据不比某个高度旧就行”的场景，例如读取一个很久没变过的配置槽位。`Equals` 适合需要可复现结果的场景，例如对账和历史回溯。

省略 `blockCtx` 等同于 `{ "block_id": "latest", "type": "Equals" }`。

### `block_id` 的写法

| 写法     | 示例                      |
| ------ | ----------------------- |
| 标签     | `"latest"`、`"earliest"` |
| 十六进制高度 | `"0x1406f40"`           |
| 区块哈希   | `"0x9b83…"`（32 字节）      |

## 标准 `eth_*` 方法的区块参数

`eth_call`、`eth_getBalance` 这类方法沿用以太坊的区块参数（`"latest"`、十六进制高度或 `{"blockHash": …}`）。leafage-evm 按 `Equals` 语义处理它们：请求哪个高度就在哪个高度的状态上执行。

nodex-proxy 只把 `blockCtx` 形式的对象解析为区块上下文，`eth_*` 方法的区块参数不参与选池。这类请求先发往 State 节点，State 节点返回 `-39006` 时再由 proxy 改发 Archive 节点。要跳过这一跳，在请求头里显式指定：

```text theme={null}
x-nodex-node-type: archive
```

## 路由规则

nodex-proxy 先按区块上下文选节点池，再在池内按权重或轮询选具体节点。链头高度来自 etcd 的 `{chainID}[/{version}]/lastBlockNumber`，即 consistency-checker 写入的**已确认高度**。

| 区块上下文                            | 节点池     |
| -------------------------------- | ------- |
| `Equals` + `latest` / `pending`  | State   |
| `Equals` + 高度 ≥ 已确认链头 − 64       | State   |
| `Equals` + 高度 \< 已确认链头 − 64      | Archive |
| `Equals` + 高度，但链头未知              | Archive |
| `Contains`                       | State   |
| 没有可解析的上下文（`eth_*` 方法）            | State   |
| 请求头 `x-nodex-node-type: archive` | Archive |
| 上一次尝试返回 `-39008`                 | Native  |

两个池互为兜底：State 池为空时用 Archive 池，反之亦然。只有一个池的链会跳过上下文解析。

<Note>
  proxy 侧的“64”是硬编码，leafage-evm 侧的窗口由 `--diff-depth-limit` 控制，默认值恰好也是 64。把查询节点的窗口调小而 proxy 不变，会让一部分本该去 Archive 的请求先在 State 节点上失败一次。
</Note>

## 错误码驱动的兜底

三个错误码把“节点没有这份状态”翻译成路由动作：

| 错误码      | 名称                      | 谁返回                | 含义                         | proxy 的动作                |
| -------- | ----------------------- | ------------------ | -------------------------- | ------------------------ |
| `-39006` | `BlockNotFound`         | State 节点           | 请求的高度已离开内存窗口               | 改选 Archive 节点重试一次        |
| `-39007` | `InvalidBlockID`        | Archive 节点         | 该区块在本节点不存在，例如高度未到或哈希不在规范链上 | 不重试，原样返回                 |
| `-39008` | `UnsupportedPrecompile` | State / Archive 节点 | 调用触及需要原链能力的预编译             | 改选 Native 节点重试，路径改写为 `/` |

已经在 Archive 节点上的请求不会再次重试。直连 leafage-evm 的客户端需要自己处理这三个错误码。

## 小结

* **区块上下文**回答“要哪个区块的状态”，有 `Equals`（精确）和 `Contains`（不早于即可）两种语义，省略即 `latest`。
* `Contains` 在 leafage-evm 侧永远走 `latest` 状态，在 proxy 侧永远走 State 节点。
* `eth_*` 方法的区块参数不参与选池，靠 `-39006` 回退到 Archive；`x-nodex-node-type: archive` 可以强制。
* 路由阈值以 etcd 中的**已确认高度**为基准，前后 64 块分界。

继续阅读：

* [发送 RPC 请求](/guides/rpc-requests)：带 `blockCtx` 的完整请求示例。
* [nodex-proxy 组件文档](/components/nodex-proxy#节点选择)：负载均衡策略与方法级路由。
* [RPC 参考](/reference/rpc#错误码)：完整错误码表。
