Разработка смарт-контрактов в Ethereum

Тимур Машнин, 2022

Эта книга рассказывает о принципах работы Ethereum, отличии Ethereum от Bitcoin. Вы узнаете что такое децентрализованные приложения Dapp и смарт-контракты, познакомитесь с инструментами разработки Dapp. Изучите высокоуровневый язык Solidity создания смарт-контрактов для виртуальной машины Ethereum. Познакомитесь со средой разработки Remix. Узнаете о практическом применении смарт-контрактов, стандартах ERC20, ERC-721, ERC-1155 и EIP-3156.

Оглавление

Введение в Ethereum

В Ethereum смарт контракты — это скрипты, которые могут обрабатывать деньги.

Эти контракты соблюдаются и заверяются сторонами, которых мы называем майнерами.

Майнеры добавляют транзакцию (выполнение смарт-контракта, оплату криптовалютой и т. д.) в публичную книгу, которая называется блоком. Блоки образуют блокчейн.

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

Когда вы публикуете смарт-контракт или выполняете смарт-контракт, или переводите деньги на другой аккаунт, вы платите некоторый эфир, который преобразуется в газ.

«Газ» — это название специальной единицы, используемой в Эфириуме.

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

Например, для запуска вычисления криптографического хеша требуется 30 газов плюс 6 газов для хэширования каждых 256 бит данных.

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

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

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

Это другая стратегия оплаты, по сравнению с оплатой за транзакцию в Bitcoin, которая основана только на размере транзакции в килобайтах.

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

Поэтому важно измерять эту работу, а не просто определять оплату в зависимости от размера транзакции или контракта.

Хотя газ — это единица измерения, нет никакого токена для газа.

То есть вы не можете владеть 1000 газами.

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

Когда дело доходит до фактической оплаты газа, комиссия за транзакцию взимается как определенное количество эфира — токена сети Ethereum.

Этим токеном майнеры вознаграждаются за создание блоков.

Сначала это может показаться странным.

Почему работа не измеряется сразу в эфире?

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

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

Операция имеет стоимость газа, но сам газ также имеет стоимость, измеряемую в эфире.

Для перевода токенов с одного кошелька на другой требуется 21000 газа.

Для создания смарт-контракта может потребоваться разное количество газа.

Для выполнения смарт-контракта также может потребоваться разное количество газа.

Выполнение вычислительных действий в виртуальной машине Эфириума стоит очень дорого.

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

И комиссионные платежи помогают предотвратить чрезмерную нагрузку на сеть.

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

Таким образом, комиссии защищают сеть от преднамеренных атак.

Эфириум представляет собой машину состояний, функционирующую посредством транзакций.

Разные счета инициируют переход Эфириума из одного глобального состояния в другое.

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

И есть два типа транзакций: сообщения и транзакции создания контрактов.

Можно сказать, что транзакции являются своего рода мостами между внешним миром и внутренним состоянием Эфириума.

При этом смарт контракты могут взаимодействовать друг с другом.

Контракты, существующие в глобальной области действия состояния Эфириума, могут взаимодействовать с контрактами внутри этой же области действия.

Они делают это посредством «сообщений» или «внутренних транзакций» в адрес других контрактов.

Можно сказать, что сообщения или внутренние транзакции схожи с обычными транзакциями, но отличаются тем, что они НЕ генерируются счетами владельцев.

Их генерируют сами контракты.

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

Когда один контракт отправляет внутреннюю транзакцию на адрес счёта другого контракта, выполняется соответствующий код, прописанный в контракте-получателе.

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

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

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

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

Она измеряется в «Gwei».

«Wei» — это наименьшая единица эфира, 1 эфир = 1018 Wei.

Один Gwei равен 1 000 000 000 Wei.

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

Произведение цены газа и лимита газа даёт максимальное количество Wei, которое отправитель готов заплатить за выполнение транзакции.

Предположим, что отправитель устанавливает лимит газа 50 000, а цену газа 20 Gwei.

Это означает, что отправитель готов потратить на выполнение этой транзакции не более чем 50 000 x 20 Gwei = 1 000 000 000 000 000 Wei = 0,001 эфира.

Таким образом, лимит газа представляет собой максимальное количество газа, которое готов оплатить отправитель.

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

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

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

В этом случае выполнение транзакции прерывается, любые произведённые ею изменения в состоянии сети отменяются и Эфириум возвращается в состояние, в котором он находился перед началом транзакции — как если бы её вовсе не было.

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

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

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

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

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

Газ используется для оплаты не только вычислительных действий, но и хранения данных.

Общая плата за хранение пропорциональна наименьшему использованному объему, кратному 32 байтам числу.

В комиссии за хранение данных есть свои нюансы.

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

Поэтому, если транзакция инициирует выполнение действия, в результате которого объём занимаемого хранилища сокращается, то комиссия за выполнение этой операции не взимается, ПЛЮС производится возврат средств за освобождённый объём.

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

Если цена на газ, которая установлена в транзакции, слишком низкая, никто даже не потрудится выполнить транзакцию.

Она просто не будет включена в блокчейн майнерами.

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

Майнер просто прекратит обработку транзакции, вернет любые сделанные изменения, но все равно включит ее в блок-цепочку в качестве «неудачной транзакции», удержав за нее плату.

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

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

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

Шахтеры взимают плату только за ту работу, которую они на самом деле делают.

Эфириум построен таким образом, что интервал между блоками в нём значительно меньше (~15 секунд), чем в других блокчейнах и, например, в Биткоине (~10 минут).

Это позволяет ускорить процесс обработки транзакций.

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

