Создание децентрализованного приложения с блокчейном (Dapp) с Solidity на Ethereum + Javascript…
Это продолжение написания, чтобы помочь тем, кто недавно посетил мой семинар и может захотеть создать простое приложение. В этом блоге предполагается, что вы уже имеете представление о том, что такое блокчейн и что такое эфириум. Но для тех, кто может посмотреть мою презентацию здесь и далее здесь. За ними довольно просто следовать.
Итак, что мы хотим построить. Мы хотим создать приложение для голосования. Причем очень простой. Ethereum позволяет нам создавать децентрализованное приложение, а надежность — это язык, который мы используем для использования в стороннем приложении javascript в качестве интерфейса. Для настройки нашего путешествия нам потребуются следующие приложения, установленные в качестве зависимостей.
1. Диспетчер пакетов узлов (NPM):
2. Трюфель
3. Ганаш
4. Метамаск
Диспетчер пакетов узла
Это позволяет нам управлять пакетами из node.js. и использовать их. Вы можете подтвердить его наличие в своей системе, набрав его в командной строке
$ npm -v
Truffle
Этот пакет npm позволяет нам создавать децентрализованные приложения на блокчейне Ethereum. Это позволяет нам тестировать наши смарт-контракты на нашей локальной копии блокчейна и развертывать контракты в основной сети блокчейна. Вы можете установить версию трюфеля для использования с проектом, используя команду ниже
$ npm install -g [email protected]
Ganache
Это приложение позволяет вам иметь 10 различных фейковых аккаунтов и фейковый эфир. Вы можете скачать его отсюда https://truffleframework.com/ganache
Metamask
Это расширение в Chrome, которое мы можем использовать для взаимодействия с локальным блокчейном, который мы запускаем, или с основным блокчейном Ethereum. Мы будем использовать его в этом приложении, поэтому вы захотите выполнить поиск в Google по запросу metamask extension , а затем установить его в своем браузере Chrome.
Мы продолжим разработку нашего приложения как на солидности, так и на javascript. Однако мы также напишем тесты, чтобы убедиться, что мы идем в правильном направлении. Еще одна вещь, в зависимости от вашего редактора, вы можете захотеть найти подключаемый модуль, чтобы использовать его для солидной подсветки синтаксиса. Это поможет в написании кода солидности, а также в отображении ключевых слов и т. Д.
В этом руководстве я буду использовать vscode в качестве плагина IDE и Solidity от Хуана Бланко.
Шаг первый:
Сначала откройте приложение ganache, и вы должны увидеть что-то вроде этого
То, что вы видите выше, — это 10 разных учетных записей, созданных для вас с помощью ganache, и хотя в моей собственной копии некоторые учетные записи имеют менее 100 eth, у вас должно быть 100 eth во всех учетных записях. В правой части каждой учетной записи есть символ в виде ключа. При нажатии на этот значок отображается ваш закрытый ключ для текущей учетной записи, и его можно использовать для импорта учетной записи в разные сети. Это будет показано позже.
Теперь приступим. Выберите место в вашей системе, и давайте создадим папку, подобную той, что у нас ниже.
Теперь мы внутри нашей папки, и мы хотим быстро приступить к работе с уже существующим проектом трюфелей. Итак, в папке с выборами выполните команду ниже
$ truffle unbox pet-shop
Если у вас возникли проблемы с загрузкой приложения для зоомагазина трюфелей, вы всегда можете загрузить его из репозитория, используя следующую команду в папке выборов
В этом руководстве я использовал VSCode, и вы можете открыть текущую папку с помощью этой команды
После вышеизложенного у вас должно быть следующее представление в любой IDE, которую вы используете.
Давайте пройдемся по тому, что у нас есть здесь:
- Каталог контрактов: здесь мы будем хранить все наши смарт-контракты. Вы уже можете видеть, что у нас есть контракт на миграцию внутри, который обрабатывает наши миграции в блокчейн.
- Каталог миграции: здесь находятся все файлы миграции. Если вы работали в других фреймворках, в которых есть ORM, вы заметите, что это что-то знакомое. Всякий раз, когда мы развертываем смарт-контракты в блокчейне, мы обновляем состояние блокчейна и, следовательно, нуждаемся в миграции.
- каталог node_modules: это дом для всех наших зависимостей Node.
- src directory: здесь мы будем разрабатывать наше клиентское приложение.
- каталог тестов: здесь мы будем писать тесты для наших смарт-контрактов.
- файл truffle-config.js: это основной файл конфигурации для нашего проекта Truffle.
- файл truffle-box.json: этот файл содержит некоторые команды, которые можно использовать в проекте.
Прежде чем мы пойдем дальше, вы можете создать репозиторий для своего проекта, инициализировать текущую папку и сопоставить текущую папку с этим репозиторием.
Затем мы приступаем к написанию наших смарт-контрактов. Для пользователей типа unix вы можете использовать команду ниже:
и для пользователей Windows вы можете это сделать.
Следующее, что нужно сделать, это вставить в файл Election.sol.
Позвольте мне объяснить приведенный выше код
Первая строка объявляет версию надежности, в которой вы хотите написать свой код. Это делается в первую очередь во всех смарт-контрактах надежности. Объявление смарт-контракта начинается с ключевого слова contract, как и в ООП, вы запускаете класс с ключевого слова class. Затем мы объявили строку-кандидат и сделали ее общедоступной. В других серверных языках, таких как C # или java, ключевое слово public будет стоять перед строкой. Также в solidity объявление переменной candidate public будет генерировать бесплатную функцию получения из solidity.
Далее идет функция конструктора, эта функция вызывается всякий раз, когда смарт-контракт развертывается в блокчейне. Если вы новичок в программировании ООП, функция-конструктор обычно находится там, где вы инициализируете переменные и объекты внутри функции.
Затем мы хотим развернуть наш контракт в блокчейне, но сначала нам нужно создать для него файл миграции. В папке миграции вы заметите один файл, который начинается с номера 1. Мы пронумеруем наши файлы миграции, чтобы определить порядок развертывания миграции. Создайте новый файл миграции с именем «2_deploy_contracts.js» через среду IDE или из командной строки, например $ touch migration/2_deploy_contracts.js
Скопируйте приведенный ниже код в файл
Затем мы запускаем с терминала или консоли следующие команды
После завершения миграции мы хотим взаимодействовать с нашим развернутым смарт-контрактом. На типе терминала
Вы должны увидеть консоль с такой подсказкой $ truffle<development>:
Затем введите команду ниже или скопируйте и вставьте:
Выбор — это имя контракта, который мы создали ранее, и мы получили развернутый экземпляр контракта с функцией deployed() и присвоили его переменной app внутри функции обратного вызова обещания.
После ввода вышеуказанного кода вы должны увидеть $ undefined , это не должно вас беспокоить, поскольку это означает, что процесс завершен. Однако теперь у нас есть переменная app , которую можно использовать для подобного вызова кандидата.
Теперь, когда мы здесь, вы развернули свой смарт-контракт и можете извлекать из него данные.
Шаг второй:
Теперь переходим к следующему шагу нашего приложения. Нам нужно сохранить больше свойств нашего кандидата, таких как идентификатор, имя, количество голосов, и нам нужен способ хранить более одного кандидата. Поэтому для этого мы будем использовать тип struct и тип mapping соответственно.
Struct — это тип твердости, который позволяет создавать твердую структуру, а сопоставление похоже на ассоциативный массив или хэш с допустимым сочетанием ключей и значений. Вы можете просмотреть больше типов в документации к используемой нами версии Solidity здесь. Наш избирательный кодекс будет изменен, чтобы он выглядел так
Наша модель кандидата имеет целочисленный тип без подписи для идентификатора, строковый тип для имени и целочисленный тип без подписи для voteCount. Нам нужно будет создать экземпляр этого кандидата в нашем конструкторе и присвоить им значения.
Мы также видим в приведенном выше коде, что мы объявили тип сопоставления, который будет использоваться для хранения списка кандидатов, и ключом к сопоставлению является целое число без подписи.
Мы также отслеживаем всех кандидатов в сопоставлении, поскольку структура сопоставления в твердом состоянии не позволяет объявлять размер сопоставления. Вместо этого структура отображения возвращает значения на основе переданного ей ключа. Например, если у нас есть сопоставление всего с 5 кандидатами, и мы пытаемся извлечь из сопоставления кандидата с целым числом без знака 50, мы получим пустую структуру кандидата. Если ключ не найден, возвращается пустой результат. Подробнее о картографии здесь.
Затем давайте создадим функцию для добавления нашего кандидата в структуру сопоставления с помощью приведенного ниже кода.
Мы объявили функцию addCandidate , которая принимает один аргумент строкового типа, представляющий имя кандидата. Внутри функции мы увеличиваем кеш счетчика кандидатов, чтобы обозначить, что был добавлен новый кандидат. Затем мы обновляем сопоставление новой структурой Candidate, используя текущее количество кандидатов в качестве ключа. Эта структура кандидата инициализируется идентификатором кандидата из текущего числа кандидатов, именем из аргумента функции и начальным счетчиком голосов до 0. Обратите внимание, что видимость этой функции является частной, потому что мы хотим вызывать ее только внутри контракта.
Если вы работаете с C # или java-фоном, вы заметите, что ключевые слова public и private используются для объявления функции или свойства, но помещаются после аргумента в функциях и после типа в объявлении переменной.
Теперь мы можем добавлять кандидатов в наше приложение для выборов, вызывая указанную выше функцию в конструкторе следующим образом
Когда мы снова перенесем наше приложение в блокчейн, автоматически будут созданы два кандидата. На этом этапе наш код должен выглядеть так, как показано ниже:
Теперь мы можем снова запустить миграцию, используя команду сброса reset , как это
И теперь у нас есть работающий смарт-контракт. Затем, чтобы подтвердить то, что мы сделали до сих пор, войдите в консоль трюфелей, как мы делали ранее, и введите ту же команду, что и раньше.
На этот раз, чтобы найти кандидата, мы должны ввести приведенный ниже код.
Здесь мы вводим значение индекса кандидатов. мы можем заменить 1 на 2 и посмотреть, что мы получим обратно.
Написание тестов
Затем создайте тестовый файл с именем «selection.js» в папке tests. Фреймворк Truffle поставляется с фреймворком для тестирования мокко и библиотекой chai для запуска наших тестов. Давайте вставим приведенный ниже код в наш файл.
Давайте пройдемся по этому файлу. Мы импортировали наш контракт на выборы в этот тестовый файл и создали экземпляр тестового контракта, вводя наши учетные записи, которые будут использоваться для тестирования. На самом деле мы написали два основных теста, и эти тесты проверяют
1. Число инициализированных кандидатов.
2. Значения объекта-кандидата инициализированы соответствующими значениями.
Чтобы убедиться, что наш тест в порядке, мы можем выполнить следующую команду.
Уф . какой долгий путь мы прошли, но если вы застряли на этом пути, вы можете получить репозиторий из Интернета.
Наше клиентское приложение
Мы загружаем шаблон зоомагазина трюфелей, потому что он позволяет нам быстро настроить многие вещи. Так что это похоже на шаблон начальной загрузки, который нам нужно быстро настроить и начать. В папке с шаблоном находятся файлы html, css и js. Мы не хотим слишком подробно останавливаться на аспектах создания клиентского приложения, поэтому мы заменим этот файл javascript и файл index.html следующими кодами.
Сначала мы начнем с файла app.js
Теперь замените index.html приведенным ниже кодом:
Отметим несколько вещей, которые выполняет код App.js:
- Настроить web3: web3.js — это библиотека javascript, которая позволяет нашему клиентскому приложению взаимодействовать с цепочкой блоков. Мы настраиваем web3 внутри функции initWeb3.
- Я инициализируем контракты: мы извлекаем развернутый экземпляр смарт-контракта внутри этой функции и назначаем некоторые значения, которые позволят нам взаимодействовать с ним.
- Функция рендеринга: функция рендеринга размещает весь контент на странице с данными из смарт-контракта. На данный момент мы перечисляем только кандидатов, которые были созданы в смарт-контракте, и отображаем их в таблице. Мы также получаем текущую учетную запись, которая подключена к блокчейну внутри этой функции, и отображаем ее на странице.
Для html это простая веб-страница html. Ничего сложного.
Теперь давайте посмотрим на клиентское приложение в браузере. Во-первых, убедитесь, что вы перенесли свои контракты следующим образом:
Затем запустите сервер разработки из командной строки следующим образом:
Это должно автоматически открыть новое окно браузера с вашим клиентским приложением.
Убедитесь, что ваш локальный блокчейн работает в ганаше. Если ваш не работает, убедитесь, что номер порта в ganache совпадает с номером порта в файле truffle-config.js.
Также убедитесь, что вы вошли в метамаску и импортируете одну или две учетные записи из набора учетных записей ганаша в метамаску.
Импорт аккаунта в метамаску:
Шаг 1. В вашем запущенном приложении ganache выберите одну из учетных записей, которые вы хотите импортировать, и нажмите кнопку в правой части экрана.
Шаг 2: Откройте метамаску в браузере Chrome. Войдите в систему, если вы этого не сделали.
Шаг 3: Выберите сеть localhost из различных доступных вам сетей (localhost: 8545)
Шаг 4: Щелкните значок в правом верхнем углу и выберите учетную запись для импорта.
Шаг 5: Вставьте туда закрытый ключ, и ваша учетная запись была успешно импортирована.
Как только это будет сделано, когда вы обновите приложение, вы должны увидеть это
Шаг 3: голосование
Теперь нам нужно разрешить нашему приложению принимать голосование. Давайте поработаем над этой функцией. Под сопоставлением, которое мы объявили для кандидатов, мы объявим еще одно сопоставление для голосов.
Так же добавим функцию голосования в Избирательный договор.
Основная функциональность этой функции заключается в увеличении подсчета голосов кандидата путем считывания структуры Candidate из сопоставления «кандидаты» и увеличения «voteCount» на 1 с помощью оператора приращения (++). Давайте посмотрим на то, что он делает:
- Принимает один аргумент. Это целое число без знака с идентификатором кандидата.
- Его видимость является общедоступной, потому что мы хотим, чтобы это вызывала внешняя учетная запись.
- Он добавляет учетную запись, которая проголосовала, в только что созданное сопоставление избирателей. Это позволит нам отслеживать, проголосовал ли избиратель на выборах. Мы получаем доступ к учетной записи, которая вызывает эту функцию, с помощью глобальной переменной msg.sender, предоставленной Solidity.
- Он реализует операторы require, которые прекращают выполнение, если условия не выполняются. Сначала потребуйте, чтобы избиратель еще не голосовал. Мы делаем это, считывая адрес учетной записи с помощью «msg.sender» из сопоставления. Если он там есть, значит, аккаунт уже проголосовал. Затем требуется, чтобы идентификатор кандидата был действительным. Идентификатор кандидата должен быть больше нуля и меньше или равен общему количеству кандидатов.
Полный файл Election.sol должен выглядеть так:
Тестирование функции голосования
Теперь давайте добавим тест в наш тестовый файл «selection.js»:
Здесь мы хотим протестировать две вещи:
- Убедитесь, что функция увеличивает счетчик голосов за кандидата.
- Убедитесь, что избиратель добавляется к отображению всякий раз, когда он голосует.
Затем мы можем написать несколько тестов для требований нашей функции. Давайте напишем тест, чтобы убедиться, что наша функция голосования генерирует исключение для двойного голосования:
Мы можем утверждать, что транзакция не удалась и было возвращено сообщение об ошибке. Мы можем покопаться в этом сообщении об ошибке, чтобы убедиться, что сообщение об ошибке содержит подстроку «вернуться». Затем мы можем гарантировать, что состояние нашего контракта не изменилось, убедившись, что кандидаты не получили никаких голосов.
Теперь давайте напишем тест, чтобы предотвратить двойное голосование:
Сначала мы создадим тестовый сценарий с новым аккаунтом, который еще не проголосовал. Затем мы проголосуем за них. Потом попробуем проголосовать еще раз. Мы утверждаем, что здесь произошла ошибка. Мы можем проверить сообщение об ошибке и убедиться, что ни один кандидат не получил голосов, как и в предыдущем тесте.
Теперь давайте запустим наши тесты:
Ура, они проходят!
Фактическое голосование
Давайте добавим форму, позволяющую пользователям голосовать, под таблицей в файле index.html:
Давайте разберемся с этой формой:
- Мы создаем форму с пустым элементом выбора. Мы заполним варианты выбора кандидатами, предоставленными нашим смарт-контрактом, в файле «app.js».
- В форме есть обработчик onSubmit, который будет вызывать функцию castVote. Мы определим это в нашем файле «app.js».
Затем нам нужно обновить наш файл app.js, чтобы иметь возможность обрабатывать оба процесса, описанные выше. Нам нужен раскрывающийся список, чтобы можно было перечислить и выбрать кандидатов. Помните, что вы также можете использовать для этого переключатель. Затем мы скроем форму, когда учетная запись проголосует. Помните, что мы дадим возможность избирателю проголосовать только один раз.
Затем нам нужно написать функцию, которая вызывается при нажатии кнопки отправки, то есть мы голосуем. См. ниже:
Сначала мы запрашиваем в контракте идентификатор кандидата в форме. Когда мы вызываем функцию голосования из нашего смарт-контракта, мы передаем этот идентификатор и предоставляем текущей учетной записи метаданные функции «от». Это будет асинхронный вызов. Когда он будет готов, мы покажем загрузчик и скроем содержимое страницы. Каждый раз, когда голосование записывается, мы делаем обратное, снова показывая контент пользователю.
Теперь ваше интерфейсное приложение должно выглядеть так:
Идите вперед и попробуйте функцию голосования. Как только вы это сделаете, вы должны увидеть всплывающее окно с подтверждением Metamask, подобное этому:
В зависимости от вашей системы он может открывать новую вкладку вместо нового всплывающего окна.
После того, как вы нажмете «Отправить», вы успешно проголосовали! Вы по-прежнему будете видеть экран загрузки. На данный момент вам нужно обновить страницу, чтобы увидеть записанные голоса. В следующем разделе мы реализуем функцию обновления загрузчика автоматически.
Шаг 4. Наблюдайте за событиями
Мы хотим добавить в наше приложение отключение кнопки отправки при каждом голосовании. Мы делаем это, вызывая событие. Это позволит нам обновить наше клиентское приложение, когда учетная запись проголосовала. Мы начнем с объявления события в нашем контракте следующим образом:
Теперь мы можем вызвать это событие votedEvent внутри нашей функции «голосование» следующим образом:
Теперь, когда мы обновили наш контракт, мы должны запустить наши миграции:
Мы также можем обновить наши тесты, чтобы проверить это событие голосования следующим образом:
Этот тест проверяет квитанцию о транзакции, возвращаемую функцией «голосование», чтобы убедиться, что в ней есть журналы. Эти журналы содержат событие, которое было инициировано. Мы проверяем, что событие относится к правильному типу и имеет правильный идентификатор кандидата.
Новое: необходимо обновить клиентское приложение. Мы хотим убедиться, что приложение прослушивает проголосованное событие и запускает обновление страницы каждый раз, когда оно запускается. Мы можем сделать это с помощью такой функции «listenForEvents»:
Эта функция делает несколько вещей. Во-первых, мы подписываемся на проголосованное событие, вызывая функцию votedEvent. Мы передаем некоторые метаданные, которые говорят нам прослушивать все события в цепочке блоков. Затем мы «наблюдаем» за этим событием. Здесь мы подключаемся к консоли каждый раз, когда запускается votedEvent. Мы также повторно визуализируем весь контент на странице. Это позволит избавиться от загрузчика после того, как голосование будет записано, и отобразит обновленное количество голосов в таблице.
Наконец, мы можем вызывать эту функцию всякий раз, когда инициализируем контракт:
Теперь вы можете голосовать в своем клиентском приложении и наблюдать за голосами, записанными в режиме реального времени! Наберитесь терпения, событие может произойти через несколько секунд. Если вы не видите событие, попробуйте перезапустить Chrome. Есть известная проблема с Metamask, связанная с событиями. Для меня это всегда исправляет перезапуск Chrome.
Поздравляю! Фух, вот и все. Вы успешно создали полноценное децентрализованное приложение на блокчейне Ethereum! Уф .
Создание децентрализованного приложения Blockchain с помощью Vue и Tezos
В последние годы многие организации/частные лица внедрили технологию и разработку блокчейна. Технология блокчейн набирает популярность благодаря децентрализации и безопасности, обеспечиваемым хранением данных в блокчейне. Децентрализация здесь означает, что контроль и принятие решений осуществляются не отдельным лицом или централизованной организацией, а распределенной сетью. Можно сказать, что блокчейн — это его пользователи. В конечном итоге блокчейн обеспечивает очень безопасную сеть, которую невозможно взломать. Эта безопасность увеличивается по мере того, как в цепочку включается больше блоков.
Tezos — это блокчейн, созданный для настройки, адаптации и добавления функций и функций с помощью проверенного механизма обновления в сети. Это важный навык — научиться и понять, как подключить приложение Vuejs к смарт-контрактам, построенным на блокчейне Tezos. Владение токенами Tezos (tez) позволяет взаимодействовать с блокчейном Tezos. Вы можете хранить tez в цифровых кошельках, поддерживаемых Tezos. Дополнительную информацию о блокчейне Tezos вы можете найти здесь.
В этой статье вы узнаете, как взаимодействовать со смарт-контрактом для мемо-приложения, развернутого на блокчейне Tezos из приложения Vue. Чтобы продолжить изучение этой статьи, вам необходимы базовые знания Vue и Vuex; полный код проекта вы можете найти здесь.
Создание нашего приложения
Чтобы начать с нашего приложения Vue, мы создадим приложение Vue и добавим Vuex из CLI.
Выберите вариант конфигурации и продолжите настройку приложения. Для этой статьи мы выберем конфигурацию «По умолчанию ([Vue 3] babel, eslint)». После создания приложения вам нужно будет установить все необходимые зависимости для проекта.
Кроме того, нам нужно будет настроить webpack для устранения ошибок полифилла из-за webpack 5 в файле vue.config.js , который мы включим.
Настройка хранилища и поставщика RPC
Следующим шагом будет настройка состояния и действий. Мы создадим следующие файлы в папке магазина.
Я сосредоточусь на настройке подключения Tezos, поэтому перейду к файлу действий. Вы можете просмотреть содержимое других файлов store здесь.
В actions.js мы настроим подключение Tezos RPC к ithacanet, тестовой сети на блокчейне Tezos. Смарт-контракт, с которым мы будем работать, развернут на ithacanet. Для подключения к ithacanet у нас будет следующий код.
В строке 9 я настроил новый TezosToolkit со ссылкой RPC на тестовую сеть ithacanet; проверьте здесь ссылки на другие узлы RPC. В строке 10 мы устанавливаем соединение с Beacon; это позволяет нашему децентрализованному приложению (dApp) взаимодействовать с кошельком. Для получения дополнительной информации о Beacon вы можете посмотреть их официальную документацию.
Следующим шагом будет передача кошелька методом setWalletProvider на Tezos. В строке 17 у нас есть функция, которая подключается к смарт-контракту. Метод at принимает в качестве параметра адрес контракта (уникальный идентификатор смарт-контрактов, развернутых в блокчейне Tezos); кошелек для подписания контракта вызывает этот вариант использования. Кроме того, вы можете настроить другие форматы для подписания вызовов контракта через TezBridge или inMemory (используя закрытый ключ учетной записи). Подробнее о других форматах заключения договорных звонков вы можете прочитать здесь.
Подключение кошелька
Следующим действием будет установка подключения к кошельку в нашем dApp; для этого необходимо запросить разрешение на подключение к кошельку. В файле actions.js у меня есть функция connectWallet ; он запрашивает разрешение на подключение к кошельку.
В строке 4 запрос на подключение к кошельку инициируется методом requestPermissions ; эта функция передается кнопке подключения кошелька в приложении vue. При нажатии кнопки «Подключить кошелек» появится модальное окно с различными вариантами кошелька.
В этой статье я буду использовать кошелек храма, кошелек расширения браузера. Скачать расширение можно здесь. Как только запрос на подключение будет одобрен, действие connectWallet отправит checkWalletConnection .
Это действие проверяет, находится ли учетная запись с активным разрешением в кошельке в строке 4. Если активная учетная запись существует, pkh (хэш открытого ключа)/адрес учетной записи присваивается состоянию pkh, а состояние подключения истинно. Когда активной учетной записи не существует, параметрconnect имеет значение false, а pkh — пустая строка. Также необходимо отключить разрешение кошелька, и этого можно добиться, вызвав метод clearActiveAccount в кошельке:
Повтор сеанса с открытым исходным кодом
OpenReplay – это пакет для воспроизведения сеансов с открытым исходным кодом, который позволяет вам видеть, что пользователи делают в вашем веб-приложении, помогая вам быстрее устранять неполадки. OpenReplay размещается на собственном сервере для полного контроля над вашими данными.
Взаимодействие со смарт-контрактом
После настройки подключения к кошельку для приложения следующим шагом будет настройка взаимодействия смарт-контрактов и доступа к хранилищу контрактов. Вы можете просмотреть хранилище и методы смарт-контракта в смарт-контракте через сетевые обозреватели. Пример сетевого обозревателя для Tezos — Better Call Dev. Для предварительного просмотра контракта вам нужно будет ввести адрес контракта и выполнить поиск на платформе. Найти смарт-контракт для этого проекта в проводнике здесь
На изображении показана структура хранилища. У нас есть ключ для установки идентификатора для новой заметки, карта с парой идентификатора и адреса учетной записи в качестве ключа и объекта заметки в качестве значения, а также пользовательская карта, которая использует адрес учетной записи в качестве ключа и набор идентификаторов заметок, привязанных к адрес аккаунта.
На этом изображении видно, что смарт-контракт имеет четыре метода: addMemo , deleteMemo , toggleMemoStatus и updateMemo .
Доступ к хранилищу контрактов
Следующим действием будет доступ к хранилищу контрактов и отображение заметок, существующих в хранилище. Я буду делать это в функции getMemoList в файле действий.
Вам нужно вызвать метод storage в контракте, чтобы получить доступ к хранилищу контракта, как показано в строке 9. Чтобы получить доступ к набору идентификаторов мемо для текущей подключенной учетной записи, вызовите метод get для пользователей и передайте ключ для значения для доступа ; в данном случае адрес, подключенный к dApp. Это вернет массив больших чисел. В строке 11 мы перебираем набор, чтобы преобразовать большие числа в числа. Обновленный набор перебирается, чтобы получить все заметки с идентификатором, принадлежащим активному адресу в строках с 13 по 25. Впоследствии состояния active_memo и done_memo обновляются заметками, возвращенными из хранилища.
Выполнение вызовов смарт-контрактов из приложения Vue
Из изображения 3 мы знаем, что смарт-контракт имеет четыре метода, с которыми можно взаимодействовать. Метод addMemo позволяет создать новую заметку, принимая строку заметки в качестве значения.
В строке 4 смарт-контракт инициируется вызовом метода send() . Строка 5 ожидает подтверждения транзакции в блокчейне и отправляет действие the softUpdateMemoList . softUpdateMemoList похож на getMemoList , с той лишь разницей, что он не обновляет состояние loading .
Следующий метод смарт-контракта — deleteMemo ; это удаляет существующую заметку учетной записью, которая создала заметку. Он принимает идентификатор заметки в качестве параметра. N/B: идентификатор заметки должен быть строкой.
Чтобы переключить памятку, вы вызовете метод toggleMemoStatus в контракте. deleteMemo также принимает идентификатор заметки и должен вызываться из учетной записи, которая создала заметку.
метод против методовОбъект
Метод updateMemo принимает в качестве параметра объект со свойствами memo и id. Ранее я инициировал вызовы смарт-контрактов в таком формате:
Последовательность вызова контракта не будет работать, если вам нужно передать объект в качестве параметра методу смарт-контракта. Для этого вы будете использовать действие methodObject , которое показано в действии updatedMemo :
в строке 4 вместо method используется methodObject .
Заключение
Децентрализованное приложение завершено, и все методы смарт-контрактов интегрированы в приложение. Вы можете развернуть приложение на любой платформе, которая поддерживает приложения Vue. Предположим, вы хотите пойти дальше и развернуть приложение на децентрализованной платформе хостинга, такой как Fleek. В таком случае вы можете найти документацию по достижению этого здесь.
В этой статье мы прошли весь процесс интеграции смарт-контракта, развернутого на блокчейне Tezos, в приложение Vue. Если вы дошли до этого момента, вы сможете подключиться к кошельку и совершать вызовы смарт-контрактов в блокчейне Tezos. Если вы хотите научиться писать смарт-контракты, посмотрите эту документацию. Вы также можете найти полный код проекта здесь и живую версию приложения здесь. Ура.
Как создать dApp за три шага
Децентрализованные приложения или dApps, — это приложения, которые не полагаются на централизованный сервер или бэкэнд, а используют технологии Web3, такие как блокчейн и оракулы для хранения своей логики и функций бэкэнда, что делает их защищенными от взлома и безопасными.
В этом техническом руководстве вы узнаете, как создать простой сквозной dApp, который позволяет пользователю получать и хранить текущую цену Ethereum в смарт-контракте. Готовую демонстрационную версию можно найти на GitHub.
Требования
Пожалуйста, убедитесь, что у вас установлено следующее:
Что такое децентрализованное приложение?
В dApp код бэкенда работает на блокчейне, в отличие от традиционного приложения, где код бэкенда работает на централизованных серверах. dApp может иметь внешний код и пользовательские интерфейсы, написанные на любом языке и развернутые на любом сервере или серверах для взаимодействия с внутренней логикой.
Благодаря тому, что логика бэкенда размещается в высокозащищенных, защищенных от взлома смарт-контрактах, dApp имеют множество преимуществ, недоступных для традиционных систем Web2:
нулевое время простоя
устойчивость к цензуре
выполнение логики с минимальным уровнем доверия
Однако эти преимущества имеют и некоторые недостатки. Обслуживание dApps требует больших усилий, поскольку код, развернутый на блокчейне, по умолчанию не подлежит изменению. Кроме того, из-за того, что логика выполняется в распределенной сети, а не на централизованном сервере, повышаются и эксплуатационные расходы. В дополнение к этому, пользовательский опыт может пострадать из-за того, что пользователю dApp необходимо пройти через сложности, связанные с созданием кошелька Web3 и пополнением его достаточным количеством криптовалюты для оплаты комиссий за транзакции.
Компоненты dApp
Компоненты dApp можно разделить на три различные категории: смарт-контракты, фронтенд-логика и пользовательский интерфейс, а также хранилище данных.
Смарт-контракты Умные контракты хранят бизнес-логику dApp, а также состояние приложения. Это самое большое отличие dApp от традиционного веб-приложения, и именно это дает dApp все преимущества, упомянутые выше.
Фронтенд/интерфейс пользователя В то время как логика бэкенда dApp требует от разработчика написания кода смарт-контракта для развертывания на блокчейне, фронтенд или клиентская часть dApp может использовать стандартные веб-технологии, такие как HTML и JavaScript. Это позволяет разработчикам использовать знакомые инструменты, библиотеки и фреймворки. Пользовательский интерфейс на стороне клиента обычно связан со смарт-контрактами через клиентские библиотеки, такие как Web3.js или Ethers.js, которые поставляются в комплекте с ресурсами фронтенда и отправляются в браузер вместе с пользовательским интерфейсом. Взаимодействие со смарт-контрактами, такое как подписание сообщений и отправка транзакций смарт-контрактам, обычно осуществляется через браузерный Web3-кошелек, например MetaMask.
Хранение данных Большинству приложений необходимо хранить данные, но из-за распределенной природы блокчейн хранение больших объемов данных на цепочке нецелесообразно и может оказаться очень дорогим. Поэтому многие dApp, которым необходимо хранить данные, используют офф-чейн сервисы хранения данных, такие как IPFS или Filecoin, оставляя блокчейн только для хранения важной бизнес-логики и состояния.
Можно также использовать традиционные облачные сервисы хранения данных. Однако многие разработчики выбирают децентрализованные варианты, чтобы сохранить и расширить свойства минимизации доверия, которые обеспечивает dApp на базе блокчейна.
Архитектура Ethereum dApp
Теперь, когда мы знаем компоненты dApp, давайте рассмотрим пример создания простого сквозного контракта.
Шаг первый: создание смарт-контракта
Смарт-контракт в нашем dApp будет простым примером, используемым для поиска данных и отражения изменений состояния на блокчейне. В данном случае мы будем искать стоимость ETH/USD, используя ETH/USD Data Feed, а затем постоянно сохранять результат в смарт-контракте.
Первым делом откройте документацию и перейдите на страницу Using Data Feeds. Оттуда вы можете скопировать исходный код примера и вставить его в новый файл в выбранной вами IDE (например, Visual Code), либо нажать кнопку «Open In Remix» и работать из веб-версии Remix.
В этом примере мы будем работать с Visual Studio Code и Hardhat, фреймворком для разработки виртуальной машины Ethereum.
Сначала мы создадим новую структуру каталогов для нашего dApp с папкой backend для кода смарт-контракта:
Далее мы откроем созданную директорию для нашего dApp в редакторе VS Code, а затем установим Hardhat:
После этого удалите файл Touch.sol в папке «contracts», создайте новый файл в этой папке под названием PriceConsumerV3.sol и сохраните. Здесь мы создадим наш смарт-контракт, поэтому скопируйте код из примера в документации Chainlink в этот файл и сохраните его.
В коде примера вы увидите, что в демо-контракте уже есть функция getLatestPrice для поиска текущей цены Ethereum на Rinkeby ETH/USD Data Feed.
Нам нужно создать новую переменную и новую функцию для хранения этого значения в смарт-контракте. Первым шагом будет создание новой переменной под существующей priceFeedone для хранения цены Ethereum:
Далее нам нужно создать новую функцию, которая будет вызываться фронтендом dApp. Эта функция должна искать последнюю цену Ethereum, вызывая существующую функцию getLatestPrice. Затем она должна сохранить это значение в новом параметре storedPrice:
Ваш новый контракт должен выглядеть следующим образом:
Шаг второй: развертывание смарт-контракта
Теперь вы готовы скомпилировать и развернуть свой контракт в тестовой сети Rinkeby. Не забудьте сначала пополнить свой кошелек MetaMask некоторым количеством Rinkeby ETH.
Если вы используете Remix, вы можете скомпилировать и развернуть свой контракт, используя стандартный процесс Remix. Если вы используете IDE, например Visual Studio Code, мы рекомендуем использовать Hardhat для управления контрактами.
Первым шагом к компиляции и развертыванию вашего контракта является установка библиотеки инструментов Hardhat, библиотеки контрактов Chainlink и библиотеки dotenv для хранения паролей и секретных ключей в отдельном файле .env:
Затем замените содержимое файла hardhat-config.js на следующее:
Следующим шагом будет создание файла .env в папке бэкенда. Затем вам нужно извлечь ваш приватный ключ из кошелька Web3 и вставить его в секцию значения поля PRIVATE_KEY в файле .env. Пожалуйста, убедитесь, что вы используете новый кошелек Web3, на котором нет средств в mainnet.
После этого вам необходимо получить конечную точку RPC для доступа к сети Rinkeby. Это можно сделать, вставив URL RPC в поле RINKEBY_RPC_URL в файле .env. Мы рекомендуем подписаться на бесплатную учетную запись Infura или Alchemy, чтобы получить URL RPC.
Создание файла .env
Следующим шагом будет изменение содержимого файла deploy.js в папке ‘scripts’, чтобы убедиться, что он развернет ваш новый контракт. Откройте файл и убедитесь, что следующий код заменяет уже имеющийся. Это просто возьмет ваш скомпилированный контракт PriceConsumerV3 и попытается развернуть его. Не забудьте сохранить изменения.
Теперь вы готовы составить и развернуть свой смарт-контракт в сети Rinkeby с помощью Hardhat:
Вы должны увидеть сообщение, подобное приведенному ниже, в котором будет указан адрес на Rinkeby, на который был развернут ваш смарт-контракт. Запишите этот адрес, он понадобится нам для следующего шага.
Развернутый смарт-контракт
Поздравляем, теперь вы готовы перейти к фронтенд-части вашего dApp!
Шаг 3: Создание фронтенд-приложения
Логика фронтенда и пользовательский интерфейс вашего dApp могут быть построены с использованием широкого спектра различных фреймворков.
React — одна из самых популярных библиотек JavaScript для создания многофункциональных пользовательских веб-интерфейсов, поэтому она используется во многих Web3 dApp. Кроме того, Ethers.js — это библиотека JavaScript для подключения и взаимодействия с блокчейнами и смарт-контрактами на базе EVM. Если объединить эти два компонента, вы получите разумную отправную точку для создания фронтенда вашего dApp.
В этом разделе мы создадим новое приложение React с помощью генератора шаблонов create-react-app. Затем мы внедрим офф-чейн логику, использующую Ethers.js для связи пользовательского интерфейса с развернутым смарт-контрактом, что позволит нам создать полноценный сквозной dApp.
Создание React-приложения Первым шагом для создания фронтенда является установка и реализация проекта create-react-app boilerplate, а затем его модификация для нашего dApp. Первым шагом будет установка библиотеки в новую папку «frontend»:
После этого в вашем проекте должна появиться новая папка «frontend» со всем связанным с ней кодом React. Раскройте папку «frontend» и выполните следующие действия:
Структура папок должна выглядеть следующим образом:
Структура папок React front-end
Теперь мы почти готовы приступить к изменению кода приложения React. Но сначала не забудьте установить библиотеки для Bootstrap и Ethers.js. Bootstrap — это популярный CSS-фреймворк для фронтенда, который поставляется с удобными для React виджетами пользовательского интерфейса с наложенной стилизацией CSS, а Ethers.js позволяет нам подключить наш фронтенд к развернутым смарт-контрактам на блокчейне. Убедитесь, что эти команды выполняются из папки «frontend».
Теперь мы готовы к изменению кода приложения React. Откройте файл App.js в папке /src/ и удалите его содержимое. Мы начнем создавать его с нуля.
Первый шаг — сообщить приложению, что мы хотим использовать React (включая библиотеки useEffect и useState) и Ethers.js:
Затем создайте функцию под названием «App» и экспортируйте ее:
Теперь мы начнем заполнять содержимое функции «App». Добавьте в нее следующий код. Этот код делает следующее:
Устанавливает реактивные хуки storedPrice и setStoresPrice. Создает соединение с вашим кошельком MetaMask Web3. Устанавливает адрес развернутого смарт-контракта и ABI. Оба эти параметра необходимы Ethers.js для взаимодействия с развернутым смарт-контрактом. Адрес смарт-контракта можно получить из шага развертывания, описанного ранее в этом руководстве. Вставьте это значение вместо строки REPLACE_WITH_DEPLOYED_CONTRACT_ADDRESS. ABI смарт-контракта можно получить из файла /backend/artifacts/contracts/PriceConsumerV3.json, в элементе abi. Вы можете использовать минификатор кода, чтобы отформатировать его в лучшем виде для хранения в вашем приложении.
Теперь мы создадим две функции, которые будут использоваться в нашем приложении:
getStoredPrice подключится к развернутому смарт-контракту и получит текущее значение геттер-функции storedPrice(). Функция setNewPrice будет вызывать функцию storeLatestPrice развернутого смарт-контракта, ждать завершения транзакции, а затем вызывать функцию getStoredPrice для получения сохраненной в смарт-контракте цены. Мы также добавим вызов getStoredPrice в нашу функцию App, чтобы она первоначально вызывала функцию getter при загрузке страницы:
Последним шагом в создании фронтенда является возврат JSX-кода для рендеринга браузером. Вставьте следующий код в нижней части функции App, под вызовом getStorePrice(). Этот код делает следующее:
Возвращает простой двухколоночный макет сетки. Первый столбец содержит текущую хранимую цену ETH/USD в смарт-контракте. Второй столбец содержит кнопку, которую пользователь может использовать для взаимодействия с умным контрактом и обновления сохраненной цены. Нажатие кнопки вызывает функцию setNewPrice, описанную выше.
Теперь ваше приложение готово. При необходимости вы можете сравнить свой код с готовым примером, чтобы убедиться, что вы все сделали правильно. Теперь вы готовы к запуску вашего dApp.
Запуск приложения dApp Убедившись, что все файлы сохранены, запустите свой dApp локально, выполнив следующую команду из папки frontend:
После загрузки приложения в вашем браузере должно появиться новое окно, отображающее пользовательский интерфейс dApp. Вы также должны получить всплывающее уведомление от MetaMask с просьбой подключить ваш кошелек к приложению.
Фронтенд React
После того как вы убедитесь, что пополнили свой счет в MetaMask некоторым количеством Rinkeby ETH, нажмите кнопку «Обновить» в пользовательском интерфейсе dApp, чтобы взаимодействовать с развернутым смарт-контрактом в сети Rinkeby. Вы должны получить уведомление от MetaMask с просьбой подтвердить транзакцию. После этого в течение нескольких секунд ваш dApp должен автоматически обновиться, а в разделе «Сохраненная цена» появится текущая цена Ethereum:
Фронтенд React, показывающий результат работы Data Feed
Поздравляем, теперь вы успешно создали, развернули и взаимодействовали с простым dApp! В этом руководстве вы просто запустите фронтенд локально на своем компьютере, но при желании вы можете развернуть его на облачном сервере или даже децентрализовать фронтенд и развернуть его на IPFS! Вы также можете поработать с CSS приложения, чтобы изменить внешний вид пользовательского интерфейса.
Резюме
Децентрализованные приложения — это приложения, которые заменяют традиционную обработку данных на внутреннем сервере технологиями Web3, такими как блокчейн и смарт-контракты, что дает им уникальные гарантии безопасности и устойчивости к цензуре, которые невозможны для традиционных веб-приложений.
Tutorial: как создать полноценное децентрализованное приложение (Dapp)
Сегодня я расскажу вам, как создать свое первое децентрализованное приложение, или dApp, в блок-цепочке Ethereum. Я покажу вам, как написать свой первый смартфон «Эфириум», где мы проведем выборы между двумя кандидатами. Мы будем писать тесты против смарт-контракта, развертывать его в блок-цепочке Ethereum и разрабатывать клиентское приложение, которое позволяет учетным записям голосовать. Мы также рассмотрим ключевые понятия, такие как «что такое блок-цепь?», «Что такое умный контракт?» И «Как работает dApp?».
Вы можете посмотреть, как я создаю полное децентрализованное приложение в двухчасовом видео выше. Я также расскажу вам о пошаговых инструкциях в этом уроке. Прежде чем мы начнем строить dApp, давайте рассмотрим некоторые ключевые понятия. Если вы хотите начать кодирование, не стесняйтесь перейти к следующей части учебника.
Вы также можете бесплатно загрузить весь видеоконтент на полный 2-часовой видеоурок здесь бесплатно.
Что такое блокчейн?
Давайте использовать аналогию, чтобы понять, что такое блок-цепочка и как она работает. Давайте посмотрим на веб-приложение.
Обычно, когда вы взаимодействуете с веб-приложением, вы используете веб-браузер для подключения к центральному серверу по сети. Весь код этого веб-приложения живет на этом центральном сервере, и все данные хранятся в центральной базе данных. В любое время, когда вы совершаете транзакцию с вашим приложением, необходимо обмениваться данными с этим центральным сервером в Интернете.
Если бы мы создали наше приложение для голосования в Интернете, у нас возникли бы несколько проблем:
Данные в базе данных можно было бы изменить: их можно было бы пересчитать более одного раза или полностью удалить.
Исходный код на веб-сервере также может быть изменен в любое время.
Мы не хотим создавать наше приложение в Интернете. Мы хотим построить его на блочной цепочке, где любой человек, подключенный к сети, может участвовать в выборах. Мы хотим, чтобы их голоса были подсчитаны, и что они учитываются только один раз. Итак, давайте посмотрим, как это работает.
Вместо того, чтобы иметь сеть, центральный сервер и базу данных, блок-цепочка представляет собой сеть и базу данных, все в одном. Блок-цепочка представляет собой одноранговую сеть компьютеров, называемых узлами, которые совместно используют все данные и код в сети. Итак, если вы подключены к блочной цепочке, вы являетесь узлом в сети, и вы говорите со всеми другими компьютерными узлами в сети. Теперь у вас есть копия всех данных и кода на блок-цепочке. Центральных серверов больше нет. Просто куча компьютеров, которые разговаривают друг с другом в одной сети.
Вместо централизованной базы данных все данные транзакций, которые совместно используются узлами в цепочке блоков, содержатся в пучках записей, называемых блоками, которые соединены вместе для создания публичной книги. Этот публичный регистр представляет все данные в блок-цепочке. Все данные в публичной книге защищены криптографическим хешированием и подтверждены согласованным алгоритмом. Узлы в сети участвуют в обеспечении того, чтобы все копии данных, распределенных по сети, были одинаковыми. Это одна очень важная причина, по которой мы строим наше приложение для голосования по блочной цепочке, потому что мы хотим, чтобы наш голос был подсчитан и что он не изменился.
Как это выглядело бы для пользователя нашего приложения, чтобы проголосовать за блок-цепочку? Ну, для начала пользователю нужна учетная запись с адресом кошелька с некоторыми криптовалютами Ether, Ethereum. Как только они подключаются к сети, они отдают свой голос и платят небольшую комиссию за транзакцию, чтобы написать эту транзакцию в блок-цепочку. Эта комиссия за транзакцию называется «газ». Всякий раз, когда проводится голосование, некоторые из узлов в сети, называемые шахтерами, конкурируют за выполнение этой транзакции. Шахтер, который завершает эту транзакцию, получает Эфир, который мы заплатили, чтобы проголосовать.
В качестве резюме, когда я проголосую, я плачу цену за газ, и, когда мой голос записывается, одному из компьютеров в сети платят плату за Ether. Я в свою очередь уверен, что мой голос был записан точно навсегда.
Поэтому важно также отметить, что голосование по блочной цепи стоит Эфир, но просто увидеть список кандидатов нет. Это потому, что чтение данных из блокчейки является бесплатным, но писать на него нет.
Что такое смарт-договор?
Вот как работает процесс голосования, но как мы на самом деле кодируем наше приложение? Ну, блок-цепочка Ethereum позволяет нам выполнять код с виртуальной машиной Ethereum (EVM) на блочной цепочке с чем-то, называемым смарт-контрактом.
Смарт-контракты — это то, где живет вся бизнес-логика нашего приложения. Здесь мы фактически будем кодировать децентрализованную часть нашего приложения. Смарт-контракты отвечают за чтение и запись данных в блок-цепь, а также за выполнение бизнес-логики. Интеллектуальные контакты написаны на языке программирования Solidity, который очень похож на Javascript. Это полномасштабный язык программирования, который позволит нам выполнять многие из тех вещей, которые Javascript способен, но он ведет себя по-другому по причине использования, как мы увидим в этом уроке.
Функция интеллектуальных контрактов на блок-цепочке очень похожа на микросервис в сети. Если публичный регистр представляет собой уровень базы данных блочной цепи, тогда интеллектуальные контракты заключаются в том, что вся бизнес-логика, которая осуществляет транзакции с этими данными, живет.
Кроме того, они называются умными контрактами, потому что они представляют собой соглашение или соглашение. В случае нашего голосования dApp, это соглашение, согласно которому мой голос будет считаться, что другие голоса учитываются только один раз и что кандидат с большинством голосов фактически выиграет выборы.
Теперь давайте кратко рассмотрим структуру dApp, которую мы создаем.
У нас будет традиционный внешний клиент, который написан в HTML, CSS и Javascript. Вместо того, чтобы разговаривать с внутренним сервером, этот клиент будет подключаться к локальной цепочке Ethereum, которую мы будем устанавливать. Мы будем кодировать всю бизнес-логику о нашем dApp в интеллектуальном контракте Election с языком программирования Solidity. Мы применим этот смарт-контракт к нашей локальной цепочке Etherum и разрешим учетным записям начать голосование.
Теперь мы видели, что такое блок-цепочка и как она работает. Мы видели, почему мы хотим построить наш dApp для голосования по блочной цепочке вместо текущей сети. И мы видели, что мы хотим закодировать наш dApp, написав смарт-контракт, который будет развернут в блок-цепочку Ethereum. Теперь давайте начнем программировать!
Что мы будем строить
Вот демонстрация голосования dApp, который мы будем строить.
Мы создадим клиентское приложение, которое поговорит с нашим умным контрактом на блок-цепочке. Это клиентское приложение будет иметь таблицу кандидатов, в которой перечислены идентификатор, имя и количество голосов каждого кандидата. Он будет иметь форму, где мы можем проголосовать за желаемого кандидата. Он также показывает учетную запись, с которой мы подключаемся к блочной цепочке, в разделе «Ваша учетная запись».
Установка зависимостей
Сопутствующие видеоматериалы для этой части учебника начинаются с 8:53.
Чтобы построить наш dApp, нам нужно сначала несколько зависимостей.
Node Package Manager (NPM)
В первую очередь нам нужно Node Package Manager, или NPM, который поставляется с Node.js. Вы можете увидеть, есть ли у вас узел, который уже установлен, перейдя к вашему терминалу и типу:
Truffle Framework
Далее Truffle Framework, что позволяет нам создавать децентрализованные приложения на блок-цепочке Ethereum. Он предоставляет набор инструментов, которые позволяют нам писать интеллектуальные контакты с языком программирования Solidity. Это также позволяет нам проверять наши умные контракты и разворачивать их в цепочку. Это также дает нам возможность разрабатывать наше клиентское приложение.
Вы можете установить Truffle с NPM в командной строке следующим образом:
Ganache
Далее Ganache, локальный блок-цепочка в памяти. Вы можете установить Ganache, загрузив его с веб-сайта Truffle Framework. Он предоставит нам 10 внешних счетов с адресами на нашей локальной блок-цепочке Ethereum. Каждая учетная запись предварительно загружается 100 фальшивым эфиром.
Metamask
Далее Metamask extension for Google Chrome. Чтобы использовать блок-цепочку, мы должны подключиться к ней (помните, я сказал, что цепочка блоков — это сеть). Мы должны установить специальное расширение браузера, чтобы использовать цепочку блоков Ethereum. В это место входит метамаск. Мы сможем подключиться к нашей локальной сети Ethereum с нашей личной учетной записью и взаимодействовать с нашим умным контрактом.
Мы собираемся использовать расширение Metamask chrome для этого учебника, поэтому вам также потребуется установить браузер Chrome Chrome, если у вас его еще нет. Чтобы установить Metamask, найдите плагин Metamask Chrome в веб-магазине Google Chrome. После того, как вы установили его, убедитесь, что он указан в вашем списке расширений. Когда он будет установлен, вы увидите значок лисы в верхней правой части браузера Chrome. Ссылка на видео пройдите, если вы застряли!
Подсветка синтаксиса
Зависимость необязательна, но рекомендуется. Я рекомендую установить подсветку синтаксиса для языка программирования Solidity. Большинство текстовых редакторов и IDE не выделяют синтаксис для Solidity из коробки, поэтому вам придется установить пакет для поддержки этого. Я использую Sublime Text, и я загрузил «Ethereum» packagethat, обеспечивающий отличную подсветку синтаксиса для Solidity.
Шаг 1
Сопровождающий видеоматериал для этой части учебника начинается в 11:40. Здесь вы можете загрузить код этой части учебника. Не стесняйтесь использовать их в качестве ориентира, если вы застряли!
Теперь, когда у нас установлены наши зависимости, давайте начнем строить наш dApp!
Сначала найдите, где вы загрузили Ganache, и откройте его. Теперь, когда Ganache загрузился, у вас работает локальная цепочка.
Ganache дал нам 10 учетных записей, предварительно загруженных 100 фальшивыми эфирами (это ничего не стоит в главной сети Ethereum). Каждая учетная запись имеет уникальный адрес и закрытый ключ. Каждый адрес учетной записи будет служить уникальным идентификатором для каждого избирателя на наших выборах.
Теперь давайте создадим каталог проекта для нашего dApp в командной строке следующим образом:
Теперь, когда мы находимся внутри нашего проекта, мы можем быстро встать и Truffle box. Будем использовать Pet Shop box для этого урока. Внутри каталога проекта установите окно магазина домашних животных из командной строки следующим образом:
Вот что pet shop box имеет:
- contracts directory: this is where all smart contacts live. We already have a Migration contract that handles our migrations to the blockchain.
- migrations directory: это — то, где живут все файлы миграции. Эти миграции аналогичны другим структурам веб-разработки, которые требуют миграции для изменения состояния базы данных. Всякий раз, когда мы разворачиваем смарт контракты в блокчейне, мы обновляем состояние blockchain и, следовательно, нуждаемся в миграции.
- node_modules directory: это является домом для всех наших зависимостей Node.
- src directory: здесь мы разработаем наше клиентское приложение.
- test directory: this is where we’ll write our tests for our smart contracts.
- truffle.js file: this is the main configuration file for our Truffle project
Теперь давайте начнем писать наш умный контракт! Этот смарт-контракт будет содержать всю бизнес-логику нашего dApp. Он будет следить за чтением и записью в блок-цепочку Ethereum. Это позволит нам перечислить кандидатов, которые будут баллотироваться на выборах, и следить за всеми голосами и избирателями. Он также будет регулировать все правила выборов, например, принуждать счета только голосовать один раз. Из корня вашего проекта, вперед и создайте новый файл контракта в каталоге контрактов следующим образом:
Начнем с создания «теста на дым», который обеспечит правильную настройку нашего проекта и что мы сможем успешно заключить контракт с блочной цепью. Откройте файл и начните со следующего кода:
Позвольте мне объяснить этот код. Мы начнем с объявления версии прочности с помощью pragma solidity заявление. Затем мы объявляем интеллектуальный контракт с ключевым словом «контракт», за которым следует название контракта. Затем мы объявляем переменную состояния, которая будет хранить значение имени кандидата. Переменные состояния позволяют нам записывать данные в блок-цепь. Мы заявили, что эта переменная будет строкой, и мы установили ее видимость public . Поскольку он является общедоступным, надежность дает нам бесплатную функцию getter, которая позволит нам получить доступ к этой ценности за пределами нашего контракта. Мы увидим это в действии позже в консоли!
Затем мы создаем функцию-конструктор, которая будет вызываться при каждом разворачивании смарт-контракта в цепочку. Здесь мы установим значение переменной состояния кандидата, которая будет сохранена в блок-цепочке после миграции. Обратите внимание, что функция конструктора имеет то же имя, что и смарт-контракт. Так Solidity знает, что функция является конструктором.
Теперь, когда мы создали основу для смарт-контракта, давайте посмотрим, можно ли его развернуть в блок-цепочку. Для этого нам нужно создать новый файл в каталоге миграции. Из корня проекта создайте новый файл из командной строки следующим образом:
Обратите внимание, что мы сопоставляем все наши файлы внутри каталога миграции с номерами, чтобы Truffle знал, к какому приказу их выполнить. Давайте создадим новую миграцию, чтобы развернуть контракт следующим образом:
Во-первых, мы требуем контракт, который мы создали, и назначим его переменной под названием «Выборы». Затем мы добавим его в манифест развернутых контрактов, чтобы обеспечить его развертывание при запуске миграции. Теперь давайте проверим наши миграции из командной строки следующим образом:
Теперь, когда мы успешно перенесли наш смарт-контракт на локальную блок-цепочку Ethereum, давайте откроем консоль для взаимодействия со смарт-контрактом. Вы можете открыть консоль трюфелей из командной строки следующим образом:
Теперь, когда мы находимся внутри консоли, давайте получим экземпляр нашего развернутого смарт-контракта и посмотрим, можем ли мы прочитать имя кандидата из контракта. С консоли запустите этот код:
Election это имя переменной, которую мы создали в файле миграции. Мы получили развернутый экземпляр контракта с deployed() функции и назначил ее app переменная внутри функции обратного вызова обещания. Сначала это может показаться немного запутанным, но вы можете обратиться к демонстрации консоли в видео в 21:50 для дальнейшего объяснения.
Теперь мы можем прочитать значение переменной-кандидата следующим образом:
Congratulations! You’ve just written your first smart contract, deployed to the blockchain, and retrieved some of its data.
Создаём лист кандидатов — Шаг 2
Сопровождающие видеоматериалы для этой части учебника начинаются в 27:11. Здесь вы можете загрузить код этой части учебника. Не стесняйтесь использовать их в качестве ориентира, если вы застряли!
Теперь, когда все настроено правильно, давайте продолжим строить smart contract, представив кандидатов, которые будут баллотироваться на выборах. Нам нужен способ хранения нескольких кандидатов и хранения нескольких атрибутов о каждом кандидате. Мы хотим отслеживать идентификатор, имя и количество голосов кандидата. Вот как мы будем моделировать кандидата:
Мы моделировали кандидата с помощью Solidity Struct. Solidity позволяет нам создавать наши собственные типы структуры, как это было сделано для нашего кандидата здесь. Мы указали, что эта структура имеет id беззнакового целочисленного типа, имя типа строки и voteCount беззнакового целочисленного типа. Просто объявление этой структуры фактически не даст нам кандидата. Нам нужно создать экземпляр и назначить его переменной, прежде чем мы сможем записать ее на хранение.
Следующее, что нам нужно, — это место для хранения кандидатов. Нам нужно место для хранения одного из типов структуры, которые мы только что создали. Мы можем сделать это с помощью Solidity mapping. Отображение в Solidity похоже на ассоциативный массив или хэш, который связывает пары ключ-значение. Мы можем создать это отображение следующим образом:
В этом случае ключом к отображению является unsigned integer,и значение — это тип структуры кандидата, который мы только что определили. Это, по сути, дает нам идентификационный поиск каждого кандидата. Поскольку это сопоставление присваивается переменной состояния, мы будем записывать данные в блок-цепочку в любое время, когда мы назначаем ему новые пары ключ-значение. Затем мы устанавливаем видимость этого отображения для public чтобы получить функцию геттера, как и мы с именем кандидата в тесте дыма.
Затем мы отслеживаем, сколько кандидатов существует на выборах с переменной состояния счетчика кеша, например:
В Solidity нет способа определить размер отображения, и нет возможности перебирать его. Это потому, что любой ключ в сопоставлении, которому еще не присвоено значение, вернет значение по умолчанию (в этом случае будет пустой кандидат). Например, если у нас было только 2 кандидата на этих выборах, и мы попытаемся найти кандидата № 99, то отображение вернет пустую структуру кандидата. Такое поведение не позволяет узнать, сколько кандидатов существует, и поэтому мы должны использовать счетчик кеша.
Затем давайте создадим функцию для добавления кандидатов к создаваемому нами сопоставлению:
Мы объявили функцию addCandidate который принимает один аргумент строкового типа, который представляет имя кандидата. Внутри функции мы увеличиваем кеш-счетчик кандидатов, чтобы обозначить, что добавлен новый кандидат. Затем мы обновляем сопоставление с новой структурой кандидата, используя текущий счетчик кандидатов в качестве ключа. Эта структура кандидата инициализируется идентификатором-кандидатом из текущего подсчета кандидатов, именем из аргумента функции и начальным подсчетом голосов до 0. Обратите внимание, что видимость этой функции является private, потому что мы хотим только вызвать ее внутри контракта.
Теперь мы можем добавить двух кандидатов на наши выборы, дважды вызвав функцию addCandidate внутри функции конструктора, например:
Эта миграция будет выполняться, когда мы разворачиваем контракт на блок-цепочку и заполняем наши выборы двумя кандидатами. На этом этапе ваш полный код контракта должен выглядеть следующим образом:
Now let’s migrate our contract like this:
Теперь попробуйте взаимодействовать с кандидатами внутри консоли. Вы можете следить за мной, пока я демонстрирую это в видео в 37:31. Я оставлю это вам как упражнение.
Теперь давайте напишем несколько тестов, чтобы убедиться, что наш интеллектуальный контракт инициализирован правильно. Во-первых, позвольте мне объяснить, почему тестирование так важно, когда вы разрабатываете смарт-контракты. Мы хотим обеспечить, чтобы контракты были свободны по нескольким причинам:
1. Весь код в цепочке Ethereum неизменен; он не может измениться. Если в контракте содержатся какие-либо ошибки, мы должны отключить его и развернуть новую копию. Эта новая копия не будет иметь такое же состояние, как старый договор, и у нее будет другой адрес.
2. Развертывание контрактов требует газа, поскольку оно создает транзакцию и записывает данные в цепочку. Это стоит Ethere, и мы хотим минимизировать количество эфира, которое когда-либо приходилось платить.
3. Если какая-либо из наших контрактных функций, которые записывают в блок-цепочку, содержат ошибки, учетная запись, которая вызывает эту функцию, может потенциально потерять эфир, и она может не соответствовать ожидаемому.
Тестирование
Теперь давайте напишем несколько тестов. Убедитесь, что вы запускаете Ganache. Затем создайте новый тестовый файл в командной строке из корня вашего проекта следующим образом:
Мы напишем все наши тесты в Javascript внутри этого файла с помощью Mocha testing framework и Chai assertion library. Они поставляются в комплекте с каркасом Truffle. Мы напишем все эти тесты в Javascript, чтобы имитировать взаимодействие на стороне клиента с нашим смарт-контрактом, как и в консоли. Вот код для тестов:
Позвольте мне объяснить этот код. Во-первых, нам требуется потребовать контракт и назначить его переменной, как это было в файле миграции. Затем мы называем функцию «Contract» и записываем все наши тесты в функцию обратного вызова. Эта функция обратного вызова предоставляет переменную «accounts», которая представляет все учетные записи на нашей блочной цепочке, предоставляемые Ganache.
Первый тест проверяет, что контракт был инициализирован с правильным количеством кандидатов, путем проверки количества кандидатов равным 2.
Следующий тест проверяет значения каждого кандидата на выборах, гарантируя, что каждый кандидат имеет правильный идентификатор, имя и количество голосов.
Теперь давайте проверим тесты из командной строки следующим образом:
Да, они проходят! Если вы застряли, вы можете следить за мной, когда я пишу эти тесты в видео для дальнейшего объяснения.
Клиентская сторона приложения
Теперь давайте начнем создавать клиентское приложение, которое будет говорить с нашим умным контрактом. Мы сделаем это, изменив файлы HTML и Javascript, которые поставляются с ящиком Truffle Pet Shop, который мы установили в предыдущем разделе. Мы будем использовать этот существующий код для начала работы. Давайте также обратим внимание на несколько других вещей, которые появились в коробке с магазином Truffle Pet Shop, например Bootstrap framework что не даст нам писать CSS в этом туториале. Мы также получили lite-server, который будет служить нашим активам для целей развития.
Вам не обязательно быть экспертом по интерфейсу, чтобы следовать этой части урока. Я намеренно сохранил код HTML и Javascript очень просто, и мы не будем тратить много времени на это. Я хочу сосредоточиться на разработке смарт-контрактной части нашего dApp!
Вперед и замените весь контент вашего файла index.html на этот код:
Next, replace all of the content of your “app.js” file with this code:
Давайте обратим внимание на то, что делает этот код:
- Настраиваем web3: web3.js это библиотека javascript, которая позволяет нашему клиентскому приложению разговаривать с blockchain. Мы настраиваем web3 внутри функции «initWeb3».
Инициализация контрактов. Мы извлекаем развернутый экземпляр smart contract внутри этой функции и присваиваем некоторые значения, которые позволят нам взаимодействовать с ним.
Функция render: функция render предоставляет весь контент на странице с данными из смарт-контракта. Пока же мы перечисляем кандидатов, которые мы создали внутри смарт-контракта. Мы делаем это, перебирая каждого кандидата в сопоставлении и отображая его в таблицу. Мы также извлекаем текущую учетную запись, которая подключена к blockchain внутри этой функции и отображает ее на странице. - Вы можете посмотреть, как я более подробно объясню этот код в видео в 57:21.
Теперь давайте посмотрим на клиентское приложение в браузере. Во-первых, убедитесь, что вы скопировали свои контракты следующим образом:
Затем запустите сервер разработки из командной строки следующим образом:
Это должно автоматически открыть новое окно браузера с вашим клиентским приложением.
Обратите внимание, что в вашем приложении указано «Загрузка …». Это потому, что мы еще не вошли в blockchain! Чтобы подключиться к blockchain, нам нужно импортировать одну из учетных записей из Ganache в Metamask. Вы можете посмотреть, как я установил Metamask в видео в 1:09:05.
Когда вы подключитесь к Metamask, вы должны увидеть все данные контракта и учетной записи.
Голосование — Шаг 3
Сопутствующие видеоматериалы для этой части учебника начинаются в 1:13:39. Здесь вы можете загрузить код этой части туториала. Не стесняйтесь использовать их в качестве ориентира, если вы застряли!
Теперь давайте добавим возможность голосовать на выборах. Давайте определим картографирование «избирателей» на смарт-контракт, чтобы отслеживать учетные записи, которые проголосовали на выборах следующим образом:
Теперь добавим функцию «голосования»:
Основная функциональность этой функции заключается в увеличении количества голосов кандидата путем чтения структуры кандидата из «кандидатов» и увеличения «voteCount» на 1 с помощью оператора инкремента (++). Давайте посмотрим на несколько других вещей, которые он делает:
Он принимает один аргумент. Это целое число без знака с идентификатором кандидата.
Его видимость общедоступна, потому что мы хотим, чтобы внешняя учетная запись вызывала ее.
Он добавляет учетную запись, которая проголосовала за криптоизбирателей, которое мы только что создали. Это позволит нам отслеживать, что избиратель голосовал на выборах. Мы обращаемся к учетной записи, которая вызывает эту функцию с глобальной переменной msg.sender, предоставленной Solidity.
Он реализует инструкции, которые прекращают выполнение, если условия не выполняются. Сначала требуется, чтобы избиратель не голосовал раньше. Мы делаем это, читая адрес учетной записи с msg.sender из сопоставления. Если он есть, учетная запись уже проголосовала. Затем требуется, чтобы идентификатор кандидата был действительным. Идентификатор кандидата должен быть больше нуля и меньше или равен общему количеству кандидатов.
Теперь ваш полный код контракта должен выглядеть следующим образом:
Проверка функции голосования
Теперь давайте добавим тест в наш тестовый файл «election.js»:
Мы хотим проверить две вещи здесь:
Проверьте, что функция увеличивает количество голосов для кандидата.
Проверьте, что избиратель добавляется к отображению всякий раз, когда он голосует.
Затем мы можем написать несколько тестов для требований нашей функции. Давайте напишем тест, чтобы гарантировать, что наша функция голосования выдает исключение для двойного голосования:
Мы можем утверждать, что транзакция завершилась неудачно и что возвращается сообщение об ошибке. Мы можем выкопать это сообщение об ошибке, чтобы сообщение об ошибке содержало подстроку «revert». Тогда мы можем гарантировать, что состояние нашего контракта не изменится, гарантируя, что кандидаты не получили никаких голосов.
Теперь давайте напишем тест, чтобы предотвратить двойное голосование:
Сначала мы создадим тестовый сценарий со свежей учетной записью, которая еще не проголосовала. Затем мы проголосуем от их имени. Затем мы попытаемся снова проголосовать. Мы будем утверждать, что здесь произошла ошибка. Мы можем проверить сообщение об ошибке и убедиться, что ни один кандидат не получил голосов, как и предыдущий тест.
Теперь давайте проверим наши тесты:
Клиентская сторона (Сlient-Side) голосования
Давайте добавим форму, которая позволяет учетным записям под таблицей в нашем файле index.html:
Давайте рассмотрим несколько вещей об этой форме:
Мы создаем форму с помощью пустого элемента select. Мы будем заполнять выбранные варианты кандидатами, предоставленными нашим смарт-контрактом, в нашем файле «app.js».
Форма имеет обработчик onSubmit, который будет вызывать функцию castVote. Мы определим это в нашем файле «app.js».
Теперь давайте обновим наш файл app.js, чтобы обрабатывать обе эти вещи. Сначала мы перечислим всех кандидатов из смарт-контракта внутри элемента выбора формы. Затем мы скроем форму на странице после голосования. Мы обновим функцию render, чтобы выглядеть так:
Затем мы хотим написать функцию, которая вызывается всякий раз, когда отправляется форма:
Сначала мы запрашиваем для кандидатаId в форме. Когда мы вызываем функцию голосования из нашего умного контракта, мы передаем этот идентификатор, и мы предоставляем текущую учетную запись метафайлам функции. Это будет асинхронный вызов. Когда он будет завершен, мы покажем загрузчик и скройте содержимое страницы. Всякий раз, когда голосование записывается, мы сделаем обратное, показывая содержимое пользователю снова.
Теперь ваше внешнее приложение должно выглядеть так:
Идите дальше и попробуйте функцию голосования. Как только вы это сделаете, вы должны увидеть подтверждение метамаск:
Как только вы нажмете кнопку «Отправить», вы успешно произвели голосование! Вы по-прежнему увидите экран загрузки. На данный момент вам нужно будет обновить страницу, чтобы просмотреть записанные голоса. В следующем разделе мы обновим загрузчик автоматически. Если вы застряли, вы можете ссылаться на полный код на стороне клиента в этот момент в учебнике Здесь.
Просмотр событий — Шаг 4
Сопутствующие видеоматериалы для этой части учебника начинаются в 1:48:05. Здесь вы можете загрузить код этой части учебника. Не стесняйтесь использовать их в качестве ориентира, если вы застряли!
Последний шаг в этом учебнике — инициировать событие всякий раз, когда проводится голосование. Это позволит нам обновить наше клиентское приложение, когда голосование проголосовало. К счастью, это довольно легко. Начнем с объявления события в нашем контракте следующим образом:
Теперь мы можем инициировать это «проголосовавшее» событие внутри нашей функции «голосования» следующим образом:
Теперь, когда мы обновили наш контракт, мы должны запустить наши миграции:
We can also update our tests to check for this voting event like this:
Этот тест проверяет получение транзакции, возвращенную функцией «голосовать», чтобы гарантировать, что у нее есть журналы. Эти журналы содержат событие, которое было вызвано. Мы проверяем, что событие является правильным, и что он имеет правильный идентификатор кандидата.
Теперь давайте обновим клиентское приложение, чтобы прослушать голосовое событие и запустить обновление страницы в любое время, когда оно будет запущено. Мы можем сделать это с помощью функции «listenForEvents» следующим образом:
Эта функция делает несколько вещей. Во-первых, мы подписываемся на голосование, называя функцию «votedEvent». Мы передаем некоторые метаданные, которые говорят нам слушать все события на блочной цепочке. Затем мы «смотрим» это событие. Внутри мы заходим на консоль в любое время, когда запускается «votedEvent». Мы также повторно отображаем весь контент на странице. Это избавится от загрузчика после того, как будет записано голосование, и покажет обновленный подсчет голосов на столе.
Наконец, мы можем вызвать эту функцию всякий раз, когда мы инициализируем контракт:
Now, you can vote on your client-side application, and watch the votes recorded in real time! Be patient, it might take a few seconds for the event to trigger. If you don’t see an event, try restarting Chrome. There is a known issue with Metamask surrounding events. Restarting Chrome always fixes it for me.
Congratulations! You have successfully built a full stack decentralized application on the Ethereum blockchain! You can download the full source code to this tutorial here, and watch the full video here.
Be sure to subscribe to my youtube channel to see more videos about building decentralized applications on the Ethereum blockchain!
I’m also working on a premium decentralized application course that you can sign up for here.