Курс разработчика EOS. Часть 6. Пишем смарт-контракт. Визитка

avatar igorart 12 months ago

Назад Содержание Вперед

В прошлой статье мы написали наш  смарт-контракт "Hello word"  и разобрались с таблицами и со структурой мультииндекс. Мы уже обладаем некоторыми необходимыми нам знаниями. В этой статье мы создадим смарт-контракт - "Визитку". 

Но перед перед тем, как мы к этому приступим, нам предстоит выполнить несколько шагов.

Шаг 1 - Запускаем ноды

Если ноды в отдельном терминале до этого не были запущены, то открываем терминал и вводим команду

nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin --contracts-console

если вдруг возникнет ошибка то вводим

nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin --plugin eosio::producer_plugin --plugin eosio::http_plugin --delete-all-blocks

затем снова запускаем команду

nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin --contracts-console

Шаг 2 - Создаем кошелек

В новом терминале (старый не закрываем) создаем кошелек с именем BusinessCard

cleos wallet create -n BusinessCard

Сохраняем ключ от кошелька

Создаем две пары ключей для ActiveKey и OwnerKey. Два раза вводим команду в консоль

cleos create key

и сохраняем private и public ключи.

Импортируем два private ключа в наш кошелек. Также нам требуется импортировать 3-ий ключ - private ключ провайдера, который находится в файле config.ini. По умолчанию он стандартный

5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

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

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

cleos wallet unlock -n BusinessCard

далее

cleos wallet import значение_private_Activekey -n BusinessCard
cleos wallet import значение_private_Ownerkey -n BusinessCard
cleos wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 -n BusinessCard

Шаг 3 - Создаем аккаунт

Давайте создадим аккаунт и назовем его, к примеру buscardacc

cleos create account eosio buscardacc значение_public_Activekey значение_public_Ownerkey

Шаг 4 - Создание визитки

переходим в директорию contracts

cd ~/eos/build/contracts

создаем папку с названием нашего проекта BusinessCard

mkdir BusinessCard

в ней создаем два файла BusinessCard.hpp и BusinessCard.сpp

В BusinessCard.hpp добавьте следующий код

 
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
#include <string>

В BusinessCard.сpp

  
#include "BusinessCard.hpp"

namespace BusinessCard {

	using namespace eosio;

	using std::string;

	class Users : public contract {

		using contract::contract;

	public:

		Users(account_name self) :contract(self) {}

		//@abi action

		void add(account_name account, string& username) {

			/**

			* We require that only the owner of an account can use this action

			* or somebody with the account authorization

			*/

			require_auth(account);

			/**

			* We access the "user" table as creating an object of type "userIndex"

			* As parameters we pass code & scope - _self from the parent contract

			*/

			userIndex users(_self, _self);

			/**

			* We must verify that the account doesn't exist yet

			* If the account is not found the iterator variable should be users.end()

			*/

			auto iterator = users.find(account);

			eosio_assert(iterator == users.end(), "Address for account already exists");

			/**

			* We add the new user in the table

			* The first argument is the payer of the storage which will store the data

			*/

			users.emplace(account, [&](auto& user) {

				user.account_name = account;

				user.username = username;

				user.age = 30;

				user.address = "Minsk";

			});

		}

	private:

		///@abi table user i64

		struct user {

			uint64_t account_name;

			string username;

			uint64_t age;

			string address;

			uint64_t primary_key() const { return account_name; }

			EOSLIB_SERIALIZE(user, (account_name)(username)(age)(address))

		};

		typedef multi_index<N(user), user> userIndex;

	};

	EOSIO_ABI(Users, (add))

}

Содержимое файла BusinessCard.hpp не отличается от hello.hpp и такое же как было в  предыдущей статье.

Тут мы просто подключаем хэдер файлы.

Рассмотрим более подробно файл BusinessCard.cpp. Хорошей практикой является создавать в контракте пространство имён. Мы оборачиваем все в namespace BusinessCard {}. Далее мы создаем класс Users, который наследуется от контракта contract -  class Users : public contract {}. Аналогично с конструктором. В контракте у нас всего лишь одно действие action add - void add(account_name account, string& username) {}. В него, в качестве входных данных мы передаем название нашего аккаунта - account и имя - username.  Рассмотрим данный кусок кода:

  
		struct user {

			uint64_t account_name;

			string username;

			uint64_t age;

			string address;

			uint64_t primary_key() const { return account_name; }

			EOSLIB_SERIALIZE(user, (account_name)(username)(age)(address))

		};

		typedef multi_index<N(user), user> userIndex;

Мы объявили структуру user. Со следующими полями: имя аккаунта - account_name, имя пользователя - username, возраст - age, адрес - address. Для объявление полей мы использовали только два типа данных строковый - string и целочисленный uint64_t.  account_name - является нашим первичным ключом. Ведь мы хотим, чтобы один аккаунт соответствовал одному пользователю. Первичный ключ обязательно должен быть типа uint64_t и должен быть уникальным. Им у нас является поле account_name. Тут у нас также как и в предыдущей статье  присутствует обязательная функция primary_key(), возвращающая первичный ключ типа uint64_t . В коде мы объявили шаблонный объект userIndex. Для объявления мы использовали ключевое слово typedef.

typedef multi_index<N(user), user> userIndex;
EOSLIB_SERIALIZE(user, (account_name)(username)(age)(address))

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

Строка  require_auth(account); необходима, чтобы только владелец учетной записи(аккаунта) мог использовать нашу функцию - добавлять пользователя. Тут мы также делаем проверку на существование аккаунта


auto iterator = users.find(account);
eosio_assert(iterator == users.end(), "Address for account already exists");

Если аккаунт не существует, то как и в предыдущей статье добавляем данные при помощи функции emplace. 

 
			users.emplace(account, [&](auto& user) {

				user.account_name = account;

				user.username = username;

				user.age = 30;

				user.address = "Minsk";

			});

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

Деплой смарт-контракта

Прежде всего нам необходимо сгенерировать два файла .wast и .abi

введем две следующие команды

eosiocpp -o BusinessCard.wast BusinessCard.cpp
eosiocpp -g BusinessCard.abi BusinessCard.cpp

в директории BusinessCard появятся дополнительный файлы 

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

cleos set contract buscardacc BusinessCard BusinessCard.wast BusinessCard.abi

Тестируем наш контракт

Давайте добавим данные для нашего пользователя

cleos push action buscardacc add '["buscardacc","Igor Artemenko"]' -p buscardacc@active

Данные успешно добавились.

Резюме

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

Назад Содержание Вперед