Эти конкурирующие блоки называют ещё потерянными, то есть намайненными блоками, но не включёнными в основную цепочку.

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

Оммеры, включаемые майнерами в блокчейн, должны быть «действительными», то есть быть сформированными не более чем в шестом поколении от настоящего блока.

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

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

Виртуальная машина Ethereum является сердцем Ethereum.

Эта виртуальная машина предназначена для запуска всеми участниками одноранговой сети.

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

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

Теперь разберемся со всем этим поподробнее.

Блокчейн Ethereum хранит блоки, которые в свою очередь хранят транзакции и состояние.

И блокчейн Ethereum во многом похож на блокчейн биткойнов, хотя он имеет некоторые отличия.

Основное различие между Ethereum и Bitcoin в отношении архитектуры blockchain заключается в том, что, в отличие от биткойнов, блоки Ethereum содержат копию как списка транзакций, так и самого последнего состояния.

Состояние хранится в специальной структуре данных, называемой деревом Merkle.

Таким образом, блокчейн Ethereum включает в себя корень состояния (по одному на блок), который хранит корневой хэш дерева, представляющего состояние системы во время создания блока.

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

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

Текущий баланс эфира;

Код смарт-контракта аккаунта, если присутствует;

И хранилище аккаунта (пустое по умолчанию);

И данные состояния (вместе с балансами, контрактами) хранятся каждым клиентом Ethereum (или узлом Ethereum).

Есть два типа аккаунтов:

Счет внешнего владельца, который контролируется закрытым ключами и не имеет никакого кода, связанного с ним.

И счет контракта, который контролируются его кодом контракта, и имеет связанный с ним код.

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

Сообщение между двумя счетами внешних владельцев — это просто передача денег.

Но сообщение от счета внешнего владельца на счет контракта активирует код счета контракта, позволяя ему выполнять различные действия (например, передавать токены, записывать данные во внутреннее хранилище, майнить новые токены, выполнять вычисления, создавать новые контракты и т. д.).

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

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

Таким образом, Ethereum имеет набор аккаунтов.

У каждого аккаунта есть владелец и баланс в эфирах.

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

Виртуальная машина Ethereum представляет собой систему обработки транзакций.

То есть у нас есть состояние — это совокупность всех аккаунтов и их балансов.

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

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

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

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

Полный узел Ethereum синхронизирует блокчейн, загружая всю цепочку, от блока генезиса до текущего блока, выполняя все транзакции, содержащиеся внутри.

Также полный узел может быть без выполнения каждой транзакции.

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

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

Такие узлы называются легкими узлами.

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

Что дает возможность легкому узлу при необходимости выбрать заголовок и загрузить данные этого блока.

Термин «транзакция» используется в Ethereum для ссылки на подписанный пакет данных, который хранит сообщение, отправляемое из внешнего аккаунта.

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

Контракт может получить доступ к данным, содержащимся в поле данных.

Как пример использования, если контракт функционирует как служба регистрации домена, тогда данные транзакции будут содержать домен и IP-адрес для его регистрации.

Контракт будет читать эти значения из данных сообщения и соответствующим образом размещать их в хранилище.

Контракты имеют возможность отправлять «сообщения» другим контрактам.

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

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

Как и транзакция, сообщение приводит к тому, что аккаунт получателя запускает свой код.

Таким образом, контракты могут иметь отношения с другими контрактами точно так же, как и внешние аккаунты.

Код в контрактах Ethereum пишется на низкоуровневом, основанном на стеке языке байт-кода, называемом кодом виртуальной машины Ethereum.

Код состоит из серии байтов, где каждый байт представляет операцию.

Для написания контрактов рекомендуется высокоуровневый язык Solidity, код которого затем компилируется в язык виртуальной машины Ethereum.

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

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

Поверх сети Ethereum создаются три типа приложений.

Первая категория — это финансовые приложения, предоставляющие пользователям способы заключения контрактов с использованием их денег.

Это включает в себя суб-валюты, финансовые деривативы, контракты хеджирования, сберегательные кошельки, и т. д.

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

Наконец, существуют такие приложения, как онлайн-голосование, которые не являются финансовыми.

Контракт сам по себе не является децентрализованным приложением.

Децентрализованное приложение состоим из комбинации контракта и графического интерфейса для использования этого контракта.

При этом интерфейс реализован как веб-страница HTML/CSS/JS со специальным Javascript API в виде библиотеки web3.js для работы с блок-цепочкой Ethereum.

Под капотом эта библиотека связывается с локальным узлом через вызовы remote procedure call RPC.

И такое приложение будет работать только в клиенте Ethereum, а не в обычном веб-браузере.

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

Одноранговый распределенный протокол для обмена сообщениями получил название whisper.

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

Одноранговый протокол для обмена статическими файлами получил название swarm.

Whisper — это одноранговый протокол для конфиденциального обмена сообщениями с коротким сроком жизни.

Заголовок сообщений (тема) в Whisper хэшируется, а сами сообщения могут быть зашифрованы с помощью ключей в целях защиты данных.

Swarm представляет собой мотивированный файлообмен.

Файлы делятся на части, хранящиеся на узлах сети.

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

Оглавление

* * *

Приведённый ознакомительный фрагмент книги Разработка смарт-контрактов в Ethereum предоставлен нашим книжным партнёром — компанией ЛитРес.

Купить и скачать полную версию книги в форматах FB2, ePub, MOBI, TXT, HTML, RTF и других

Смотрите также

а б в г д е ё ж з и й к л м н о п р с т у ф х ц ч ш щ э ю я