Para desenvolvedores / JSON-RPC

Histórico e retenção

O nó é um índice RPC, não um arquivo. Ele guarda mais ou menos dois minutos de blocos, e uma consulta além disso responde null em vez de dar erro - é por isso que esta página existe antes de você escrever um indexador, e não depois.

O que o nó conserva

DadoConservado
EVM block history~2 minuteskeep_evm_blocks() = 120,000 / EVM_BLOCK_MS - 480 blocks at the default. Older blocks return null and their logs become unqueryable
Mini-block history20,000KEEP_MINI_BLOCKS, roughly 200 seconds at the 10 ms scheduling target
Receipts and bodies200,000MAX_RECEIPTS, evicted first-in-first-out
Full historynot on the nodeit lives in Postgres behind the explorer, fed by the sequencer's spool. This RPC is an index, not an archive

A janela de blocos é derivada e não fixa: keep_evm_blocks() = 120_000 / EVM_BLOCK_MS, ou seja 480 blocos na cadência padrão. Os logs são despejados junto com o seu bloco. Os recibos e os corpos das transações têm o próprio teto primeiro-a-entrar-primeiro-a-sair e podem sumir antes do bloco deles.

As leituras são servidas a partir de um instantâneo publicado em cópia-sob-escrita e nunca tomam a trava de execução, e é por isso que um eth_call lento não consegue travar a produção de blocos e um bloco travado não consegue travar as leituras. É o desenho que torna a janela aceitável: o nó otimiza para servir o presente rápido, e entrega o histórico a algo construído para isso.

Como isso falha

Fora da janela você recebe null, não um erro

eth_getTransactionReceipt, eth_getTransactionByHash e toda busca de bloco respondem null para o que foi despejado. Nada distingue "nunca existiu" de "existiu e foi removido".

Três padrões que parecem corretos e não são:

  • Sondar um recibo com um recuo longo. Espere o bastante entre as tentativas e o recibo pode ser despejado entre duas sondagens. Ele existe cerca de 10 ms depois do envio - sonde cedo e com frequência, não com paciência.
  • Recuperar o histórico a partir do bloco 0. earliest é o bloco conservado mais antigo, e ele avança enquanto você trabalha. Um laço de recuperação que corre atrás dele nunca alcança um ponto de partida fixo.
  • Reconciliar um registro toda noite. Quando um trabalho noturno rodar, todos os blocos que ele queria já sumiram.

O que fazer no lugar

O histórico completo existe - ele é transmitido do sequenciador para o Postgres atrás do explorador, que é construído para ser um arquivo. Então:

  • Para o presente - os últimos segundos - use o nó. As inscrições e o eth_getLogs sobre um intervalo estreito são aquilo em que ele é rápido.
  • Para o passado, leia o explorador. Ele também tem os rastros de chamadas, que o nó não expõe de forma alguma, já que não há espaço de nomes debug.
  • Para manter o seu próprio histórico, inscreva-se e persista à medida que os eventos chegam, em vez de pedi-los mais tarde. O fluxo de miniblocos é a fonte de maior fidelidade; um manipulador lento é expulso dele, então empurre para uma fila e processe em outro lugar.
javascript
// Right: capture as it happens, persist immediately.
socket.send(JSON.stringify({
  jsonrpc: "2.0", id: 1, method: "eth_subscribe",
  params: ["logs", { address: MY_CONTRACT }],
}));

// Wrong on this chain: a range that has already scrolled out of the window
// returns an empty array rather than an error, so this looks like "no events".
await client.getLogs({ address: MY_CONTRACT, fromBlock: 0n, toBlock: "latest" });

E se você indexar um armazenamento de eventos por (blockNumber, logIndex), inclua o hash da transação: aqui o logIndex é enumerado por transação, então esse par não é único.

Os recibos através de um reinício

O estado sobrevive a um reinício; o índice dos recibos, não

O índice de recibos e logs é mantido em memória. Já se observou o recibo de uma transferência confirmada sumir depois de um reinício do sequenciador enquanto a mudança de saldo sobreviveu corretamente - portanto um recibo não é o registro durável de coisa alguma. Trate o explorador como o registro do que aconteceu, e o recibo do nó como um aviso de recebimento rápido e perecível.