Вы здесь

Создание автоматизированных смарт-контрактов, не требующих сервера

«Умные контракты» - неправильное название. Несмотря на слово «умный» (перевод с английского слова ‘smart’), смарт-контракты в сети Ethereum не являются самоисполняющимися цифровыми соглашениями. Код смарт-контракта запускается только при участии внешнего источника воздействия. Другими словами, для запуска смарт-контракта необходим внешний процесс.

Создание автоматизированных смарт-контрактов, не требующих сервера

В этой статье мы выстроим решение этой проблемы. Вы узнаете:

  • Зачем нам нужна внесетевая автоматизация смарт-контрактов;
  • Где можно применить автоматизацию смарт-контрактов;
  • Как развернуть бессерверные функции с помощью бессерверной платформы.

Наконец, мы рассмотрим «бессерверные эфиры», готовый к запуску и развертыванию полнофункциональный сервис автоматизации смарт-контрактов. Вы можете использовать этот продукт в качестве основы для создания автоматизированных смарт-контрактов, соответствующих вашим потребностям.

Бессерверные эфиры (открытый исходный код доступен на Github. Просто скопируйте и нажмите кнопку развернуть!)

Дальше вы узнаете, зачем нам нужна автоматизация и как она работает.

Проблема: смарт-контракты не являются самоисполняющимися

Давайте представим, что нам нужно исполнить смарт-контракт с функцией, которая должна автоматически выполняться каждый час.

Как это можно сделать?

Никак. Это невозможно сделать с помощью простых смарт-контрактов в Solidity. Несмотря на свое название, «умные» контракты в Ethereum не являются самоисполняющимися. Вам нужен внешний источник (человек или машина), чтобы вызвать смарт-контракт и выполнить его код.

Максимум, что может сделать контракт, - это обеспечить 1-часовой интервал между исполнениями, например:

function runMe() public {
  require(block.timestamp >= lastTriggeredAt + 1 hour);
  ...
}

Приведенный выше оператор require () гарантирует, что между исполнениями есть по крайней мере 1 час. В противном случае транзакция возвращается.

Тем не менее, кто-то все еще должен вызвать смарт-контракт в первую очередь для запуска кода.

Небольшое отступление на тему самоисполнения

Чисто технически для автоматического выполнения определенных операций можно использовать модификаторы функций. Одним из примеров этого является распределение блокчейн-компанией Compound управляющих токенов COMP среди пользователей одноименного протокола. Как только условно взятый адрес заработает 0,001 COMP, при каждой транзакции в сети Compound (будь то отправка актива или перевод токена) на его кошелек автоматически будут поступать токены COMP.

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

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

Наконец, кто-то все еще должен вызвать смарт-контракт для запуска кода.

Области, где можно применить автоматизацию смарт-контрактов

Протоколы DeFi уже в некоторой степени прибегают к внесетевой автоматизации смарт-контрактов. MakerDAO использует сторонних Киперов для мониторинга коэффициентов обеспечения долговых позиций и ликвидации любых недозагруженных позиций. Другие протоколы DeFi имеют аналогичные потребности.

Существуют два часто пересекающихся варианта использования внесетевой автоматизации смарт-контрактов:

  • Автоматические триггеры: вы хотите выполнить контракт на определенных условиях.
  • Мониторинг состояний и событий: вы хотите знать, когда контракт находится в определенном состоянии.

1. Автоматические триггеры

Рассматрим примеры, когда вам нужно исполнять контракт периодически или на определенных условиях, а именно:

  • Периодически проводить перебалансировку в пуле;
  • Закрывать раунды голосования в процессе управления или DAO;
  • Использовать оракулов для обновления данных;
  • Выплачивать пропорционально распределяемые дивиденды на инвестиционные токены.

2. Мониторинг состояний и событий

