LayerZero — это протокол, который позволяет различным блокчейнам обмениваться данными и активами. С его помощью можно легко осуществлять кроссчейн обмен, перемещать ликвидность и передавать информацию между разными сетями.
В общей сложности LayerZero Labs собрали $ 263 млн от a16z, Binance, Multicoin, Sequoia Capital, Paypal Ventures, Uniswap Labs и других инвесторов.
Подавляющее большинство пабликов и блогеров выкладывают гайды для прохождения активностей с целью потенциального airdrop. Мы же хотели бы рассказать более подробно о том, как работает протокол LayerZero.
Материалы
Два основных документа, после прочтения которых появляется понимание принципа работы протокола LayerZero:
- Статья на Medium проекта
Как устроен LayerZero?
Верхнеуровневое объяснение
Внутри каждого блокчейна развернуто несколько смарт-контрактов, которые ответственны за передачу данных из Блокчейна А в другие блокчейны. Совокупность этих смарт-контрактов называется Layer Zero endpoint. Подробнее об устройстве LZ endpoint мы расскажем в отдельном разделе. Все кросс-чейн запросы проходят через систему смарт-контрактов LZ endpoint как при отправлении из source сети, так и при приеме в destination сети.
Для передачи кросс-чейн запроса в другой блокчейн Layer Zero полагается на 2 независимые друг от друга архитектурные компоненты:
1. Oracle.
Задача Oracle прочитать заголовок блока в Блокчейне А и отправить его в Блокчейн Б. При этом Oracle передает заголовки не всех подряд блоков Блокчейна А, а только заголовки блоков, где есть LZ кросс-чейн запросы.
Это реализуется следующим образом: как только появляется кросс-чейн запрос, endpoint Блокчейна А оповещает об этом Oracle: “Появился новый LZ кросс-чейн запрос, он находится в Блоке N Блокчейна А. Пожалуйста, прокинь заголовок этого блока в эндпоинт Блокчейна Б ”. Так как в одном блоке source сети может быть несколько LZ кросс-чейн запросов, то Oracle будет оповещаться несколько раз об одном и том же блоке, но работу о передачи заголовка блока в эндпоинт Блокчейна Б выполнит только один раз.
Oracle - это не один оракул, а децентрализованная сеть оракулов. Теоретически LZ может использовать любую сеть оракулов, но на практике использует Chainlink, как наиболее проработанное на настоящий момент решение. В источниках это Chainlink DON (Decentralized oracle networks).
2. Relayer.
Relayer строит доказательство существования для каждой транзакции, содержащей LZ кросс-чейн вызов, после чего проталкивает это доказательство в Блокчейн Б вместе со всеми данными данного конкретного кросс-чейн вызова.
ВАЖНО! Существует много Oracle, и много Relayer. Разработчики приложения сами выбирают, какая пара (Oracle X, Relayer Y) будет ответственна за передачу кросс-чейн вызовов для их приложения.
Таким образом, flow для кросс-чейн вызова выглядит следующим образом:
1) DApp отправляет сообщение из Блокчейна A в Блокчейн Б. В этот момент dApp обращается к эндпоинту Блокчейна А, куда передает всю необходимую информацию (chainID, address, functionToCall, arguments), а также идентификаторы Oracle и Relayer, которые будут использоваться для передачи.
2) Endpoint парсит транзакцию, уведомляет Oracle и Relayer о кросс-чейн вызове.
3) Oracle передает заголовок блока с кросс-чейн вызовом в endpoint Блокчейна Б.
4) Relayer строит и отправляет доказательство транзакции с кросс-чейн вызовом в endpoint Блокчейна Б.
5) Доказательство проверяется в смарт-контракте сети назначения, и если все ок, и сообщение пересылается по адресу назначения.
Более подробный процесс
Шаг 1. Communicator smart-contract
Из dApp вызов приходит сначала в этот смарт-контракт. Он берет транзакцию, парсит ее содержимое на следующие компоненты:
1) t - уникальный ID транзакции. На самом деле, как я понял, это объект уникальным образом идентифицирующих транзакцию (chainID, blockID итд), а не просто хэш.
2) Packet - содержит ровно то, что нужно для кросс-чейн вызова:
● dst - уникальный идентификатор смарт-контракта в сети назначения. По сути это chainID+smart-contract_address
● payload, который нужно скормить смарт-контракту в сети назначения
3) Relayer args - информация для оплаты кросс-чейн вызова.
Далее Communicator отправляет все эти три объекта данных в смарт-контракт Validator.
Шаг 2. Validator smart-contract
Получив все 3 объекта (Packet, Relayer args, t) с предыдущего шага, смарт-контракт Validator делает следующие 2 действия:
1) Смарт-контракт Validator эмитит ивент, где содержится data всех объектов (Packet, Relayer args, t), которые пришли ему от Communicator. Именно этот ивент ждет Relayer.
ВАЖНО ПОНИМАТЬ! Сразу после получения этого ивента Relayer начинает формировать доказательство существования транзакции t. Каждый новый кросс-чейн вызов означает +1 доказательство в памяти релеера. Таким образом, Relayer копит в памяти объекты [Packet, t, proof]. Более того, так как в t содержится blockID, Relayer всегда точно знает к какому блоку source сети какие объекты [Packet, t, proof] относятся. Накопление Relayer таких объектов - непрерывный процесс.
2) Во-вторых, смарт-контракт Validator прокидывает t и dst, которые пришли от Communicator, далее по цепочке в смарт-контракт Network.
Шаг 3. Network smart-contract
1) Смарт-контракт Network принимает от валидатора объекты t (где содержится blockID) и dst (где содержится chainID)
2) Отправляет dst и blockID оракулу Oracle. По сути Network говорит Oracle: “В блоке blockID есть функции кросс-чейн вызовов LayerZero, прокинь пожалуйста заголовок для blockID в endpoint сети, которая соответствует dst”
Теперь мяч на стороне Oracle и Relayer, они получили всю необходимую информацию от endpoint source сети.
Шаг 4. Oracle оповещает endpoint в destination сети.
Oracle оповещает эндпоинт в destination сети, что появился блок с blockID и хорошо бы подтянуть из Relayer транзакции с кросс-чейн вызовами для этого блока.
1) Oracle ждет финализации блока с полученным на предыдущем шаге blockID (получен от смарт-контракта Network), после читает заголовок блока blockID и отправляет заголовок в смарт-контракт Network, который относится к эндпоинту destination сети.
2) Смарт-контракт Network, во-первых, сохраняет заголовок блока во внутреннее хранилище, а, во-вторых, хэширует заголовок блока и проталкивает его в смарт-контракт Validator (этот хэш обозначен blk_hdr_hash).
Шаг 5. Relayer отдает все доказательства транзакций для запрашиваемого блока
Все это время Relayer копил в памяти объекты [Packet, t, proof] кросс-чейн вызов, содержащие в себе в том числе доказательства существования транзакции. Пришло время что-то сделать с этими объектами :)
После того, как как Relayer получает blk_hdr_hash от валидатора, он отправляет все накопленные объекты [Packet, t, proof] для соответствующего блока в смарт-контракт Validator.
Шаг 6. Валидация смарт-контрактом Validator
Смарт-контракт Validator проверяет существование транзакций t в блоке, используя 2 сущности:
● Заголовок блока , хранящийся в хранилище смарт-контракта Network,
● Доказательства существования транзакции proof из объектов [Packet, t, proof], присланного Relayer для блока BlockID.
Если все ок, то Packet улетает по назначению в целевой смарт-контракт.