Установка и использование платформы

Пример смарт-контракта с использованием gRPC

В этом разделе рассмотрен пример создания простого смарт-контракта на Python. Для обмена данными с нодой смарт-контракт применяет gRPC-интерфейс.

Перед началом работы убедитесь, что на вашей машине установлены утилиты из пакета grpcio для Python:

pip3 install grpcio

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

Описание и листинг программы

При инициализации смарт контракта при помощи транзакции 103, для него устанавливается целочисленный параметр sum со значением 0.

При вызове каждом вызове смарт-контракта при помощи транзакции 104, он возвращает инкремент параметра sum (sum + 1).

Листинг программы:

Если вы хотите, чтобы транзакции с вызовом вашего контракта могли обрабатываться одновременно, то необходимо в самом коде контракта передать параметр async-factor. Контракт передаёт значение параметра async-factor в составе gRPC-сообщения ConnectionRequest, определенном в файле contract_contract_service.proto:

message ConnectionRequest {
string connection_id = 1;
int32 async_factor = 2;
}

Подробнее о параллельном исполнении смарт-контрактов.

Авторизация смарт-контракта c gRPC

Для работы с gRPC смарт-контракту необходима авторизация. Чтобы смарт-контракт корректно работал с методами API, выполняются следующие действия:

  1. В переменных окружения смарт-контракта должны быть определены следующие параметры:

  • CONNECTION_ID – идентификатор соединения, передаваемый контрактом при соединении с нодой;

  • CONNECTION_TOKEN – токен авторизации, передаваемый контрактом при соединении с нодой;

  • NODE – ip-адрес или доменное имя ноды;

  • NODE_PORT – порт gRPC сервиса, развёрнутого на ноде.

Значения переменных NODE и NODE_PORT берутся из конфигурационного файла ноды секции docker-engine.grpc-server. Остальные переменные генерируются нодой и передаются в контейнер при создании смарт контракта.

Создание смарт-контракта

1. В директории, которая будет содержать файлы вашего смарт-контракта, создайте поддиректорию src и поместите в нее файл contract.py с кодом смарт-контракта.

2. В директории src создайте директорию protobuf и поместите в нее следующие protobuf-файлы:

  • contract_contract_service.proto

  • data_entry.proto

Эти файлы помещены в архив we-proto-x.x.x.zip, размещенном в официальном GitHub-репозитории Waves Enterprise.

3. Сгенерируйте код gRPC-методов на Python на основе файла contract_contract_service.proto:

python3 -m grpc.tools.protoc -I. --python_out=. --grpc_python_out=. contract_contract_service.proto

В результате будет создано два файла:

  • contract_contract_service_pb2.py

  • contract_contract_service_pb2_grpc.py

В файле contract_contract_service_pb2.py измените строку import data_entry_pb2 as data__entry__pb2 следующим образом:

import protobuf.data_entry_pb2 as data__entry__pb2

Таким же образом измените строку import contract_contract_service_pb2 as contract__contract__service__pb2 в файле contract_contract_service_pb2_grpc.py:

import protobuf.contract_contract_service_pb2 as contract__contract__service__pb2

Затем сгенерируйте вспомогательный файл data_entry_pb2.py на основе data_entry.proto:

python3 -m grpc.tools.protoc -I. --python_out=. data_entry.proto

Все три полученных файла должны находиться в директории protobuf вместе с исходными файлами.

4. Создайте shell-скрипт run.sh, который будет запускать код смарт-контракта в контейнере:

#!/bin/sh

eval $SET_ENV_CMD
python contract.py

Поместите файл run.sh в корневую директорию вашего смарт-контракта.

5. Создайте сценарный файл Dockerfile для сборки и управления запуском смарт-контракта. При разработке на Python основой образа вашего смарт-контракта может служить официальный образ Python python:3.8-slim-buster. Обратите внимание, что для обеспечения работы смарт-контракта в контейнере Docker должны быть установлены пакеты dnsutils и grpcio-tools.

Пример Dockerfile:

FROM python:3.8-slim-buster
RUN apt update && apt install -yq dnsutils
RUN pip3 install grpcio-tools
ADD src/contract.py /
ADD src/protobuf/common_pb2.py /protobuf/
ADD src/protobuf/contract_pb2.py /protobuf/
ADD src/protobuf/contract_pb2_grpc.py /protobuf/
ADD run.sh /
RUN chmod +x run.sh
ENTRYPOINT ["/run.sh"]

Поместите Dockerfile в корневую директорию вашего смарт-контракта.

6. Свяжитесь со службой технической поддержки Waves Enterprise для помещения вашего смарт-контракта в открытый репозиторий, если вы работаете в Waves Enterprise Mainnet.

Если вы работаете в частной сети, соберите смарт-контракт самостоятельно и разместите его в собственном репозитории.

Как работает смарт-контракт с использованием gRPC

После вызова смарт-контракт с gRPC работает следующим образом:

  1. После старта программы выполняется проверка на наличие переменных окружения.

  2. Используя значения переменных окружения NODE и NODE_PORT, контракт создает gRPC-подключение с нодой.

  3. Далее вызывается потоковый метод Connect gRPC-сервиса ContractService. Метод принимает gRPC-сообщение ConnectionRequest, в котором указывается идентификатор соединения (полученный из переменной окружения CONNECTION_ID). В метаданных метода указывается заголовок authorization со значением токена авторизации (полученного из переменной окружения CONNECTION_TOKEN).

  4. В случае успешного вызова метода возвращается gRPC-поток (stream) с объектами типа ContractTransactionResponse для исполнения. Объект ContractTransactionResponse содержит два поля:

    • transaction – транзакция создания или вызова контракта;

    • auth_token – токен авторизации, указываемый в заголовке authorization метаданных вызываемого метода gRPC сервисов.

Если transaction содержит транзакцию 103), то для контракта инициализируется начальное состояние. Если transaction содержит транзакцию вызова (тип транзакции – 104), то выполняются следующие действия:

  • с ноды запрашивается значение ключа sum (метод GetContractKey сервиса ContractService);

  • значение ключа увеличивается на единицу, т.е. sum = sum + 1);

  • новое значение ключа сохраняется на ноде (метод CommitExecutionSuccess сервиса ContractService), т.е. происходит обновление состояния контракта.