개발자를 위한 문서 / JSON-RPC
히스토리와 보존
노드는 아카이브가 아니라 RPC 인덱스입니다. 대략 2분치의 블록을 보관하며, 그 너머의 질의는 오류를 내는 대신 null로 답합니다 - 이 페이지가 인덱서를 쓴 뒤가 아니라 쓰기 전에 있는 이유입니다.
노드가 보관하는 것
| 데이터 | 보관 |
|---|---|
| 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 history | 20,000KEEP_MINI_BLOCKS, roughly 200 seconds at the 10 ms scheduling target |
| Receipts and bodies | 200,000MAX_RECEIPTS, evicted first-in-first-out |
| Full history | not on the nodeit lives in Postgres behind the explorer, fed by the sequencer's spool. This RPC is an index, not an archive |
블록 창은 고정된 것이 아니라 유도된 값입니다. keep_evm_blocks() = 120_000 / EVM_BLOCK_MS이며, 기본 케이던스에서는 480 블록입니다. 로그는 자기 블록과 함께 축출됩니다. 영수증과 트랜잭션 본문은 자체 선입선출 상한을 갖고 있어 자기 블록보다 먼저 사라질 수 있습니다.
읽기는 발행된 copy-on-write 스냅샷에서 제공되며 실행 락을 결코 잡지 않습니다. 느린 eth_call이 블록 생산을 멈춰 세울 수 없고 멈춘 블록이 읽기를 멈춰 세울 수 없는 이유가 그것입니다. 보관 창을 받아들일 만하게 만드는 설계도 바로 그것입니다. 노드는 현재를 빠르게 제공하는 데 최적화하고, 히스토리는 그 일을 위해 만들어진 것에 넘깁니다.
이것이 실패하는 방식
보관 창 바깥에서는 오류가 아니라 null이 옵니다
eth_getTransactionReceipt, eth_getTransactionByHash, 그리고 모든 블록 조회는 축출된 것에 대해 null로 답합니다. "존재한 적이 없다"와 "존재했다가 버려졌다"를 구별해 주는 것은 아무것도 없습니다.
맞아 보이지만 틀린 세 가지 패턴입니다.
- 긴 백오프로 영수증을 폴링하기. 시도 사이를 충분히 길게 두면 영수증은 두 번의 폴링 사이에 축출될 수 있습니다. 영수증은 보낸 지 약 10 ms의 스케줄링 목표 안에 존재합니다 - 참을성 있게가 아니라 이르게, 자주 폴링하십시오.
- 블록 0부터 백필하기.
earliest는 가장 이른 보관된 블록이고, 작업하는 동안 앞으로 움직입니다. 그것을 쫓는 백필 루프는 고정된 시작점에 결코 닿지 못합니다. - 원장을 야간에 대사하기. 야간 작업이 도는 시점이면 그것이 원하던 블록은 전부 사라져 있습니다.
대신 무엇을 할 것인가
전체 히스토리는 존재합니다 - 시퀀서에서 익스플로러 뒤의 Postgres로 흘러 들어가며, 그쪽은 아카이브가 되도록 만들어졌습니다. 그러므로,
- 현재, 즉 최근 몇 초는 노드를 쓰십시오. 구독과 좁은 범위의
eth_getLogs가 노드가 빠른 일입니다. - 과거는 익스플로러에서 읽으십시오. 거기에는 호출 트레이스도 있는데,
debug네임스페이스가 없으므로 노드는 그것을 전혀 노출하지 않습니다. - 자기 히스토리를 보관하려면 나중에 질의하는 대신 구독해서 이벤트가 도착할 때 저장하십시오. 미니블록 스트림이 가장 충실도가 높은 소스입니다. 느린 핸들러는 거기서 떨어져 나가므로, 큐에 밀어 넣고 처리는 다른 곳에서 하십시오.
// 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" });그리고 이벤트 저장소를 (blockNumber, logIndex)로 키잉한다면 트랜잭션 해시도 포함하십시오. 여기서 logIndex는 트랜잭션마다 새로 매겨지므로 그 쌍은 유일하지 않습니다.
재시작을 건넌 영수증
상태는 재시작을 견디지만 영수증 인덱스는 견디지 못합니다
영수증과 로그 인덱스는 메모리에 있습니다. 확인된 전송의 영수증이 시퀀서 재시작 뒤에 사라지는 동안 잔액 변화는 올바르게 살아남은 사례가 관측되었습니다 - 그러니 영수증은 무엇에 대해서도 내구성 있는 기록이 아닙니다. 무슨 일이 있었는지의 기록은 익스플로러로, 노드의 영수증은 빠르되 썩는 수신 확인으로 취급하십시오.