СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ........

56
СМАРТ - КОНТРАКТЫ СЕТИ ETHERERUM

Transcript of СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ........

Page 1: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

СМАР Т -КОНТРАК ТЫ С Е ТИ E T H E R E R U M

Page 2: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ANTEATER DEV

2 018

Version 1.0

https://anteater.dev | http://smart-eth.ru

Page 3: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Посвящается всем влюбленным в небо

Page 4: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Предисловие 5 .................................................................................................

Что такое Ethereum 6 .......................................................................................

Подготовка к работе 7 .....................................................................................

Установка плагина Metamask 7 ...............................................................................

Получение Ether для Ropsten Test Network 8 .............................................................

Введение в разработку 11 ...............................................................................

Среда разработки 11 ...............................................................................................

Структура смарта-контракта 12 ..............................................................................

Типы данных 13 ......................................................................................................

Модификаторы 15 ...................................................................................................

Функции 16 ...............................................................................................................

Примеры разработки #1 18 .............................................................................

Смарт-Контракт Simple Billboard 18 ..........................................................................

Смарт-Контракт Simple Billboard 2.0 23 ....................................................................

Смарт-Контракт Simple Billboard 2.0 и web3.js 27 ....................................................

Работа с web3.js 36 ..........................................................................................

Пример разработки №2 40 .............................................................................

Разработка смарт-контракта лотереи 40 ...............................................................

Тестирование смарт-контракта 42 .........................................................................

Разработка клиентской части 44 ...........................................................................

Приложение 1 49 .............................................................................................

Приложение 2 52 .............................................................................................

Приложение 3 53 .............................................................................................

Ответы на задания 56......................................................................................

Page 5: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ПР ЕДИСЛОВИЕ Децентрализованные системы и криптовалюты вошли в нашу жизнь. Каждый слышал о них, возможно даже кто-то пробовал использовать. Данная книга поможет вам ознакомиться с возможностью одной из популярным децентрализованных систем Ethereum и поможет разобраться с разработкой смарт-контрактов для нее.

Книга идеально подходит для новичков - материал в книге больше практический.

С дополнительными примерами разработки можно ознакомиться на сайте http://smart-eth.ru.

Page 6: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ЧТО ТАКОЕ E T H E R E U M Ethereum является одной из популярных децентрализованной системой, в которой можно создавать децентрализованные приложения, который работают на базе умных контрактов (или смарт-контрактов). Вся эта система работает как одна децентрализованная виртуальная машина Ethereum Virtual Machine (EVM).

Ethereum был придуман Виталиком Бутериным, который вместе с Гэвином Вудом собрали 18 миллионов долларов на этот проект. Главная особенность Ethereum заключается в возможности использования смарт-контрактов, который выполняются на EVM. Для разработки смарт-контрактов используется язык Solidity, так как смарт-контракт подчинен логики кода, то ничто не способно нарушить условия описанные в смарт-контракте.

Внутренняя валюта сети Ethereum - это ether (эфир). Один из способов получения эфира - это майнинг. Разработчики сети Ethereum решили не ограничивать выпуск эфира. Так же эфир можно купить на всех криптовалютных биржах.

Для выполнения смарт-контрактов в EVM необходимо иметь определенное количество эфира, которое и является «топливом» для EVM. Количество эфира необходимо для выполнения смарт-контракта зависит от сложности контракта.

Page 7: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ПОДГОТОВКА К РАБОТ Е Для работы с сетью Etherum можно использовать браузер Google Chrome или Mozilla Firefox c плагином Metamask. С помощью этой связки можно работать без особых проблем как с основной сетью Ethereum, так и с тестовой Ropsten.

УС ТАНОВКА ПЛАГИНА M E TA M A S K

Для установки плагина воспользуемся браузером Mozilla Firefox. Для установки плагина Metamask для Mozilla Firefox необходимо перейти по ссылки https://addons.mozilla.org/ru/firefox/addon/ether-metamask.

Для установки необходимо нажать кнопку «Добавить в Firefox». После установки в правом верхнем углу будет доступна иконка Metamask, при первом запуске необходимо будет принять политику конфиденциальности. После этого Metamask попросить вас придумать пароль для аккаунта и так же предложить сохранить seed фразу для восстановления доступа к аккаунту - ОБЯЗАТЕЛЬНО СОХРАНЯЕМ!

Теперь у нас есть аккаунт (кошелек) от основной сети Ethereum.

Page 8: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Для обучения разработки смарт-контрактов для сети Ethereum рекомендуется использовать тестовую сеть Ropsten Test Network. При работе в данной сети не будет использоваться реальный эфир, а тестовый, который можно получить бесплатно.

ПОЛУЧЕНИЕ E T H E R ДЛЯ R O P S T E N T E S T N E T W O R K

Для получения Ether для тестовой сети необходимо переключиться к сети Ropsten Test Network и создать адрес кошелька для этой сети.

Page 9: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Переключение между сетями находиться в верхнем левом угле окна Metamask. После переключения на тестовую сеть создадим аккаунт выбрать в меню пункт Create Account.

После создания кошелька для тестовой сети можно получить для нее эфир. Для этого необходимо нажать кнопку Buy, после нажатия нужно нажать кнопка ROPSTEN TEST FAUCET, который откроет страницу, на которой можно получить тестовый Ether.

Page 10: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

После нажатия кнопки «request 1 ether from faucet» в сеть будет помещена транзакция по переводу 1 Ether для тестовой сети на ваш адрес кошелька. И после подтверждения транзакции баланс кошелька изменится и будет составлять 1 ether.

Теперь у вас есть все необходимое для разработки смарт-контрактов в сети Ethereum.

Page 11: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ВВ ЕДЕНИЕ В РАЗРАБОТКУ СР ЕДА РАЗРАБОТКИ

