Saltar al contenido
TrautsLablab

Ejecutable local con Anvil

Depurar JSON-RPC con cast

Hacer llamadas JSON-RPC con Cast y clasificar cada error en su capa: transporte, JSON-RPC o EVM.

Duración
20–35 min
Nivel
Base práctica Ethereum
Pasos
3
Versión
3.29.0-alpha.1

Modelo mental

Un error de "RPC" puede venir de tres lugares distintos: no llegaste al nodo, el nodo no entendió la petición, o la EVM ejecutó y revirtió. Cada capa pide un arreglo diferente.

  1. 1Preflight
  2. 2Anvil
  3. 3Lecturas
  4. 4Errores por capa
  5. 5Reporte

Antes de empezar

  • Foundry instalado: anvil y cast en el PATH (https://getfoundry.sh).
  • Node.js 20 o superior para el preflight.
  • Puerto local 8545 libre.

Pasos

  1. Paso 1Preflight y Anvil

    Asegurar que las herramientas existen y que el RPC es local.

    Preflight
    node tools/labs/ethereum-rpc-cast-debugging/preflight.mjs
    Terminal A: Anvil
    anvil --host 127.0.0.1 --port 8545 --chain-id 31337

    Comprueba

    • — El JSON del preflight muestra available: true para anvil y cast, rpcSafe: true y port8545Free: true.
    • — Anvil queda escuchando en 127.0.0.1:8545.

    Evidencia esperada

    JSON del preflight.

  2. Paso 2Lecturas básicas

    Ver la respuesta cruda de un método JSON-RPC, no solo la versión formateada.

    Terminal B
    export RPC_URL="http://127.0.0.1:8545"
    cast chain-id --rpc-url $RPC_URL
    cast block-number --rpc-url $RPC_URL
    cast rpc eth_getBlockByNumber latest false --rpc-url $RPC_URL
    cast rpc eth_chainId --rpc-url $RPC_URL

    Comprueba

    • — chain-id devuelve 31337 y eth_chainId devuelve "0x7a69", el mismo número en hexadecimal.
    • — eth_getBlockByNumber devuelve un JSON con hash, parentHash, stateRoot y transactionsRoot.

    Evidencia esperada

    Salida de las cuatro llamadas.

  3. Paso 3Provocar un error por capa

    Aprender a leer el mensaje y asignar la responsabilidad correcta.

    Transporte
    cast block-number --rpc-url http://127.0.0.1:8546
    JSON-RPC
    cast rpc eth_foo --rpc-url $RPC_URL
    EVM
    cast rpc eth_call '{"data":"0x60006000fd"}' latest --rpc-url $RPC_URL

    Comprueba

    • — Transporte: "Connection refused (os error 111)"; nunca llegó al nodo.
    • — JSON-RPC: "error code -32601: Method not found"; el nodo respondió pero no conoce el método.
    • — EVM: "error code 3: execution reverted"; el código 0x60006000fd (PUSH1 0, PUSH1 0, REVERT) se ejecutó y revirtió.

    Evidencia esperada

    Tabla con endpoint, método, parámetros, error y capa responsable para cada caso.

El código del laboratorio

Estos son los archivos que ejecutan los pasos, tal como están en el repositorio .

tools/labs/ethereum-rpc-cast-debugging/runbook.md
# Ethereum RPC + Cast debugging

Version: `2.0.44-alpha.1`

## Boundary

Use only `http://127.0.0.1:8545` with an ephemeral Anvil instance. Never paste a personal private key or public RPC credential.

## Start

```powershell
node tools/labs/ethereum-rpc-cast-debugging/preflight.mjs
anvil --host 127.0.0.1 --port 8545 --chain-id 31337
```

In a second terminal:

```powershell
$env:RPC_URL="http://127.0.0.1:8545"
cast chain-id --rpc-url $env:RPC_URL
cast block-number --rpc-url $env:RPC_URL
cast rpc eth_getBlockByNumber latest false --rpc-url $env:RPC_URL
```

Bash equivalent:

```bash
export RPC_URL="http://127.0.0.1:8545"
cast chain-id --rpc-url $RPC_URL
cast block-number --rpc-url $RPC_URL
cast rpc eth_getBlockByNumber latest false --rpc-url $RPC_URL
```

Then provoke one failure per layer:

```bash
cast block-number --rpc-url http://127.0.0.1:8546            # transport: Connection refused
cast rpc eth_foo --rpc-url $RPC_URL                           # JSON-RPC: -32601 Method not found
cast rpc eth_call '{"data":"0x60006000fd"}' latest --rpc-url $RPC_URL   # EVM: code 3 execution reverted
```

Record endpoint, method, parameters, result or error, and the layer responsible: transport, JSON-RPC, or EVM.

## Cleanup

Stop Anvil with `Ctrl+C` and remove `RPC_URL` from the environment (`unset RPC_URL` in Bash).
tools/labs/ethereum-rpc-cast-debugging/preflight.mjs
import { spawnSync } from 'node:child_process';
import net from 'node:net';

const commands = ['anvil', 'cast'];
const versions = Object.fromEntries(
  commands.map((command) => {
    const result = spawnSync(command, ['--version'], { encoding: 'utf8' });
    return [command, { available: result.status === 0, version: (result.stdout || result.stderr || result.error?.message || '').trim().split('\n')[0] }];
  })
);

const rpcUrl = process.env.RPC_URL ?? '';
const rpcSafe = !rpcUrl || /^https?:\/\/(127\.0\.0\.1|localhost)(:\d+)?\/?$/i.test(rpcUrl);
const portFree = await new Promise((resolve) => {
  const server = net.createServer();
  server.once('error', () => resolve(false));
  server.listen(8545, '127.0.0.1', () => server.close(() => resolve(true)));
});

const report = { versions, rpcUrl: rpcUrl || '(unset)', rpcSafe, port8545Free: portFree };
console.log(JSON.stringify(report, null, 2));

if (commands.some((command) => !versions[command].available) || !rpcSafe) process.exit(1);

Criterios de aceptación

  • Las lecturas responden con chainId 31337.
  • Cada uno de los tres errores queda asignado a la capa correcta.
  • Anvil quedó detenido y RPC_URL eliminado.

Limpieza

Variables
unset RPC_URL

Anvil: Ctrl+C en la terminal A.

Si algo falla

Síntoma, causa probable y cómo corregirlo
SíntomaCausaQué hacer
El preflight termina con código 1 y rpcSafe: falseRPC_URL apunta a un host que no es 127.0.0.1 ni localhost.Ejecuta unset RPC_URL o apúntalo a http://127.0.0.1:8545.
port8545Free: falseYa hay un Anvil corriendo.Es válido si es tu Anvil; si no, ciérralo antes de empezar.
El caso de transporte no fallaHay otro servicio escuchando en 8546.Usa otro puerto cerrado para el ejemplo.