Актуально, если вы хотите знать, соблюдены ли определенные условия. Например:

  • Вы хотите знать, изменилось ли значение в смарт-контракте;
  • Вы хотите получать уведомления обо всех изменениях Контроля Доступа;
  • Вы хотите знать, когда было выпущено конкретное Событие смарт-контракта.

Решение – бессерверные функции?

Приведенные выше примеры использования хорошо подходят для бессерверной функции. Переходя на бессерверный режим, мы можем развертывать код, не подготавливая ничего заранее и не управляя ничем впоследствии. Это максимально упрощает реализацию ваших идей.

Быстрый старт: переход на бессерверную платформу с бессерверным фреймворком

Бессерверная платформа предоставляет вам все необходимое для разработки, развертывания, мониторинга и обеспечения безопасности бессерверных приложений. Мы будем использовать ее, чтобы ускорить развитие нашего проекта и уменьшить интеллектуальные затраты.

> npm install -g serverless
> serverless -v
x.x.x

Давайте быстро рассмотрим, как работает бессерверная платформа.

Вы можете пропустить этот раздел, если вам просто интересен результат. Или читайте дальше, чтобы узнать больше о бессерверной платформе.

0. serverless.yml

Все лямбда-функции и события в вашем Бессерверном сервисе можно найти в конфигурационном файле, называемом serverless.yml. В нем определены функции и события сервиса.

service: serverless-ethers
provider:
  name: aws
  runtime: nodejs12.x
  environment:
    CHAIN_ID: 3
    DEFAULT_GAS_PRICE: 60000000000
functions:
  myFunc:
    handler: functions/myFunc.handler
    events:
      - schedule: rate(2 hours)

Под свойством functions вы устанавливаете свои бессерверные функции. В приведенном выше примере:

  • У нас есть функция под названием myFunc;
  • Свойство handler указывает на файл и модуль, содержащий код, который вы хотите запустить в своей функции;
  • Свойство Events задает триггеры событий для выполнения функции.

У вас может быть несколько функций в одном сервисе.

1. Функции

Функция – это функция AWS Lambda. Это самостоятельная единица развертывания вроде микросервиса. Это просто код, развернутый в облаке, который чаще всего пишется для выполнения одной задачи.

// functions/myFunc.js
exports.handler = async function(event, context) {
  // Do anything
};

Функции - это просто обычные функции JS. Они могут принимать объект события в качестве полезной нагрузки.

2. События

События – это то, что запускает ваши функции. События принадлежат каждой функции и могут быть найдены в свойстве events в serverless.yml.

Триггер Запланированных Событий можно использовать для автоматизации периодического выполнения функций. Например, для запуска функции myFunc каждые 2 часа мы указываем:

# serverless.yml
functions:
  myFunc:
    handler: functions/myFunc.handler
    events:
      - schedule: rate(2 hours)

Вы также можете задать график с помощью выражений cron schedule:

# serverless.yml
events:
  - schedule: cron(0 12 * * ? *) # 12PM UTC

Если вы используете AWS в качестве провайдера, все события в сервисе - это все, что может вызвать функцию AWS Lambda, например:

  • Запрос конечной точки HTTP шлюза API AWS (например, для REST API);
  • Загрузка корзины AWS S3 (например, для изображения);
  • Таймер CloudWatch (например, для запуска каждые 5 минут);
  • Тема AWS SNS (например, сообщение);
  • И так далее…

Это все, что вам нужно знать на данный момент.

Чтобы узнать больше о бессерверной платформе, ознакомьтесь с этими документами.

С азами бессерверного фреймворка закончили, давайте теперь перейдем к сервису serverless-ethers.

Введение в serverless-ethers (бессерверные эфиры)

serverless-ethers - это полнофункциональный бессерверный сервис, который можно развернуть и запустить из коробки.

git clone [email protected]:yosriady/serverless-ethers.git
cd serverless-ethers
nvm use
npm install

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

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

