Node Times

Cover image for Что такое блокчейн RPC?
Newsroom
Newsroom

Posted on

Что такое блокчейн RPC?

От редакции NodeTimes, автор: Ника.

Блокчейн RPC (remote procedure call) – это клиент-сервисный интерфейс, который приложение использует для чтения состояния цепи из узла или передачи ему транзакции; в семействах цепей Ethereum он использует протокол JSON-RPC. Узел выполняет работу; конечная точка (endpoint) – это лишь адрес, по которому вы отправляете запросы. Каждый баланс и каждое подтверждение, которые показывает вам кошелек, являются ответом на один из этих вызовов, поэтому честность этого единственного перехода определяет честность всего приложения.

Что означает RPC в контексте блокчейна

RPC (удаленный вызов процедур) позволяет одной программе вызывать процедуру, работающую на другой машине; в блокчейне вызывающей стороной является кошелек, бот или бэкенд, а вызываемой – узел. Протокол намеренно прост: HTTP POST с JSON, именем метода, параметрами и идентификатором.

JSON-RPC: протокол, который они используют, безсостоятельный формат вызова, независимый от транспорта, передающий данные в формате JSON, поэтому один и тот же запрос работает поверх HTTP, WebSocket или сокета внутри процесса. Клиент выполнения (execution client): программное обеспечение узла, которое исполняет транзакции, поддерживает дерево состояний (state trie) и отвечает на JSON-RPC (Geth, Nethermind, Besu, Erigon, Reth). Клиент консенсуса (consensus client): отдельный процесс, который следует за цепочкой маяков (beacon chain) и управляет клиентом выполнения через Engine API (локальный канал узла, а не конечная точка, доступная через интернет).

Форматы запросов, как они определены в спецификации:

{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0x…","latest"]}
{"jsonrpc":"2.0","id":2,"method":"eth_chainId","params":[]}
Enter fullscreen mode Exit fullscreen mode

Пространства имен, с которыми вы столкнетесь в продакшене, немногочисленны:

  • eth_* читает и записывает состояние цепи и транзакции: eth_blockNumber, eth_getBalance, eth_getStorageAt, eth_call, eth_sendRawTransaction.
  • net_* и web3_* предоставляют сетевую идентичность и информацию о клиенте, дешевые проверки, которые вы используете для обеспечения согласованности.
  • debug_* и trace_* охватывают трассировку и симуляцию, и они обычно отключены на публичных конечных точках.
  • eth_getProof возвращает доказательство Меркла для учетной записи или ячейки хранилища: единственный вызов, который позволяет проверить ответ вместо того, чтобы просто доверять ему.

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

Типы узлов и то, на что каждый из них может ответить

Тип узла определяется тем, сколько состояния и истории хранит машина, а не интерфейсом, который она предоставляет. Именно поэтому два адреса с одинаково выглядящими URL могут вести себя по-разному: они поддерживаются узлами разных классов.

Тип узла Хранит Отвечает на Типичное использование
Легкий узел (Light node) заголовки блоков только заголовки: запрашивает состояние у полного узла и проверяет ответ с помощью доказательства мобильные кошельки, клиенты с низкими ресурсами
Полный узел (Full node) последнее состояние, недавние снимки, и каждый блок и транзакцию текущее состояние, недавние блоки кошельки, dApps, операторы конечных точек
Архивный узел (Archive node) каждое историческое состояние историческое состояние на любом прошлом блоке аналитика, обозреватели (explorers), трассировка
Валидатор (клиент валидатора на клиенте консенсуса) полный узел плюс ключи валидатора предложения блоков и аттестации стейкинг, обязанности консенсуса
Узел только для RPC (Solana) состояние, без роли консенсуса читает и ретранслирует вызовы флоты Solana, обслуживающие только запросы

Для активации валидатору требуется минимум 32 ETH, и после EIP-7251 эффективный баланс на одном валидаторе может быть консолидирован до 2 048 ETH. Эта роль – отдельная тема, рассмотренная в статье что консенсус означает для цепи.

Различие, имеющее коммерческое значение, – это валидатор против услуги RPC. В Solana валидатор запускает консенсус и получает вознаграждения, тогда как узел RPC только отвечает на запросы; в Ethereum клиент выполнения отвечает на вызовы независимо от того, прикреплен ли к нему валидатор. Три класса хранения следуют документации самой Ethereum; валидатор – это отдельное программное обеспечение, подключенное к клиенту консенсуса, а узел только для запросов – это роль Solana, а не класс Ethereum. Какой класс узла находится за конечной точкой, также зависит от того, как цепь разделяет состояние, что описано в разделе шардинг.

Узел, конечная точка и провайдер – три разные вещи

Конечная точка – это сетевой адрес, узел – это процесс, выполняющий работу, а провайдер – компания, управляющая флотом за многими конечными точками. Если объединить这三个, можно поверить, что вы управляете децентрализованной инфраструктурой, отправляя каждый запрос на один URL.

  • Один узел может находиться за несколькими конечными точками, а одна конечная точка может быть балансировщиком нагрузки над флотом.
  • Конечная точка провайдера – это общая входная дверь: именно поэтому архивные запросы терпят неудачу на бесплатных тарифах, а самостоятельное размещение покупает узел, но не высокую доступность.
  • Эти три элемента разделены тем, кто владеет отказом: ваше приложение владеет запросом, провайдер владеет маршрутом, а узел владеет ответом.

Над всем этим стоит более широкий стек: L0, L1 и L2 решают, где оседает состояние и данные, конечная точка – это способ добраться до них, а ваше dApp – просто еще один клиент.

Как путешествует вызов и где он может быть отвергнут

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

  1. Ваше приложение отправляет POST-запрос JSON-RPC на конечную точку.
  2. Балансировщик нагрузки направляет его к одному узлу во флоте.
  3. Клиент выполнения этого узла отвечает на основе локального состояния или возвращает ошибку, если метод отключен.
  4. Для записи узел проверяет сырую транзакцию и распространяет ее; включение в блок – решение билдера.
  5. Узел, отставший от головы цепи, все равно отвечает, и ответ все равно выглядит корректным.

Проектируйте систему с учетом трех возможных сбоев, а не одного: ограничения скорости при нагрузке, отсутствующие методы на вашем тарифном плане и устаревшая голова после того, как узел выходит из синхронизации. Отстающий узел не объявляет о себе; он отвечает в той же форме, что и здоровый узел.

Что такое узел и почему цепи нужно так много из них, имеет свое собственное объяснение: почему блокчейну нужны узлы. И если базовый слой для вас нов, начните со статьи что такое блокчейн.

Почему два провайдера могут отвечать по-разному

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

  • Задержка индексирования: узлы провайдера могут отставать от головы цепи, поэтому чтение, привязанное к последнему блоку, разрешается на основе немного более старого состояния.
  • Реорганизации: недавний блок может быть заменен, и ответ, который был верен мгновение назад, перестает быть верным.
  • Различные источники истины: флот может поддерживаться архивными узлами, снимками или внутренним кэшем, а внутренняя структура флотов провайдеров не документирована публично.

Решение состоит в том, чтобы перестать сравнивать снимки последнего блока. Привяжите чтения к хэшу блока (EIP-1898) и сравнивайте их со вторым источником, управляемым независимо: это единственный способ отличить реальное расхождение от артефакта времени.

Что может видеть и делать оператор вашей конечной точки

Тот, кто отвечает на вызов, может наблюдать за ним, задерживать его, цензурировать или возвращать данные, которые выглядят корректно, но фактически ложны. RPC – это граница доверия, а не просто труба.

  • Один провайдер – это одна точка истины, каким бы обещаниям ни соответствовал окружающий его протокол.
  • Перекрестная проверка двух независимых конечных точек превращает большую часть скрытой коррупции в видимое расхождение.
  • Там, где движутся ценности, предпочитайте ответ, который вы можете проверить, ответу, который вы запросили дважды.

Эта граница не теоретическая. Эксплойт моста KelpDAO произошел через отравленные ответы RPC: ни бага в контракте, ни скомпрометированного ключа подписи, просто сервис проверки, который доверял ответам от узлов, контролируемых злоумышленником. Этот эксплойт – отдельная тема; здесь он лишь отмечает, где находится граница доверия. То, что остается от претензии на децентрализацию, рассматривается в статье что Web3 означает на практике.

Как аудировать конечную точку

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

  1. Идентичность цепи: вызовите eth_chainId и net_version. Несоответствие означает, что конечная точка обслуживает цепь, которую вы не собирались запрашивать.
  2. Свежесть головы: сравните eth_blockNumber со вторым провайдером. Разрыв означает, что узел устарел или флот несогласован.
  3. Состояние синхронизации: вызовите eth_syncing. Любое значение, кроме false, означает, что ответы поступают из состояния позади головы.
  4. Привязка состояния: вызовите eth_getBalance с объектом блока вместо latest. Ошибка означает, что форма параметра с хэшем блока не поддерживается.
  5. Глубина архива: запросите баланс на фиксированном историческом блоке. Тихое падение до состояния последнего блока означает, что архивные запросы на самом деле не являются архивными.
  6. Поддержка трассировки: сделайте один вызов debug_ или trace_. Ошибка означает, что трассировка отключена на этом уровне.
  7. Поведение под нагрузкой: отправьте 20 вызовов eth_blockNumber за 2 секунды. Ограничение скорости проявляется в виде ошибок или добавленной задержки.
  8. Покрытие методов: запросите один метод из каждого пространства имен, на которое вы опираетесь, и сравните результат с опубликованной спецификацией.

EIP-1898 делает возможной проверку привязки: вызывающая сторона передает {"blockNumber": …} или {"blockHash": …} вместо "latest", с рекомендуемым кодом -32001, когда блок не найден, иdistinct ошибкой, возникающей при сбое requireCanonical. Привязка к хэшу – это то, как вы запрашиваете состояние согласованно во время реорганизации.

Контракт запроса и ошибки живет в спецификации Ethereum JSON-RPC (EIP-1474) и репозитории execution-apis, а не на маркетинговой странице провайдера, где обычно заканчиваются большинство объяснений RPC.

Запустите проверки в этом порядке, и вопрос изменится: не «работает ли моя конечная точка», а «может ли она меня обмануть, и замечу ли я это».

Часто задаваемые вопросы

Является ли RPC-конечная точка тем же самым, что и узел?

Нет. Узел – это программное обеспечение, которое хранит состояние и выполняет вызовы, а конечная точка – это адрес, к которому подключается ваше приложение, который может обслуживать целый флот.

Рассмотрение их как синонимов – это то, как одиночная точка отказа принимается за кластер.

Централизован ли блокчейн RPC?

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

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

Нужен ли мне архивный узел?

Только если вы запрашиваете историческое состояние. Полный узел отвечает на запросы о последнем и недавних блоках; архивный запрос к неархивному узлу завершается неудачей или возвращает что-то другое.

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

Почему моя транзакция «исчезает» после отправки?

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

Решение операционное: повторно транслируйте через вторую конечную точку, отслеживайте хэш и предпочитайте конечные точки, которые показывают статус транзакции.

Какие методы RPC следует отключить в продакшене?

Любое пространство имен, которое вы не используете, и пространства имен трассировки по умолчанию: debug_ и trace_ дороги и являются обычным вектором исчерпания ресурсов на узле, доступном через интернет.

Строгий белый список методов чтения eth_ плюс eth_sendRawTransaction покрывает большинство приложений.

Top comments (0)