> ## 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.

# Block context and routing

> How a request states “which block's state” it wants: the Equals and Contains semantics of blockCtx, the block parameter of standard eth_* methods, and the rules nodex-proxy uses to route among State, Archive, and Native nodes.

Different query nodes keep different ranges of state, so every request has to answer one question: **which block's state do you want?** The answer is called the **block context**. leafage-evm uses it to pick the state layer to execute on; nodex-proxy uses it to pick the node pool to send the request to.

## Two semantics: Equals and Contains

Methods in the DeBank namespace (`contractMultiCall`, `estimateGas`, `getAddressBalance`, and so on) accept an optional `blockCtx` parameter:

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

| `type`     | Semantics                                  | leafage-evm behavior                                          | nodex-proxy routing                                                                      |
| ---------- | ------------------------------------------ | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `Equals`   | Exactly the state of block `block_id`      | Executes on that block's state layer; errors if it is missing | Chooses State or Archive by the distance between `block_id` and the confirmed chain head |
| `Contains` | Any state that already includes `block_id` | Executes on `latest` state directly                           | Always chooses a State node                                                              |

`Contains` fits cases where "the data just must not be older than some height", such as reading a configuration slot that rarely changes. `Equals` fits cases that need reproducible results, such as reconciliation and historical lookups.

Omitting `blockCtx` is the same as `{ "block_id": "latest", "type": "Equals" }`.

### Forms of `block_id`

| Form       | Example                  |
| ---------- | ------------------------ |
| Tag        | `"latest"`, `"earliest"` |
| Hex height | `"0x1406f40"`            |
| Block hash | `"0x9b83…"` (32 bytes)   |

## Block parameters of standard `eth_*` methods

Methods such as `eth_call` and `eth_getBalance` keep Ethereum's block parameter (`"latest"`, a hex height, or `{"blockHash": …}`). leafage-evm treats them with `Equals` semantics: the request executes on the state of exactly the height it names.

nodex-proxy parses only `blockCtx`-shaped objects as block context; the block parameter of `eth_*` methods does not take part in pool selection. Such requests go to a State node first, and when the State node returns `-39006` the proxy re-sends them to an Archive node. To skip that hop, say so explicitly in a request header:

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

## Routing rules

nodex-proxy first picks a node pool by block context, then picks a node inside the pool by weight or round robin. The chain head height comes from etcd's `{chainID}[/{version}]/lastBlockNumber`, the **confirmed height** written by consistency-checker.

| Block context                               | Node pool |
| ------------------------------------------- | --------- |
| `Equals` + `latest` / `pending`             | State     |
| `Equals` + height ≥ confirmed head − 64     | State     |
| `Equals` + height \< confirmed head − 64    | Archive   |
| `Equals` + height, chain head unknown       | Archive   |
| `Contains`                                  | State     |
| No parseable context (`eth_*` methods)      | State     |
| Request header `x-nodex-node-type: archive` | Archive   |
| Previous attempt returned `-39008`          | Native    |

The two pools back each other up: an empty State pool falls back to the Archive pool and vice versa. Chains with only one pool skip context parsing entirely.

<Note>
  The proxy's "64" is hard-coded, while the query node's window is set by `--diff-depth-limit`, whose default happens to be 64 as well. Shrinking the query node window without touching the proxy makes some requests that belong on Archive fail once on a State node first.
</Note>

## Error-code-driven fallback

Three error codes translate "this node does not have that state" into routing actions:

| Code     | Name                    | Returned by          | Meaning                                                                                                                    | Proxy action                                           |
| -------- | ----------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `-39006` | `BlockNotFound`         | State node           | The requested height has left the in-memory window                                                                         | Retry once on an Archive node                          |
| `-39007` | `InvalidBlockID`        | Archive node         | The block does not exist on this node, for example the height is not reached yet or the hash is not on the canonical chain | No retry; returned as is                               |
| `-39008` | `UnsupportedPrecompile` | State / Archive node | The call touches a precompile that needs the original chain                                                                | Retry on a Native node, with the path rewritten to `/` |

A request already on an Archive node is not retried again. Clients that talk to leafage-evm directly have to handle these three codes themselves.

## Summary

* The **block context** answers "which block's state", with two semantics, `Equals` (exact) and `Contains` (no older than); omitting it means `latest`.
* `Contains` always runs on `latest` state on the leafage-evm side and always goes to a State node on the proxy side.
* The block parameter of `eth_*` methods does not take part in pool selection; `-39006` triggers the fallback to Archive, and `x-nodex-node-type: archive` forces it.
* The routing threshold is measured from the **confirmed height** in etcd, with the boundary 64 blocks behind it.

Continue reading:

* [Sending RPC requests](/en/guides/rpc-requests): complete request examples with `blockCtx`.
* [nodex-proxy component documentation](/en/components/nodex-proxy#node-selection): load-balancing strategies and method-level routing.
* [RPC reference](/en/reference/rpc#error-codes): the full error code table.