├── contracts/
│   ├── abis/
│   ├── abis.js
│   └── addresses.js
├── functions/
│   └── exec.js
└── serverless.yml
  • contracts/ содержат ABI и адреса смарт-контрактов;
  • functions/ содержат функции JS, реализующие бизнес-логику;
  • serverless.yml описывает конфигурацию сервиса.

В качестве отступления приведу несколько примеров смарт-контрактов.

Я написал и развернул образец смарт-контракта для тестирования:

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.10;
contract DummyStorage {
    event Write(address indexed source, uint256 value);
    uint internal _currentValue;
    function get() public view returns (uint) {
        return _currentValue;
    }
    function put(uint value) public {
        emit Write(msg.sender, value);
        _currentValue = value;
    }
}

Смарт-контракт DummyStorage имеет следующие функции:

  • get – это функция только для чтения, которая возвращает текущее значение контракта.
  • put – это функция записи, которая обновляет текущее значение контракта.

Проверенный образец контракта доступен на Ropsten. Можете смело использовать его, чтобы проверить свои функции!

1. Интерфейсы ABI смарт-контракта

Каталог контрактов содержит ABI контрактов, с которыми взаимодействуют функции. В образце проекта он содержит ABI для контракта DummyStorage.

├── contracts/
│   ├── abis/
│   │     └── DummyStorage.json
│   ├── abis.js
│   └── addresses.js

ABI можно еще представить как публичную API-спецификацию смарт-контракта, что-то вроде спецификации OpenAPI. Вам нужен ABI для вызова функций контракта.

Структура контрактов / каталогов позволяет нам импортировать как ABI, так и адрес контракта следующим образом:

// functions/exec.js
const { abis, addresses } = require('../contracts');
const DummyStorageABI = abis.DummyStorage;
const DummyStorageAddress = addresses.DummyStorage;

Они нам понадобятся в нашей работе.

2. Функции

Функция exec использует эфиры для загрузки ABI контракта и вызова смарт-контракта:

// Initialize contract
const contract = new ethers.Contract(
  DummyStorageAddress,
  DummyStorageABI,
  wallet,
)
// Call smart contract function `put(uint)`
const RANDOM_INTEGER = Math.floor(Math.random() * 100); // returns a random integer from 0 to 99
const tx = await contract.put(RANDOM_INTEGER)

Загрузка ABI и адреса контракта дает нам абстракцию ethers.Contract со всеми функциями нашего смарт-контракта, включая get() и put().

На примере функции exec мы вызываем contract.put() с помощью случайного целого числа.

3. serverless.yml

Прежде чем вы сможете запустить функцию exec, вам нужно будет указать некоторые переменные среды в вашем serverless.yml:

# serverless.yml
service: serverless-ethers
provider:
  name: aws
  runtime: nodejs12.x
  region: ap-southeast-1
  timeout: 30
  environment:
    DEFAULT_GAS_PRICE: 60000000000
    MNEMONIC: ...
    SLACK_HOOK_URL: ...

serverless-ethers использует следующие переменные среды:

  • DEFAULT_GAS_PRICE: Цена газа по умолчанию используется при совершении операций записи;
  • MNEMONIC: 12-словесная мнемоника, используемая для получения адреса Ethereum. Убедитесь в наличии эфира, если собираетесь записывать данные в Ethereum!
  • SLACK_HOOK_URL: Он отправляет сообщения в Slack с помощью входящих веб-крючков. Вы можете извлечь этот URL-адрес из вашей панели мониторинга Slack. (На усмотрение)

Вы можете на ходу менять переменные среды развернутой функции с помощью консоли AWS Lambda.

Важное примечание: убедитесь, что ваши ключи хранятся не в открытом источнике. Используйте безопасное хранилище типа AWS Secrets Manager для хранения учетных данных, таких как мнемоника и ключи API. Поскольку каждый проект имеет свои собственные требования по безопасности и настройке, мы оставляем читателям право решать, как они хотят подойти к вопросу хранения чувствительной информации.

