Перейти к основному контенту

Использование WebSockets

alchemy
websockets
запросы
javascript
Для начинающих
Элан Халперн
1 декабря 2020 г.
6 минут на чтение

Это руководство начального уровня по использованию WebSockets для выполнения запросов к блокчейну Эфириума. В примерах используются стандартные методы JSON-RPC, поэтому они работают с любым узлом или провайдером узлов, который предлагает конечную точку WebSocket, включая Alchemy.

 (открывается в новой вкладке)WebSockets против HTTP

В отличие от HTTP, при использовании WebSockets вам не нужно постоянно делать запросы, когда вы хотите получить определенную информацию. WebSockets поддерживают сетевое подключение для вас (если все сделано правильно) и прослушивают изменения.

Как и в случае с любым сетевым подключением, не следует предполагать, что WebSocket будет оставаться открытым вечно без прерываний, но правильная обработка разорванных соединений и переподключение вручную могут быть сложной задачей. Еще одним недостатком WebSockets является то, что вы не получаете коды состояния HTTP в ответе, а только сообщение об ошибке.

Клиентские библиотеки могут справиться с этим за вас. Например, транспорт WebSocket в Viem (открывается в новой вкладке) по умолчанию переподключается при сбое сокета и отправляет пинги для поддержания активности (keep-alive).

Попробуйте

Вам нужен URL-адрес WebSocket для узла Эфириума. Провайдеры узлов предоставляют его при создании ключа программного интерфейса приложения (API), обычно в формате wss://<provider-host>/<your-api-key>. Например, URL-адрес основной сети Ethereum в Alchemy выглядит как wss://eth-mainnet.g.alchemy.com/v2/<your-api-key> (зарегистрируйте бесплатный аккаунт Alchemy (открывается в новой вкладке)). Информацию о других провайдерах см. в разделе узлы как услуга, или используйте конечную точку WebSocket вашего собственного узла. Публичные конечные точки, такие как wss://ethereum-rpc.publicnode.com, также подходят для быстрых экспериментов, но они имеют ограничения по частоте запросов и могут не поддерживать все типы подписок.

Самый простой способ протестировать WebSockets — установить инструмент командной строки для выполнения запросов WebSocket, такой как wscat (открывается в новой вкладке). Используя wscat, вы можете отправлять запросы следующим образом:

npx wscat -c wss://<provider-host>/<your-api-key>

> {"jsonrpc": "2.0", "id": 0, "method": "eth_gasPrice"}

< {"jsonrpc": "2.0", "result": "0x41f9de2", "id": 0}

Строки, начинающиеся с >, — это то, что вы вводите, а строки, начинающиеся с <, — это то, что узел отправляет в ответ.

Как использовать WebSockets

Для начала откройте WebSocket, используя URL-адрес WebSocket вашего провайдера. В Alchemy вы можете найти его, открыв свое приложение на панели управления (открывается в новой вкладке) и просмотрев его ключ программного интерфейса приложения (API). Обратите внимание, что URL-адрес для WebSockets (wss://) отличается от URL-адреса для HTTP-запросов (https://), хотя большинство провайдеров используют один и тот же ключ API для обоих.

Любой из методов JSON-RPC, поддерживаемых вашим провайдером, можно использовать через WebSocket. Для этого используйте ту же полезную нагрузку, которая была бы отправлена в теле HTTP-запроса POST, но вместо этого отправьте эту полезную нагрузку через WebSocket.

С Web3

Переход на WebSockets при использовании клиентской библиотеки, такой как Viem (открывается в новой вкладке), прост. Используйте транспорт webSocket с вашим URL-адресом WebSocket вместо транспорта http. Например, после npm install viem сохраните это как index.mjs и запустите node index.mjs:

API подписок

При подключении через WebSocket вы можете использовать два дополнительных метода: eth_subscribe и eth_unsubscribe. Эти методы позволят вам прослушивать определенные события и немедленно получать уведомления.

eth_subscribe

Создает новую подписку на указанные события. Узнайте больше о eth_subscribe (открывается в новой вкладке).

Параметры

  1. Типы подписок
  2. Необязательные параметры

Первый аргумент указывает тип события для прослушивания. Второй аргумент содержит дополнительные параметры, которые зависят от первого аргумента. Различные типы описаний, их параметры и полезные нагрузки событий описаны ниже.

Возвращает

ID подписки: этот идентификатор будет прикреплен к любым полученным событиям, а также может быть использован для отмены подписки с помощью eth_unsubscribe.

События подписки

Пока подписка активна, вы будете получать события, которые представляют собой объекты со следующими полями:

  • jsonrpc: всегда «2.0»
  • method: всегда «eth_subscription»
  • params: объект со следующими полями:
    • subscription: ID подписки, возвращенный вызовом eth_subscribe, который создал эту подписку.
    • result: объект, содержимое которого зависит от типа подписки.

Типы подписок

  1. newHeads

Генерирует событие каждый раз, когда в цепь добавляется новый заголовок, в том числе во время реорганизации цепи.

Когда происходит реорганизация цепи, эта подписка генерирует событие, содержащее все новые заголовки для новой цепи. В частности, это означает, что вы можете увидеть несколько сгенерированных заголовков с одинаковой высотой, и когда это происходит, более поздний заголовок следует считать правильным после реорганизации.

Пример:

  1. logs

Генерирует журналы, которые являются частью недавно добавленных блоков и соответствуют указанным критериям фильтрации.

Когда происходит реорганизация цепи, журналы, которые являются частью блоков в старой цепи, будут сгенерированы снова со свойством removed, установленным в true. Кроме того, генерируются журналы, которые являются частью блоков в новой цепи, что означает, что в случае реорганизации можно увидеть журналы для одной и той же транзакции несколько раз.

Параметры

  1. Объект со следующими полями:
    • address (необязательно): либо строка, представляющая адрес, либо массив таких строк.
      • Будут генерироваться только журналы, созданные с одного из этих адресов.
    • topics: массив спецификаторов тем.
      • Каждый спецификатор темы — это либо null, либо строка, представляющая тему, либо массив строк.
      • Каждая позиция в массиве, которая не равна null, ограничивает генерируемые журналы только теми, у которых есть одна из заданных тем в этой позиции.

Некоторые примеры спецификаций тем:

  • []: разрешены любые темы.
  • [A]: A на первой позиции (и что угодно после).
  • [null, B]: что угодно на первой позиции и B на второй позиции (и что угодно после).
  • [A, B]: A на первой позиции и B на второй позиции (и что угодно после).
  • [[A, B], [A, B]]: (A или B) на первой позиции и (A или B) на второй позиции (и что угодно после).

Пример:

В этом примере прослушиваются события Deposit из контракта обернутого эфира (WETH) (открывается в новой вкладке) в основной сети Ethereum:

  1. newPendingTransactions

Генерирует хеш каждой транзакции, которая добавляется в состояние ожидания узла (его мемпул).

Пример:

> {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newPendingTransactions"]}

< {"jsonrpc":"2.0","result":"0x1c2365b029179adf1e84b9e327315249","id":1}
< {"jsonrpc":"2.0","method":"eth_subscription","params":{"result":"0x4a62d0ad7c8868fbbfa10604e68638e637c6fc6f64fd1fb4ca042dcd0158c992","subscription":"0x1c2365b029179adf1e84b9e327315249"}}

Некоторые провайдеры также предлагают свои собственные типы подписок. Например, alchemy_pendingTransactions (открывается в новой вкладке) от Alchemy генерирует полные объекты транзакций вместо просто хешей и принимает необязательные фильтры fromAddress, toAddress и hashesOnly. Они не являются частью стандартного программного интерфейса приложения (API) JSON-RPC, поэтому работают только с этим провайдером.

eth_unsubscribe

Отменяет существующую подписку, чтобы больше не отправлялись события.

Параметры

  1. ID подписки, ранее возвращенный вызовом eth_subscribe.

Возвращает

true, если подписка была успешно отменена, или false, если подписки с заданным ID не существовало.

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

Пример:

> {"jsonrpc": "2.0", "id": 2, "method": "eth_unsubscribe", "params": ["0xe0d4abf5caf333fbf94c5f02182e6469"]}

< {"jsonrpc":"2.0","result":true,"id":2}

Зарегистрируйтесь в Alchemy (открывается в новой вкладке) бесплатно, ознакомьтесь с документацией Alchemy (открывается в новой вкладке) и следите за последними новостями Alchemy в Твиттере (открывается в новой вкладке).