Эта вторая статья уроков по написанию смарт-контрактов на Ethereum. Первую часть можно найти тут. Полный список уроков тут.
В сегодняшнем уроке мы напишем смарт-контракт визитку и познакомимся с двумя типами данных — mapping и uint:
Пусть наша визитка хранит только имя и возраст. Т.е. внутри контракта будет две переменные.
- name — имя — переменная уже знакомого нам по первому уроку типа string
- age — возраст — переменная типа uint. uint — сокращенно от unsigned int — беззнаковое целое. Целое положительное число по русски.
Также в контракте будут функции для доступа к нашим переменным. Итак, наш контракт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
pragma solidity ^0.4.18; contract BusinessCard { string name; uint age; function getName() public constant returns (string) { return name; } function setName(string newName) public { name = newName; } function getAge() public constant returns (uint) { return age; } function setAge(uint newAge) public { age = newAge; } } |
Запустите (как запускать контракт описано в первом уроке) контракт и поиграйтесь с ним. Установите и получите возраст и имя.
Теперь попробуйте самостоятельно добавить поле «год рождения». Внизу решение. Постарайтесь не подсматривать.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
pragma solidity ^0.4.18; contract BusinessCard { string name; uint age; uint year; function getName() public constant returns (string) { return name; } function setName(string newName) public { name = newName; } function getAge() public constant returns (uint) { return age; } function setAge(uint newAge) public { age = newAge; } function getYear() public constant returns (uint) { return year; } function setYear(uint newYear) public { year = newYear; } } |
На данный момент наша визитка хранит три поля — год рождения, имя и возраст. А что если нам потребуется добавить еще какую-нибудь информацию? Добавлять поля в код контракта как вы уже убедились очень просто. Но каждый раз когда мы меняем контракт его нужно заново заливать в блокчейн. И это уже будет новый контракт. Поэтому нам нужно как-то решить эту проблему.
На помощь нам придет тип данных — mapping. Записывается он так:
1 |
mapping (тип_ключей => тип_значений) имя_переменной; |
Это массив, который хранит пары (ключ => значение). Если вы не сталкивались с этим типом данных раньше, то можно его представлять себе как таблицу из двух столбцов, которую можно расширять. При этом каждый столбец имеет тип.
ключ | значение |
name | Alexander |
age | 30 |
year | 1987 |
Для нашей карточки ключи — это имена полей. Данные нашей визитной карточки разных типов. А в mapping значения иметь должны один общий тип. Проще всего все значения представить в виде строк. А выглядеть это будет так
1 |
mapping (bytes32 => string) data; |
Почему ключ типа bytes32? Дело в том что ключем не может быть строка, поэтому мы строку будем преобразовывать в тип bytes32 с помощью функции keccak256. Вдаваться в подробности пока не будем, просто примите это пока как данное.
Тогда добавление в mapping нового элемента в нашем случае будет выглядеть следующим образом:
1 |
data[keccak256("newFiled")] = "new value"; |
а получение соответственно:
1 |
string returnedValue = data[keccak256("newField")]; |
Таким образом мы можем записывать в mapping произвольное количество значений. Перепишем наш контракт-визитку:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
pragma solidity ^0.4.13; contract BusinessCard { mapping (bytes32 => string) data; function setData(string key, string value) public { data[keccak256(key)] = value; } function getData(string key) public constant returns(string) { return data[keccak256(key)]; } } |
Запишем его в блокчейн (как это делать описано в первом уроке) и попробуем записать электронную почту в нашу визитку. Обратите внимание как прописывать параметры функции при вызове, когда параметров несколько — через запятую:
Прописывает почту, нажимаем setData. А потом пробуем получить данные. Пишем что хотим получить «email» и вызываем getData.
Поиграйтесь с контрактом, попробуйте добавить другие поля, например телефон или город.
На этом второй урок заканчивается. Продолжение читать тут. Предыдущий урок тут.
Если у вас возникли вопросы то можете смело писать на электронную почту (раздел «контакты»). Также приветствуется критика.
Если статья показалась вам полезной и вы желаете отблагодарить автора, то это можно сделать отослав немного эфира на адрес 0xEA15Adb66DC92a4BbCcC8Bf32fd25E2e86a2A770.
В качестве ключа mapping допускается использовать string.
При компиляции никаких ошибок не выдает, отрабатывает без ошибок.
В спецификации к языку ключ с типом string не указан в качестве запрещенных к использованию для типа данных mapping
Да, вы правы. Допускается. Проблема будет, если модификатор доступа к мэпу будет public.
До этого урока, все получалось.
Когда прописываю справа значение в SetData «еmail», «адрес почты» то GetData его не принимает.
Присоединяюсь к вопросу.
age — возраст — переменная типа uint. uint — сокращенно от unsigned int — беззнаковое целое. Целое !положительно! число по русски.
Спасибо. Исправил.
Почему при описании добавления в mapping нового элемента используется функция sha256, а в самом коде используется sha3 ?
Опечатка. Да и сейчас используется keccak256. Старые функции теперь Deprecated. Исправил.
Я конечно не читал ещё следующие уроки, и возможно ответ на мой вопрос есть дальше. Но все же, я из опыта других языков хотел бы спросить. А не проще в качестве ключа использовать uint — где это количество пользователей, а значением была бы структура, которая уже с готовыми полями?