Локальный запуск

Вы можете использовать бессерверную команду CLI invoke local для локального запуска ваших функций. Она отлично подходит для тестирования!

> serverless invoke local -f exec
Starting...
Contract ABIs loaded
Ethers wallet loaded
Contract loaded
Sending transaction...
:white_check_mark: Transaction sent https://ropsten.etherscan.io/tx/0x72204f07911a319b4e5f7eb54ad15ed666cfc1403b53def40c9d60188b176383
Completed
true

Развертывание в AWS

Развертывание выполняется так же просто, как и бессерверное развертывание:

> serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service serverless-ethers.zip file to S3 (2.95 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.....................
Serverless: Stack update finished...
Service Information
service: serverless-ethers
stage: dev
region: ap-southeast-1
stack: serverless-ethers-dev
resources: 8
api keys:
  None
endpoints:
  None
functions:
  exec: serverless-ethers-dev-exec
layers:
  None

Вот и все! Теперь у вас есть бессерверная функция, которую вы можете использовать для автоматизации и мониторинга ваших смарт-контрактов. Вы можете использовать этот шаблон в качестве основы для создания своих собственных автоматизированных смарт-контрактов.

В заключение

Поздравляю! Теперь вы знаете:

  • Зачем нужна оффчейн-автоматизация смарт-контрактов;
  • Где применима автоматизация смарт-контрактов
  • Что такое бессерверная платформа;
  • Как работает приложение serverless-ethers.

Если у вас остались какие-то вопросы или есть желание поделиться своим мнением, обращайтесь! Мне было бы интересно узнать, как вы намерены использовать автоматизацию смарт-контрактов.

Пример приложения serverless-ethers с открытым исходным кодом доступен на Github. Добавляйте репозитарий в избранное, если вы нашли его полезным!

Ну и на десерт: поддержка ChatOps с помощью Slack

В комплект serverless-ethers входит функция postToSlack, которая поможет вам интегрироваться с Slack.

const successMessage = `:white_check_mark: Transaction sent https://ropsten.etherscan.io/tx/${tx.hash}`;
await postToSlack(successMessage);

Функция postToSlack позволяет использовать переменную среды SLACK_HOOK_URL, которую вы можете извлечь из консоли Slack. После настройки вы сможете оправлять уведомления в Slack о каждом успешном выполнении операции.

Это удобный и простой способ контролировать свои функции.

Дополнительно: мониторинг Событий смарт-контрактов

Пока мы успели реализовать только вариант использования «автоматического триггера». А как насчет мониторинга состояний и событий смарт-контракта?

Вы можете использовать API событий Ethers v5 для периодического мониторинга определенных событий. В своей функции вы можете сделать следующее:

// Given the following Event:
// event Transfer(bytes32 indexed node, address owner)
// Get the filter (the second null could be omitted)
const filter = contract.filters.Transfer(userAccount, null);
// Query the filter
const logs = contract.queryFilter(filter, 0, "latest"); // from block 0 to latest block
// Print out all the values:
logs.forEach((log) => {
  console.log(log.args._to, log.args._value);
});

Предполагая, что вы хотите, чтобы эта функция выполнялась периодически (например, каждые 5 минут), вам также нужно будет сохранить флаг, который отслеживает последний блок, который функция видела с момента последнего выполнения.

Мониторинг событий особенно полезен, если у вас имеется белый список для Контроля Доступа, который вам нужно отслеживать. С помощью функции мониторинга событий вы можете уведомлять канал Slack всякий раз, когда новые адреса будут заноситься в белый список для целей администрирования. Очень удобно!

Категория: 
Tutorial
1
Ваша оценка: Нет Средняя: 1 (1 оценка)
16364 / 0
Аватар пользователя Serg Demin
Публикацию добавил: Serg Demin
Дата публикации: ср, 07/29/2020 - 10:31

Что еще почитать: