Эта вторая статья уроков по написанию смарт-контрактов на 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.
Поиграйтесь с контрактом, попробуйте добавить другие поля, например телефон или город.
На этом второй урок заканчивается. Продолжение читать тут. Предыдущий урок тут.
Если у вас возникли вопросы то можете смело писать на электронную почту (раздел «контакты»). Также приветствуется критика.



В качестве ключа mapping допускается использовать string.
При компиляции никаких ошибок не выдает, отрабатывает без ошибок.
В спецификации к языку ключ с типом string не указан в качестве запрещенных к использованию для типа данных mapping
Да, вы правы. Допускается. Проблема будет, если модификатор доступа к мэпу будет public.
До этого урока, все получалось.
Когда прописываю справа значение в SetData «еmail», «адрес почты» то GetData его не принимает.
Присоединяюсь к вопросу.
age — возраст — переменная типа uint. uint — сокращенно от unsigned int — беззнаковое целое. Целое !положительно! число по русски.
Спасибо. Исправил.
Почему при описании добавления в mapping нового элемента используется функция sha256, а в самом коде используется sha3 ?
Опечатка. Да и сейчас используется keccak256. Старые функции теперь Deprecated. Исправил.
Я конечно не читал ещё следующие уроки, и возможно ответ на мой вопрос есть дальше. Но все же, я из опыта других языков хотел бы спросить. А не проще в качестве ключа использовать uint — где это количество пользователей, а значением была бы структура, которая уже с готовыми полями?