Для разработчиков / JSON-RPC

Подписки

Четыре вида подписок на сервере, который не является HTTP-слушателем. Здесь живёт поток мини-блоков - единственная поверхность отсюда, которой вы не найдёте на другой сети.

Отдельный сервер

На HTTP-порту подписок не существует

eth_subscribe к HTTP-точке доступа отвечает -32601. Узел нигде не регистрирует подписок jsonrpsee; сокет - это отдельный, написанный вручную сервер на собственном слушателе, и только там подписки и обслуживаются.

У реплики WebSocket-сервера нет вовсе: слушатель поднимается только на пути лидера. Подписки - поверхность, доступная только у лидера.

Точка доступаValue
Точка доступаwss://rpc.picklechain.xyz/ws/публичная тестовая сеть; примеры пишут её как $WS_URL
Узел, который вы запускаете самиws://127.0.0.1:8546WebSocket-порт по умолчанию у узла, запущенного на вашей машине

On a deployment behind a reverse proxy, both /ws and /ws/ are served as two separate locations with no redirect between them: a WebSocket client mostly does not follow a 301 on its handshake, so whichever spelling was redirected would simply fail to connect.

Рукопожатие

eth_subscribe и pickle_subscribe принимаются как взаимозаменяемые и ведут себя одинаково:

json
// ->
{"jsonrpc":"2.0","id":1,"method":"pickle_subscribe","params":["miniBlocks"]}

// <-
{"jsonrpc":"2.0","id":1,"result":"0x1"}

// <- then, per event
{"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{…}}}
  • Subscription ids come from a per-connection counter starting at 1, so two connections both see 0x1. Do not treat an id as globally unique.
  • Notifications always arrive under the method name eth_subscription, even for a subscription opened as pickle_subscribe. Unwrap the payload at params.result.
  • eth_unsubscribe and pickle_unsubscribe both return a boolean: true if the id was found on this connection, false otherwise.

Четыре вида

One notification per sealed EVM block.

Полезно знать. The payload is a nine-field summary - number, hash, parentHash, timestamp, mixHash, baseFeePerGas, transactionCount, miniBlockFrom, miniBlockTo - and not the full header that eth_getBlockByNumber returns. transactionCount is a decimal number. A client that needs gasLimit, gasUsed or logsBloom must re-fetch the block.

miniBlocks

alias: newMiniBlocks

The preconfirmation stream: one notification per sealed mini-block, at the mini-block scheduling target. Both spellings are the same stream.

Полезно знать. Mini-block fields break the eth_* hex convention on purpose: number, evmBlockNumber, timestampUs and each receipt's gasUsed are decimal JSON numbers, and the timestamp is in microseconds.

Logs as they are indexed, with the standard address and topics filtering. An absent or empty filter means every log.

Полезно знать. A malformed topics filter answers -32602 before an id is allocated, so a failed subscribe leaves you with no subscription rather than a silent one.

Transaction hashes, as a bare string payload.

Полезно знать. "Pending" does not mean what it means elsewhere. There is no public mempool; a hash is published only AFTER the transaction has executed and been indexed. Treat this as an executed-transaction feed, not a mempool feed.

Разобранный пример

Поток мини-блоков, с тем же запасным путём, которым пользуется лента первой стороны. Запасной путь важен: оборванный сокет - это норма, а путь с опросом - то, чем вы догоняете без пропусков.

javascript
// WS_URL: wss://rpc.picklechain.xyz/ws/ on the public testnet, or a node of your own.
// The /ws path is required - an upgrade at the bare origin answers 405.
const socket = new WebSocket(WS_URL);

socket.addEventListener("open", () => {
  socket.send(JSON.stringify({
    jsonrpc: "2.0", id: 1, method: "pickle_subscribe", params: ["miniBlocks"],
  }));
});

socket.addEventListener("message", (event) => {
  const message = JSON.parse(event.data);
  // The subscribe reply carries an id; notifications carry params.result.
  if (!message.params) return;
  const mini = message.params.result;

  // Decimal numbers, not hex quantities - and microseconds, not seconds.
  console.log(mini.number, mini.transactions.length, mini.timestampUs);
});

// A slow handler is DROPPED from the stream rather than buffered, so do the
// work elsewhere and keep this callback cheap.

Если сокет закрылся, опрашивайте pickle_miniBlockNumber, а затем pickle_getMiniBlockByNumber от последней увиденной высоты. Ограничьте догоняющий проход - эталонный клиент забирает не больше 100 за проход, - иначе долгий обрыв связи превратится во всплеск запросов против общего бюджета тяжёлых чтений.

Ограничения и политика сброса

ОграничениеValue
Message size256 KiBframe and message both; oversized answers -32005 "message too large"
Connections256excess connections are dropped at accept, with no error frame - your client sees a closed socket, not a rejection
Subscriptions per connection32-32005 "subscription limit reached"
Requests per second100 per connection-32005 "request rate limit exceeded"
Stream depth1024 per streama subscriber that falls behind is DROPPED from the stream rather than buffered, so a slow handler loses notifications silently. Do the work off the socket

Медленные подписчики теряют данные молча

Каждый поток - это широковещательный канал глубиной 1024. Подписчика, который отстал, сбрасывают с потока, а не дают ему растить память узла: вы получаете не кадр с ошибкой, а пропуск. При целевом интервале мини-блока этот буфер - запас в несколько секунд, так что любая работа на событие тяжелее, чем укладывание в очередь, сокету не место.

Ни одно из этих ограничений не настраивается через окружение, а предел числа соединений применяется при приёме: 257-е соединение закрывается без кадра ошибки, и это выглядит как сетевой сбой, а не как отказ.

Обычные вызовы через сокет

Any frame that is not a subscribe or unsubscribe is forwarded to the same handler the HTTP port uses, so every method in the reference is callable over the socket.

Коды ошибок различаются по транспорту

Error codes are re-wrapped on the way out. Every non-send failure comes back as -32603 regardless of its original code, so an eth_call revert is -32000 over HTTP and -32603 over the socket. A client that branches on the code needs to know which transport it is on.