Среда разработки смарт-контракта для сети Ethereum - это Remix. Главным достоинством является работы в любом браузере (исключением является лишь исполнение контрактов в сети Ethereum (mainnet, ropsten), так как необходимо использовать расширение браузера Metamask.

Для запуска среды разработки необходимо в браузере в строке адреса ввести адрес https://remix.ethereum.org.

В левой части среды разработки находится перечень наших файлов в формате .sol.

В правой части среды разработки находятся закладки с различными настройками и параметрами работы среды разработки. На закладке Compile можно запустить исполнение смарт-контракта в сеть Ethereum, а также увидеть ошибки и предупреждения по коду. На закладке Run можно выполнить смарт-контракт в сети Ethereum. Причем можно выбрать окружение для его запуска - это может быть виртуальная машина JavaScript, встроенный web3 (плагин Metamask) или же можно подключиться к произвольной сети Ethereum, указав ее адрес. Дополнительно на этой

Page 12: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

закладке можно выполнить функции смарт-контракта и просматривать его глобальные переменные. На закладке Settings можно выбрать версию компилятора, цвет темы и другие параметры (например, связанные с оптимизацией). На закладке Analysis можно выбрать какие предупреждения, будет выводить компилятор - например предупреждения связанные с потенциально высокими затратами на выполнение смарт-контракта. На закладке Debugger можно выполнить отладку смарт-контракта.

Среднюю часть среды разработки занимает сам код и окно с логом исполнения смарт-контракта

С Т РУК ТУРА СМАР ТА -КОНТРАК ТА

Пример простого смарт-контракта:

Первой строкой всегда идет указание на версию компилятора Solidity:

pragma solidity ^0.4.23;

pragma solidity ^0.4.23;

contract FirstContract { // описание переменных string helloText; address owner; // описание событий event Say(string helloText); // описание модификаторов modifier onlyOwner() { require (msg.sender == owner); _; } // конструктор constructor() public { owner = msg.sender; helloText = "Hello!"; } // описание функций function changeText(string _helloText) onlyOwner public { helloText = _helloText; } function sayHello() view public { emit Say(helloText); } }

Page 13: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

А дальше структура, следующая:

1. После ключевого слова contract следует его имя - FirstContract

2. Описание глобальных переменных, который будет хранить смарт-контракт.

3. Описание событий - они начинаются с ключевого слова event.

4. Описание модификаторов - они начинаются с ключевого слова modifier.

5. Описание конструкторов смарт-контракта.

6. Описание различных функций

Все части смарт-контракта будут рассмотрены подробнее далее.

ТИПЫ ДАННЫХ

Простые типы данных

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

1. Самым простым является тип данных bool. Он хранит значения или true или false.

2. Числовые типы - они делятся на два типа - целые и беззнаковые.Целыми являются типы int8, int16 … int256 используются для хранения целого длинной 8, 16 … 256 бит. Для примера, int8 может хранить значения от -127 до 128.Беззнаковыми являются типы uint8, uint16 … uint256 используются для хранения целого числа длиной 8, 16 … 256 бит. Для примера, uint8 может хранить значения от 0 до 255

Массивы

Массивы в Solidity, как и в любом языке программирования позволяют хранить данные одного типа. Массивы можно задавать как заранее определенного размера, так и без размера. У массивов есть свойство length, которое позволяет узнать количество элементов массива. С помощью метода push() можно добавлять новые элементы в массив. Пример смарт-контракта для работы с массивами:

contract workWithArray {

Page 14: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

// инициализация массива uint[] public numbers; // вывод количества элементов в массиве function getLength() view public returns (uint) { return numbers.length; } // добавление элемента в массив function addNumber(uint _num) public { numbers.push(_num); } }

Структуры

Язык Solidity позволяет работать со структурами. Пример описания структуры:

struct Employee { string name; uint32 salary; }

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

Строки

В Solidity есть два варианта использования строк - bytes и string. Тип bytes имеет определенную размер, а тип string - не имеет длины. Одно из преимуществ тип string - этот тип хранит строку в формате UTF8. Пример инициализации переменных:

bytes16 str1; // строка с типом bytes длинной 16 string str2; // строка с типом string

Соответствия

Соответствие (mapping) является набор данных, каждому уникальному ключу соответствует какое-то значение. По своей сути соответствие является массивом, только индексом будет являться значение любого типа, а не число. Соответствие не имеет размера. Примеры работы с соответствием:

contract workWithMapping { // инициализация соответствия mapping(string => uint) public salary; // добавления данных в соответствие function setSalary(string _name, uint _salary) public {

Page 15: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

salary[_name] = _salary; } // получение значения соответствия по имени function getSalary(string _name) view public returns (uint) { return salary[_name]; } }

Адреса

Тип данных address используется для хранения адреса - смарт-контракта или кошелька. Этот тип данных имеет свойства и функции, которые позволяют работать с кошельками Ethereum.

Всегда стоит проверять при передаче как Ether, так и токенов на пустой адрес, которым является адрес 0x0000000000000000000000000000000000000000 (сокращенное значение 0х0). Это так называемый Genesis адрес сети.

На момент написания книги на данном кошельке находится свыше 700 миллионов долларов в эфире и токенах ERC20. Все эти средства были отправлены пользователями ошибочно и на вернуть их нельзя. Будьте внимательны, когда отправляете эфир или токены ERC20!

Для запроса баланса адреса нужно вызвать свойство balance.

Чтобы отправить Ether нужно воспользоваться функцией send (количество Ether указывается в wei)

address to = 0x12345678901234567890; address from = 0x11111111111111111111; if(from.balance > 100){ to.send(100); }

МОДИФИКАТОРЫ

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

Page 16: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Пример использования модификатора:

// описание модификаторов modifier onlyOwner() { require (msg.sender == owner); _; } // описание функций function changeText(string _helloText) onlyOwner public { helloText = _helloText; }

Модификатор onlyOnwer проверяет адрес отправителя и адрес владельца смарт-контракта. Если проверка будет выполнена, то компиляторе перейдет уже к функции, для которой указан модификатор.

ФУНКЦИИ

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

Пример функции, которая принимает значение, но не возвращает ничего:

function changeText(string _helloText) onlyOwner public { helloText = _helloText; }

При вызове функции changeText необходимо передать переменную c типом string, и эта переменная будет присвоена глобальной переменной helloText смарт-контракта.

Пример функции, которая принимает значение и возвращает значение:

function getSalary(string _name) view public returns (uint) { return salary[_name]; }

Ключевые слова функций в Solidity:

Page 17: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

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

2. public - означает, что данная функция будет доступна всем и любой ее может вызвать

3. private - означает, что данная функция будет доступна только из контракта, доступ к ней есть только у функций самого контракта.

4. external и internal - указание на внешние и внутренние функции. Внешние могут быть вызваны только из других контрактов, а вот внутренние только из самого контракта

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

function getCoords() view public returns (uint, uint) { uint x = 10; uint y = 45; return (x, y); }

6. payable - указывает на то, что функция может принимать ether.

Page 18: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ПРИМЕРЫ РАЗРАБОТКИ # 1 СМАР Т -КОНТРАК Т S I M P L E B I L L B O A R D

Смарт-контракт Simple Billboard будет хранить рекламное объявление, которое будет доступно для всех, а редактирование объявления сможет редактировать только владелец контракта, то есть тот, кто его выполнил в сети Ethereum.

Для смарт-контракта мы создадим две переменные:

address owner; string ads;

Переменная owner будет хранить адрес владельца смарт-контракта, а переменная ads текст рекламного объявления.

При создании смарт-контракта мы должна сразу указать нашего владельца. Это необходимо сделать в функции-конструкторе:

constructor() public { owner = msg.sender; }

В Solidity есть специальные переменные. Самая важная переменная это msg. Именно в этой переменной есть свойства, который передают при отправке сообщения в сеть Ethereum. Переменная msg содержит следующие свойства:

msg.sender - отправитель сообщения в блокчейн

msg.value - количество отправленного эфира в wei

msg.data - произвольные данные

При вызове конструктора смарт-контракта в переменную, в которой должен хранится адрес владельца, необходимо передать msg.sender.

Для просмотра рекламного сообщения в сети Ethereum будет использоваться функцию getBillboard:

function getBillboard() view public returns(string) { return ads; }

Page 19: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Для функции указано ключевое слово view (для простого чтения данных из сети Etherum), public (функция видима всем) и возврат значения returns с типом string. В теле функции одна строка кода - возврат переменной контракта ads.

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

function setBillboard(string _ads) public { require(owner == msg.sender); ads = _ads; }

Page 20: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Функция setBillboard будет принимать строковую переменную, которая будет записана в глобальную переменную смарт-контракта ads.

Первая строка функции - проверит является ли отправитель сообщения

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

Полный код нашего смарт-контракта:

pragma solidity ^0.4.23;

contract SimpleBillboard { address owner; string ads; constructor() public { owner = msg.sender; } function getBillboard() view public returns(string) { return ads; } function setBillboard(string _ads) public { require(owner == msg.sender);

Page 21: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ads = _ads; } }

Для проверки работы смарт-контракта его необходимо запустить в среде разработки Remix. Для этого нужно создать новый файл:

В окне необходимо ввести имя нового файла - пусть это будет SimpleBillboard.sol и нажимаем Ok.

В вводим код смарт-контракта в редакторе.

После ввода необходимо выполнить компиляцию контракта с помощью кнопки Start to compile (стрелка 1) и если критических ошибок нет (стрелка 2), то код введен верно и можно переходить к закладке Run и выполнить смарт-контракт в сети

Ethereum.

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

Page 22: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Enviroment нужно переключиться на значение JavaScript VM (стрелка 1) и выполнить смарт-контракт с помощью кнопки Deploy (стрелка 2)

После выполнения смарт-контракта под кнопкой Deploy появятся функции смарт-контракта.

Для выполнения функции SetBillboard необходимо указать строку с текстом рекламного объявления и нажать кнопку setBillboard. А для просмотра текста рекламного объявления, не нужно указывать никаких переменных для передачи в функции - нужно выполнить функция getBillboard, которая вернет значение из сети Ethereum.

В нижней части экрана можно увидеть транзакции и вызовы функций смарт-контракта.

Page 23: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

СМАР Т -КОНТРАК Т S I M P L E B I L L B O A R D 2 . 0

Первая версия нашего смарт-контракта Simple Billboard имела недостаток - только одно рекламного объявление могло быть создано, но у нас есть множество пользователей, который могут подать свое объявления. В текущем варианта каждый пользователь должен сам создать себе смарт-контракт аналогичный Simple Billboard. Но можно реализовать контракт, который будет хранить (и выводить) рекламные объявления разных пользователей. Для этого необходимо доработать код нашего смарт-контракта. Для этого необходимо добавить следующее:

1. Соответствие, которое будет иметь для каждого адреса свое строковое значение с объявлением.

mapping(address => string) ads;

2. Функцию getBillboard нужно доработать, что она смогла принимать переменную с типом адресом, чье объявление мы хотим посмотреть. Новая функция будет выглядеть так:

function getBillboard(address _owner) view public returns(string) { return ads[_owner]; }

3. Функция setBillboard тоже требует доработки. Теперь она будет записывать объявление не в переменную, а в соответствие по адресу.

function setBillboard(string _ads) public { ads[msg.sender] = _ads; }

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

function removeAds(address _ownerAds) public { require(owner == msg.sender); delete ads[_ownerAds]; }

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

Page 24: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

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

Итоговый код смарт-контракта Billboard 2.0:

pragma solidity ^0.4.23;

contract SimpleBillboard2 { address owner; mapping(address => string) ads; constructor() public { owner = msg.sender; } function getBillboard(address _owner) view public returns(string) { return ads[_owner]; } function setBillboard(string _ads) public { ads[msg.sender] = _ads; } function removeAds(address _ownerAds) public { require(owner == msg.sender); delete ads[_ownerAds];

Page 25: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

} }

По адресу 0x8661eb885e368c2ef6e93f1a9b5127b39244ee0e в тестовой сети Ropsten можно просмотреть этот смарт контракт (которая ссылка http://bit.ly/SimpleBB2). При переходе на ссылке вы окажитесь на сайте Etherscan - данный ресурс позволяется просматривать транзакции сети Ethereum как основной сети, так и тестовой сети Ropsten.

Сайт Etherscan позволяет прочитывать данные контракта, а так же записывать - необходимо лишь подключить плагин MetaMask. Для примера можно проверить какой текст объявления у адреса 0x479162250cCa930124D376ee2bedb141b69E72c8. Для просмотра необходимо перейти на закладку Read Contract в и поле у функции getBillboard указать адрес 0x479162250cCa930124D376ee2bedb141b69E72c8 и нажать Query.

И после выполнения запросы мы увидим, то объявление, которое оставил пользователь с адресом 0x479162250cCa930124D376ee2bedb141b69E72c8. Вы так же сможете попробовать записать свои объявления. Сайт Еtherscan добавил возможность записи - для этого есть закладка Write Contract. На ней вы найдете функцию setBillboard и поле рядом необходимо указать наше объявления и нажать кнопку Write и после подтверждения транзакции наше объявление будет записано в блокчейн

Page 26: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

навсегда, кроме тех случаем, когда мы (как владельцы смарт-контракта) можем удалить объявление.

Но данный способ не удобен для работы - необходимо иметь более удобный способ взаимодействия с данными блокчейна и самого смарт-контракта. Для этого имеется удобная библиотека на языке JavaScript - web3.js. Но для ее работы необходимо настроить работы Node.js.

Page 27: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

СМАР Т -КОНТРАК Т S I M P L E B I L L B O A R D 2 . 0 И W E B 3 . J S

Настройка node.js

Node.js - это платформа, в основе которой лежит движок V8 и позволяет выполнять роль веб-сервера. Так же эта платформа позволяет подключать дополнительные внешние библиотеки, одной из таких библиотек и является web3.js.

Скачать актуальную версию можно с официального сайта https://nodejs.org и установка не вызовет особых сложностей.

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

После установки можно выполнить команду в консоли ‘node -v’для просмотра версии установленного node.js, а так же для проверки правильности установки

Версия Node.js описанная в книге 8.11.3.

Теперь мы создадим каталог для разработки веб-интерфейса для работы со смарт-контрактом и в нем инициализировать работы node.js с библиотекой web3.js - для этого необходимо выполнить последовательно следующие команды в консоли:

mkdir simplebb cd simlpebb npm init

Page 28: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

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

MacBook-Air-Maxim:simplebb pazhukov$ npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file.

Press ^C at any time to quit. package name: (simplebb) simplebb version: (1.0.0) 1.0.0 description: GUI for Simple Billboard 2.0 entry point: (index.js) index.js test command: git repository: keywords: author: license: (ISC) About to write to /Users/pazhukov/simplebb/package.json:

{ "name": "simplebb", "version": "1.0.0", "description": "GUI for Simple Billboard 2.0", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }

Is this ok? (yes) yes

В конце нужно согласиться с веденными данными набрав в консоли yes. Все введенные данные будут записаны в файл package.json.

Теперь необходимо установить добавить в наш проект библиотеку web3.js. Это действия выполняется с помощью команды:

npm install ethereum/web3.js —save

Page 29: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Для работы нам понадобиться еще одна библиотека для Node.js - lite-server, которая будет выполнять роль веб-сервера. Установка библиотеки осуществляется с помощью команды:

npm install lite-server —save

После установки библиотеки нужно дополнить файл package.json, чтобы мы имели возможность запустить наш веб-сервер (добавленные кусок файла выделен жирным) и файл package.json будет следующим:

{ "name": "simplebb", "version": "1.0.0", "description": "GUI for Simple Billboard 2.0", "main": "index.js", "scripts": { "dev": "lite-server" }, "author": "", "license": "ISC", "dependencies": { "web3": "github:ethereum/web3.js" }, "devDependencies": { "lite-server": "^2.3.0" } }

Теперь веб-сервер и наш проект можно запустить с помощью команды в консоли:

npm run dev

Перед запуском веб-сервера необходимо добавить пустой файл index.html.

Разработка клиентской части

Клиентская часть будет представлять собой файл index.html и будет написана на языке HTML. В дополнение к библиотеке web3.js мы будем использовать так же JQuery, но это уже будет серверная часть кода.

Для реализации взаимодействия со смарт-контрактом нам необходимо следующее:

1. Поле для ввода текста объявления, которое мы хотим разместить в блокчейне

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

Page 30: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

3. Две кнопки - одна для просмотра и для публикации объявления

Текст файл index.html:

<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title>Simple Billboard</title> <script src="./node_modules/web3/dist/web3.min.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.slim.js"></script> </head> <body> <h2>Просмотр объявления</h2> Адрес: <input type="text" id="address" /> <input type="button" value="Просмотр" id="getAds"/><br> <textarea id="ads"></textarea> <hr> <h2>Подать объявление</h2> <textarea id="newAds"></textarea><br> <input type="button" value="Подать" id="setAds"/><br> <div id="info"></div>

<script> // место для кода серверной части </script> </body> </html>

Назначение:

1. Поле address - необходимо для ввода адреса, чье объявления мы хотим просмотреть

2. Кнопка getAds - будет вызывать функцию getBillboard смарт-контракта

3. Текстовая область ads - после вызова функции getBillboard в ней будет показано объявление

4. Текстовая область newAds - будет содержать текст нового объявления

5. Кнопка setAds - будет вызывать функцию setBillboard смарт-контракта

6. Поле info - будет содержать информацию о номере транзакции блокчейна, которой будут записаны новые данные в блокчейн.

Серверная часть нашего приложения для работы с блокчейном и смарт-контрактом будет располагаться так же в файле index.html и написана на языке JavaScript, для этого будет использоваться библиотеки web3.js и jquery.js.

Page 31: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Разработка серверной части

Более полное описание работы с библиотекой web3.js описано в разделе «Работа с web3.js», в данном разделе будут описан необходимый минимум для работы со смарт-контрактом.

При использовании расширения Metamask будет автоматически инициализирована переменная web3.

Для работы со смарт-контрактом нужно определить аккаунт (или адрес) в плагине Metamask и назначить его по-умолчанию:

web3.eth.defaultAccount = web3.eth.accounts[0];

Для работы со смарт-контрактом необходимо получить его ABI (Application Binary Interface) - это можно сделать в среде разработки Remix на закладке Compile по кнопке Details и кнопки копирования ABI смарт-контракта все можно сохранить в буфере обмена.

Для инициализации контракта нужно использовать функцию web3.eth.contract() - данная функция должна принимать ABI смарт-контракта:

var SimpleBBContract = web3.eth.contract([ { "constant": false, "inputs": [

Page 32: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

{ "name": "_ownerAds", "type": "address" } ], "name": "removeAds", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "name": "_owner", "type": "address" } ], "name": "getBillboard", "outputs": [ { "name": "", "type": "string" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "_ads", "type": "string" } ], "name": "setBillboard", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "payable": false, "stateMutability": "nonpayable", "type": "constructor" } ]);

Так как контракт уже находиться в блокчейне - к нему можно подключиться по адресу (0x8661eb885e368c2ef6e93f1a9b5127b39244ee0e):

var SimpleBB = SimpleBBContract.atkv(‘0x8661eb885e368c2ef6e93f1a9b5127b39244ee0e’);

Page 33: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Переменная SimpleBB будет подключена к смарт-контракту и может вызывать все доступные функции или просматривать переменные контракта.

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

$('#getAds').click(function() { // 1 var address = $('#address').val(); // 2 var data = SimpleBB.getBillboard.getData(address); // 3 var gasRequire = web3.eth.estimateGas({ to: '0x8661eb885e368c2ef6e93f1a9b5127b39244ee0e', data: data }, function(error, result){}); // 4 SimpleBB.getBillboard.call(address, { from: web3.eth.defaultAccount, gas: gasRequire}, function(error, result){ if(!error){ $("#ads").html(result); } else{ $("#info").html(error); } } ); });

При нажатии на кнопку будут выполняться 4 последовательных действия:

1. Получаем значение адреса из поля address

2. Формируем набор данных для функции getBillboard

3. Рассчитываем необходимое количество gas - но в данном случае это не имеет смысла, так как просмотр не требует затрат gas

4. Выполняем вызов функции и передаем параметр address. Если ошибок не будет, то результат запишем в поле ads, иначе в info запишем сообщение об ошибке.

Page 34: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

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

$('#setAds').click(function() { // 1 var newAds = $('#newAds').val(); // 2 var data = SimpleBB.setBillboard.getData(newAds); // 3 var gasRequire = web3.eth.estimateGas({ to: '0x8661eb885e368c2ef6e93f1a9b5127b39244ee0e', data: data }, function(error, result){}); // 4 SimpleBB.setBillboard.sendTransaction(newAds, { from: web3.eth.defaultAccount, gas: gasRequire}, function(error, result){ if(!error){ $("#info").html(result); } else{ $("#info").html(error); } } ); });

При нажатии кнопки Подать (с id=setAds) будет происходить следующее:

1. Получаем текст нового объявления из newAds

2. Формируем набор данных

3. Рассчитываем количество необходимого gas - теперь мы отравим сообщение в блокчейн и этот параметр необходим

4. Отправка сообщения в блокчейн - в случае успеха в поле info будет показана транзакция, которой будет внесено изменения в объявление. Поэтому после нажатия Metamask предложил подтвердить транзакцию.

Page 35: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Полный текст файла index.html для примера разработки интерфейса для работы со смарт-контрактом Simple Billboard 2.0 описан в приложение 1.

Page 36: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

РАБОТА С W E B 3 . J S Библиотека web3.js позволяется взаимодействовать с блокчейном Ethereum для создания клиентских приложений. На момент написания книги существует различное множество проектов, который взаимодействуют с Ethereum. Одним из популярных проектов на блокчейне Ethereum - CryptoKitties. CryptoKitties - это одна из первых игры на блокчейне Ethereum, в которой можно покупать и продавать котиков, а так же создавать новых.

Скачать библиотеку можно по адресу https://github.com/ethereum/web3.js/, а документация по работе с web.3js расположена по адресу https://github.com/ethereum/web3.js/.

Инициализация web3.js

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

if (typeof web3 !== 'undefined') { web3 = new Web3(web3.currentProvider); } else { web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); }

>>>Про запуск тестовой ноды

После этого мы можем использовать объект web3 и все его функции.

Методы web3.eth

Объект web3.eth содержит функции и переменные для работы с блокчейном. Один из часто используемых переменных это web3.eth.defaultAccount - содержит адрес, который будет использоваться для методов sendTransaction() и call(). Присваивается адрес простым присвоением строки с адресом:

web3.eth.defaultAccount = ‘0x479162250cca930124d376ee2bedb141b69e72c8';

Для получения текущей цены gas можно воспользоваться переменной web3.eth.gasPrice - данная переменная используется только для чтения.

Page 37: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Для просмотра баланса ether можно воспользоваться функцией getBalance:

var balance = web3.eth.getBalance("0x407d73d8a49eeb85d32cf465507dd71d507100c1"); console.log(balance.toNumber()); // 3000000000000

Для отправки ether между адресами используется функция sendTransaction. Для этого необходимо выполнить следующий код:

web3.eth.sendTransaction()

В качестве параметров функция принимает объект со следующими параметрами:

• from: (тип параметра String) - адрес отправителя, по-умолчанию используется web3.eth.defaultAccount, если не задано другое значение.

• to: (тип параметра String) - опциональный параметр, указывается адрес получателя.

• value: (тип параметра Number, String или BigNumber) - опциональный параметр, указывается количество передаваемог ether в wei.

• gas: (тип параметры Number, String или BigNumber) - опциональный параметры, указывается необходимо количество gas для выполнения параметры

• gasPrice: (тип параметры Number, String или BigNumber) - опциональный параметры, указывается цена gas в wei.

• data: (тип параметра String) - опциональный параметры, указывается любая произвольная информация или же код контракта в случае выполнения транзакции по созданию контракта.

• nonce: (тип параметра Number) - опциональный параметры, показывает счетчик транзакций, который отправил отправитель.

При выполнении функции будет возвращен хеш транзакции. Пример транзакции:

var tx = web3.eth.sendTransaction({ from: "0x479162250cca930124d376ee2bedb141b69e72c8", to: "0xfdad952495b70b67f8cef797a4bd80e1c3aefaa2", value: 1000000000000000000, data: "Happy Birthday" });

Работа с контрактами

Page 38: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Для работы с контрактами необходимо обязательно выполнить две команды - описать ABI контракта и подключить к нему по его адресу:

var LotteryContract = web3.eth.contract([{"constant":false,"inputs":[],"name":"startLottery","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"tickets","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ticketCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"buyTicket","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"winner","type":"address"},{"indexed":false,"name":"ticketId","type":"uint256"},{"indexed":false,"name":"prise","type":"uint256"}],"name":"LotteryResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"ticketId","type":"uint256"}],"name":"NewTicket","type":"event"}]);

var Lottery = LotteryContract.at('0xe04a13683c034c0c60b848c8d6f64ce462c72734');

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

Для чтения данных из контракта необходимо воспользоваться функцией call. К примеру, в смарт-контракте есть функция, который возвращает значение из массива с определенным id:

function getData(uint _dataId) public view returns (uint32){ return (datas[_dataId];); }

Для получения данных необходимо использовать следующий код на JavaScript:

var result = Contract.getData.call(id, { from: web3.eth.defaultAccount, value: 0, gas: 2000000}, function(err, result){ if(!err){ // если нет ошибки } else { // если ошибка } } );

Так как функция getData имеет ключевое слово view, то при вызове кода затрат на выполнение не будет и код просто прочитает значение из блокечейна.

Page 39: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Если необходимо передать данные в блокчейн, необходимо воспользоваться функцией sendTransaction. Если у нас есть функция смарт-контракта, которая выполняется какие-то действия с данными в блокчейне:

function actionWithData() public onlyOwner {

// действия с данными в блокчейне }

Тогда, необходимо выполнить следующий код на JavaScript:

Contract.actionWithData.sendTransaction( { to: contract_addr, from: web3.eth.defaultAccount, gas: 20000000}, function(error, result){ if(!error){ // если нет ошибки } else{ // если ошибка } } );

И самое важное в работе со смарт-контрактами - это работы событиями. Пример работы с событиями описан в разделе Пример разработки №2.

Page 40: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ПРИМЕР РАЗРАБОТКИ №2 РАЗРАБОТКА СМАР Т -КОНТРАК ТА ЛОТ Е Р ЕИ

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

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

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

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

2. Цена билета для участия в лотереи - та цена в ether, которую должен заплатить участник и перевести на адрес смарт-контракта

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

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

address owner; uint ticketPrice = 0.0001 ether; mapping(uint => address) public tickets; uint public ticketCount;

Для того, чтобы оповестить «внешний мир» о том, что был куплен билет или был объявлен победитель нужно описать два события:

event LotteryResult(address winner, uint ticketId, uint prise); event NewTicket(uint ticketId);

Событие LotteryResult оповестит о том, кто выиграл (адрес кошелька и номер билета) и какую сумму. Событие NewTicket оповестит о номере билета, который был приобретен.

Page 41: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Так как мы будет использовать владельца контракта опишем присвоение владельца и модификатор для использования его в функции для запуска розыгрыша.

constructor() public { owner = msg.sender; } modifier onlyOwner() { require(msg.sender == owner); _; }

Для функционирования смарт-контракта в него нужно добавить всего две функции:

1. Покупка билета - это будет функция с модификатором payable, так как мы будет получать средства. В теле функции мы выполним проверку, что мы получили ту необходимую нам сумму за билет. Если проверка будет пройдена, мы добавим в наше сопоставления для номера билеты адрес покупателя и кандидата на победу.

function buyTicket() public payable { require(msg.value == ticketPrice); tickets[ticketCount] = msg.sender; emit NewTicket(ticketCount); ticketCount = ticketCount + 1; }

2. Запуск розыгрыша - эту функция сможет вызвать только владелец контракта (поэтому у нее будет модификатор onlyOwner). Первое, что будет проверять функция - это количество билетов и их будет минимум 5, иначе выигрыш будет слишком мал (не стоит переживать, себе мы тоже оставим немного за организацию).

function startLottery() public onlyOwner { require(ticketCount >= 5); uint random = uint(sha3(block.timestamp)) % (ticketCount - 1); address winner = tickets[random]; uint prize = (ticketCount * 0.0001 ether) * 80 / 100; winner.transfer(prise); emit LotteryResult(winner, random, prize); for(uint i=0; i<=ticketCount-1; i++) { delete tickets[i]; } ticketCount = 0; }

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

Page 42: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

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

Полный текст смарт-контракта вы найдете в Приложение 2.

Т Е С ТИРОВАНИЕ СМАР Т -КОНТРАК ТА

Для тестирования работы смарт-контракта воспользуемся возможностями редактором Remix. На закладке Run выберем Enviroment - JavaScript VM. Для работы с этим окружением у нас будет доступно 5 адресов с балансом 100 ether на каждом.

Первый адрес будет владельцем контракта, он и все остальные 4 будут покупателями билетов на лотерею. С помощью кнопки Deploy выполним контракт. Теперь нам будут доступны 4 объекта - buyTicket (для покупки билета), startLottery (запуск розыгрыша), ticketCount (счетчик купленных билетов) и tickets (список купленных билетов и их покупателей).

Page 43: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Для покупки билета необходимо в поле Value указать 0.0001 ether и нажать кнопку buyTicket.

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

Page 44: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

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

В событии LotteryResult сообщает, что победил адрес с купленным билетом номер 3 - 0x583031D1113aD414F02576BD6afaBfb302140225 и победитель получает сумму в размере 400000000000000 wei.

Задание №1 - Победитель получается 80% средств в розыгрыше, остальные 20% остается на самом смарт-контракте. Для перевода средств необходим описать функцию для перевода средств со смарт-контракта на адрес владельца.

РАЗРАБОТКА КЛИЕН ТСКОЙ ЧАС ТИ

Cмарт-контракта имеет адрес 0xe04a13683c034c0c60b848c8d6f64ce462c72734 в тестовой сети Ropsten.

Для страницы с возможностью покупки билетов необходимо три объекта:

1. Кнопка - при нажатии будет создана транзакция для покупки и отправлена в блокчейн

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

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

Page 45: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Для реализации в коде страницы html необходимо указать следующее:

<input type="button" value="Купить билет" id="buyTicket"/><br> <div id="info"></div> <div id="tx"></div>

В части страницы html предусмотренной для ввода кода на языке JavaScript необходимо указать ABI смарт-контракта и подключиться к нему по адресу из тестовой сети Ropsten.

var LotteryContract = web3.eth.contract([{"constant":false,"inputs":[],"name":"startLottery","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"tickets","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ticketCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"buyTicket","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"winner","type":"address"},{"indexed":false,"name":"ticketId","type":"uint256"},{"indexed":false,"name":"prise","type":"uint256"}],"name":"LotteryResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"ticketId","type":"uint256"}],"name":"NewTicket","type":"event"}]);

var Lottery = LotteryContract.at('0xe04a13683c034c0c60b848c8d6f64ce462c72734');

Код, который будет выполняться при нажатии кнопки будет содержать, определение данных (1), который будут переданы с транзакцией, количество gas необходимого для выполнения функции (2) по покупке билета и сам запуск транзакции в блокчейн (3). При определение переменной gasRequire будет передано цена билета (0.0001 ether = 100000000000000 wei) в параметре value. Такое же значение нужно передать для транзакции.

В случае успешного выполнения транзакции в поле tx будет отображен хэш транзакции.

Код, который будет выполнен при нажатии кнопки buyTicket:

$('#buyTicket').click(function() { // 1 var data = Lottery.buyTicket.getData(); // 2 var gasRequire = web3.eth.estimateGas({ to: '0xe04a13683c034c0c60b848c8d6f64ce462c72734', value: 100000000000000, data: data }, function(error, result){}); // 3

Page 46: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Lottery.buyTicket.sendTransaction( { to: '0xe04a13683c034c0c60b848c8d6f64ce462c72734', from: web3.eth.defaultAccount, gasPrice: 10000000000, value: 100000000000000, gas: gasRequire}, function(error, result){ if(!error){ $('#tx').html(result); } else{ $('#tx').html(error); } } ); });

Для описания работы с событиями переменной необходимо, какое именно событие смарт-контракта необходимо использовать:

var buyTicketEvent = Lottery.NewTicket();

Теперь переменная buyTicketEvent может отслеживать оповещение о событии NewTicket:

buyTicketEvent.watch(function(error, result) {

if(!error) { ticketId = result.args.ticketId.valueOf(); $('#info').html("Ваш билет № " + ticketId); } else { $('#info').html(error); }

});

В коде смарт-контракта для события NewTicket был определен один параметр события и это номер билета - ticketId. Для доступа к параметрам события нужно обратиться следующим образом: result.args.ticketId.

Page 47: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

Полный код страницы для покупки билеты представлен в Приложение 3.

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

Для отображения информация о результате будет использоваться следующий код HTML:

<input type="button" value="Розыгрыш" id="runLottery"/><br> <div id="info"></div> <div id="tx"></div>

При нажатии на кнопку с идентификатором runLottery должна быть запущена функция смарт-контракта startLottery:

$('#runLottery').click(function() { // 1 var data = Lottery.startLottery.getData(); // 2 var gasRequire = web3.eth.estimateGas({ to: '0xe04a13683c034c0c60b848c8d6f64ce462c72734', data: data }, function(error, result){}); // 3 Lottery.startLottery.sendTransaction( { to: '0xe04a13683c034c0c60b848c8d6f64ce462c72734', from: web3.eth.defaultAccount, gas: gasRequire}, function(error, result){ if(!error){ $('#tx').html(result); } else{ $('#tx').html(error); } } ); });

Так как функция смарт-контракта вызывает событие LotteryResult, его необходимо запустить для отслеживания:

var lotteryEvent = Lottery.LotteryResult();

lotteryEvent.watch(function(error, result) {

if(!error) { winner = result.args.winner.valueOf(); ticketId = result.args.ticketId.valueOf(); prise = result.args.prise.valueOf();

Page 48: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ethPrise = web3.fromWei(prise, 'ether'); $('#info').html("Выиграл билет № " + ticketId + ". Победитель "

+ winner + ", выигрыш " + ethPrise + " Ether"); } else { $('#info').html(error); }

});

После того, как победитель будет объявлен на странице будет выведен адрес победителя и сумма, которую он выиграл.

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

Таблица деноминации ether

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

Единица Значение в Wei

wei 1 Wei

Kwei 1,000 Wei

Mwei 1,000,000 Wei

Gwei 1,000,000,000 Wei

microether 1,000,000,000,000 Wei

milliether 1,000,000,000,000,000 Wei

ether 1,000,000,000,000,000,000 Wei

Page 49: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ПРИЛОЖЕНИЕ 1 Текст файл index.html:

<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title>Simple Billboard</title> <script src="./node_modules/web3/dist/web3.min.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.slim.js"></script> </head> <body> <h2>Просмотр объявления</h2> Адрес: <input type="text" id="address" /> <input type="button" value="Просмотр" id="getAds"/><br> <textarea id="ads"></textarea> <hr> <h2>Подать объявление</h2> <textarea id="newAds"></textarea><br> <input type="button" value="Подать" id="setAds"/><br> <div id="info"></div>

<script> // место для кода серверной части web3.eth.defaultAccount = web3.eth.accounts[0];

var SimpleBBContract = web3.eth.contract([ { "constant": false, "inputs": [ { "name": "_ownerAds", "type": "address" } ], "name": "removeAds", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "name": "_owner", "type": "address" } ], "name": "getBillboard", "outputs": [ { "name": "", "type": "string" } ], "payable": false, "stateMutability": "view",

Page 50: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

"type": "function" }, { "constant": false, "inputs": [ { "name": "_ads", "type": "string" } ], "name": "setBillboard", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "payable": false, "stateMutability": "nonpayable", "type": "constructor" }]);

var SimpleBB = SimpleBBContract.at('0x8661eb885e368c2ef6e93f1a9b5127b39244ee0e');

$('#getAds').click(function() { // 1 var address = $('#address').val(); // 2 var data = SimpleBB.getBillboard.getData(address); // 3 var gasRequire = web3.eth.estimateGas({ to: '0x8661eb885e368c2ef6e93f1a9b5127b39244ee0e', data: data }, function(error, result){}); // 4 SimpleBB.getBillboard.call(address, { from: web3.eth.defaultAccount, gas: gasRequire}, function(error, result){ if(!error){ $("#ads").html(result); } else{ $("#info").html(error); } } ); });

$('#setAds').click(function() { // 1 var newAds = $('#newAds').val(); // 2 var data = SimpleBB.setBillboard.getData(newAds); // 3 var gasRequire = web3.eth.estimateGas({ to: '0x8661eb885e368c2ef6e93f1a9b5127b39244ee0e', data: data }, function(error, result){}); // 4 SimpleBB.setBillboard.sendTransaction(newAds, {

Page 51: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

from: web3.eth.defaultAccount, gas: gasRequire}, function(error, result){ if(!error){ $("#info").html(result); } else{ $("#info").html(error); } } ); });

</script> </body> </html>

Page 52: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ПРИЛОЖЕНИЕ 2 Текст смарт-контракта лотереи BlockchainLottery:

pragma solidity ^0.4.23;

contract BlockchainLottery { address owner; uint ticketPrice = 0.0001 ether; mapping(uint => address) public tickets; uint public ticketCount; event LotteryResult(address winner, uint ticketId, uint prise); event NewTicket(uint ticketId); constructor() public { owner = msg.sender; } modifier onlyOwner() { require(msg.sender == owner); _; } function buyTicket() public payable { require(msg.value == ticketPrice); tickets[ticketCount] = msg.sender; emit NewTicket(ticketCount); ticketCount = ticketCount + 1; } function startLottery() public onlyOwner { require(ticketCount >= 5); uint random = uint(sha3(block.timestamp)) % (ticketCount - 1); address winner = tickets[random]; uint prize = (ticketCount * 0.0001 ether) * 80 / 100; winner.transfer(prise); emit LotteryResult(winner, random, prize); for(uint i=0; i<=ticketCount-1; i++) { delete tickets[i]; } ticketCount = 0; } }

Page 53: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ПРИЛОЖЕНИЕ 3 Код страницы bc_lottery.html:

<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title>BlockChain Lottery</title> <script src="./node_modules/web3/dist/web3.min.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.slim.js"></script> </head> <body> <input type="button" value="Купить билет" id="buyTicket"/><br> <div id="info"></div> <div id="tx"></div>

<script> // место для кода серверной части web3.eth.defaultAccount = web3.eth.accounts[0];

var LotteryContract = web3.eth.contract([{"constant":false,"inputs":[],"name":"startLottery","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"tickets","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ticketCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"buyTicket","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"winner","type":"address"},{"indexed":false,"name":"ticketId","type":"uint256"},{"indexed":false,"name":"prise","type":"uint256"}],"name":"LotteryResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"ticketId","type":"uint256"}],"name":"NewTicket","type":"event"}]);

var Lottery = LotteryContract.at('0xe04a13683c034c0c60b848c8d6f64ce462c72734');

$('#buyTicket').click(function() { // 1 var data = Lottery.buyTicket.getData(); // 2 var gasRequire = web3.eth.estimateGas({ to: '0xe04a13683c034c0c60b848c8d6f64ce462c72734', value: 100000000000000, data: data }, function(error, result){}); // 3 Lottery.buyTicket.sendTransaction( { to: '0xe04a13683c034c0c60b848c8d6f64ce462c72734', from: web3.eth.defaultAccount, gasPrice: 10000000000, value: 100000000000000, gas: gasRequire}, function(error, result){ if(!error){ $('#tx').html(result);

Page 54: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

} else{ $('#tx').html(error); } } ); });

var buyTicketEvent = Lottery.NewTicket();

buyTicketEvent.watch(function(error, result) {

if(!error) { ticketId = result.args.ticketId.valueOf(); $('#info').html("Ваш билет № " + ticketId); } else { $('#info').html(error); }

});

</script> </body> </html>

Код страницы bc_lottery_admin.html:

<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title>BlockChain Lottery</title> <script src="./node_modules/web3/dist/web3.min.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.slim.js"></script> </head> <body> <input type="button" value="Розыгрыш" id="runLottery"/><br> <div id="info"></div> <div id="tx"></div>

<script> // место для кода серверной части web3.eth.defaultAccount = web3.eth.accounts[0];

var LotteryContract = web3.eth.contract([{"constant":false,"inputs":[],"name":"startLottery","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"tickets","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ticketCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"buyTicket","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"winner","type":"address"},{"indexed":false,"name":"ticketId","type":"uint256"},{"indexed":false,"name":"prise","type":"uint256"}],"name":"LotteryResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"ticketId","type":"uint256"}],"name":"NewTicket","type":"event"}]);

Page 55: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

var Lottery = LotteryContract.at('0xe04a13683c034c0c60b848c8d6f64ce462c72734');

$('#runLottery').click(function() { // 1 var data = Lottery.startLottery.getData(); // 2 var gasRequire = web3.eth.estimateGas({ to: '0xe04a13683c034c0c60b848c8d6f64ce462c72734', data: data }, function(error, result){}); // 3 Lottery.startLottery.sendTransaction( { to: '0xe04a13683c034c0c60b848c8d6f64ce462c72734', from: web3.eth.defaultAccount, gas: gasRequire}, function(error, result){ if(!error){ $('#tx').html(result); } else{ $('#tx').html(error); } } ); });

var lotteryEvent = Lottery.LotteryResult();

lotteryEvent.watch(function(error, result) {

if(!error) { winner = result.args.winner.valueOf(); ticketId = result.args.ticketId.valueOf(); prise = result.args.prise.valueOf(); ethPrise = web3.fromWei(prise, 'ether'); $('#info').html("Выиграл билет № " + ticketId + ". Победитель "

+ winner + ", выигрыш " + ethPrise + " Ether"); } else { $('#info').html(error); }

});

</script> </body> </html>

Page 56: СМАРТ КОНТРАКТЫ СЕТИ ETHERERUM · Что такое Ethereum 6 ..... Подготовка к работе 7 ... Смарт-контракт Simple Billboard будет

ОТВ Е ТЫ НА ЗАДАНИЯ Задание №1

function withDraw() public onlyOwner { uint amount = getBalance(); owner.transfer(amount); } function getBalance() public view returns (uint){ return address(this).balance; }