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

Создание смарт-контрактов с помощью Java/Kotlin Contract SDK

В этом разделе описан Java/Kotlin Сontract SDK Toolkit (we-contract-sdk) – инструментарий для разработки, тестирования и развертывания Docker смарт-контрактов в публичных блокчейн сетях Waves Enterprise. Этот инструментарий позволяет быстро освоить экосистему Waves Enterprise, используя любой из языков программирования JVM, поскольку смарт-контракт разворачивается в Docker-контейнере. Вы можете создать смарт-контракт с помощью любого из JVM языков, например Java.

Контракт можно развернуть в различных средах и сетях. Например, для локальной разработки смарт-контрактов и их тестирования вы можете локально развернуть свою сеть (создать локальную среду) на основе ноды в ознакомительном режиме (Sandbox) и развернуть контракты в этой сети.

Вся обработка транзакций осуществляется с помощью методов одного класса, помеченных аннотацией @ContractHandler. Методы, реализующие логику обработки, помечены @ContractInit (для CreateContractTx) и @ContractAction (для CallContractTx).

Для развёртывания контракта необходимо выпустить транзакции 103 и 104.

Системные требования

Перед началом разработки смарт-контрактов убедитесь, что на вашей машине установлено следующее ПО:

  • Docker

  • JDK версии 8 и выше

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

  • Docker

  • JRE версии 8 и выше

Зависимости

<dependency>
  <groupId>com.wavesenterprise</groupId>
  <artifactId>we-contract-sdk-grpc</artifactId>
  <version>1.0.0</version>
</dependency>
dependencies {
     implementation("com.wavesenterprise:we-contract-sdk-grpc:1.0.0")
}

Быстрый старт

Для создания вашего нового контракта выполните следующие шаги.

Примечание

Все примеры, приведённые ниже, доступны в разделе Samples GitHub-репозитория Waves Enterprise.

1. Создайте обработчик контрактов

@ContractHandler
public class SampleContractHandler {

    private final ContractState contractState;
    private final ContractTransaction tx;

    private final Mapping<List<MySampleContractDto>> mapping;

    public SampleContractHandler(ContractState contractState, ContractTransaction tx) {
        this.contractState = contractState;
        mapping = contractState.getMapping(
          new TypeReference<List<MySampleContractDto>>() {
          }, "SOME_PREFIX");
        this.tx = tx;
    }
}

2. Добавьте методы обработки транзакций контракта @ContractInit и @ContractAction

public class SampleContractHandler {

  // ...

  @ContractInit
  public void createContract(String initialParam) {
    contractState.put("INITIAL_PARAM", initialParam);
  }

  @ContractAction
  public void doSomeAction(String dtoId) {
      contractState.put("INITIAL_PARAM", Instant.ofEpochMilli(tx.getTimestamp().getUtcTimestampMillis()));

      if (mapping.has(dtoId)) {
          throw new IllegalArgumentException("Already has " + dtoId + " on state");
      }
      mapping.put(dtoId,
              Arrays.asList(
                      new MySampleContractDto("john", 18),
                      new MySampleContractDto("harry", 54)
              ));
  }
}

3. Отправьте контракт с указанным обработчиком контракта и настройками

public class MainDispatch {
  public static void main(String[] args) {
      ContractDispatcher contractDispatcher = GrpcJacksonContractDispatcherBuilder.builder()
              .contractHandlerType(SampleContractHandler.class)
              .objectMapper(getObjectMapper())
              .build();

      contractDispatcher.dispatch();
  }

  private static ObjectMapper getObjectMapper() {
      ObjectMapper objectMapper = new ObjectMapper();
      objectMapper.registerModule(new JavaTimeModule());
      return objectMapper;
  }
}

4. Создайте Docker-образ

FROM openjdk:8-alpine
MAINTAINER Waves Enterprise <>

ENV JAVA_MEM="-Xmx256M"
ENV JAVA_OPTS=""

ADD build/libs/*-all.jar app.jar

RUN chmod +x app.jar
RUN eval $SET_ENV_CMD
CMD ["/bin/sh", "-c", "eval ${SET_ENV_CMD} ; java $JAVA_MEM $JAVA_OPTS -jar app.jar"]

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

Опубликуйте образ в репозиторий, используемый нодой блокчейн сети Waves Enterprise. Для удобства вы можете использовать bash-скрипт build_and_push_to_docker.sh, который соберёт образ вашего смарт-контракта, опубликует его в указанный реестр и выведет image и imageHash на экран.

./build_and_push_to_docker.sh my.registry.com/contracts/my-awesome-docker-contract:1.0.0

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

Для создания контракта вам понадобятся image и imageHash опубликованного контракта.

Пример CreateContractTx:

{
  "image": "my.registry.com/contracts/my-awesome-docker-contract:1.0.0",
  "fee": 0,
  "imageHash": "d17f6c1823176aa56e0e8184f9c45bc852ee9b076b06a586e40c23abde4d7dfa",
  "type": 103,
  "params": [
      {
        "type": "string",
        "value": "createContract",
        "key": "action"
      },
      {
        "type": "string",
        "value": "initialValue",
        "key": "createContract"
      }
  ],
  "version": 2,
  "sender": "3M3ybNZvLG7o7rnM4F7ViRPnDTfVggdfmRX",
  "feeAssetId": null,
  "contractName": "myAwesomeContract"
}

Для вызова контракта вам понадобится contractId = CreateContractTx.id.

Пример CallContractTx:

{
   "contractId": "7sVc6ybnqZr523xWK5Sg7xADsX597qga8iQNAS9f1D3c",
   "fee": 0,
   "type": 104,
   "params": [
     {
     "type": "string",
     "value": "doSomeAction",
     "key": "action"
     },
     {
       "type": "string",
       "value": "someValue",
       "key": "createContract"
     }
   ],
   "version": 2,
   "sender": "3M3ybNZvLG7o7rnM4F7ViRPnDTfVggdfmRX",
   "feeAssetId": null,
   "contractVersion": 1
}

Примечания по использованию

Использование с Java 11 и выше

Библиотека протестирована с Java 8, 11 и 17. При использовании с Java версии 11 и выше необходимо указать дополнительные опции Java для io.grpc, чтобы включить оптимизацию:

--add-opens java.base/jdk.internal.misc=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true

Полный пример можно найти в Dockerfile для Java 17.