Как контракт может работать сам по себе в более позднее время?

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

Ответы (9)

Ленивый против нетерпеливого выполнения

Существует два основных способа разработки контракта, который будет вызываться позже: ленивая оценка или энергичная оценка .

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

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

Более сложным примером является процентный договор. Скажем, я вношу 1 ETH и каждый месяц получаю 1% годовых, начисляя сложные проценты.

Есть два способа сделать это:

  1. Ленивый способ: когда я хочу вывести свои деньги, я вызываю контракт, и он рассчитывает мой баланс на основе процентной ставки, моего последнего известного баланса и прошедшего времени.
  2. Нетерпеливый способ: я использую будильник Ethereum или какой-либо аналогичный сервис для вызова claimInterest()функции контракта, которая вычисляет проценты за этот месяц и дебетует мой баланс.

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

Нетерпеливая оценка полезна, когда переходы состояний

  1. Вычислительно дорого
    • Работа с большими наборами памяти, сортировка больших списков и т.д.
  2. Недетерминированный
    • Полагается на внешний ввод, например вызовы Oraclize.it
  3. Отсутствие стимулов
    • Сверка данных, различные неденежные контракты.
  4. Зависит от другого контракта
    • Если контракт должен принимать входные данные или отправлять транзакции в другой контракт

Планирование звонков с будильником Ethereum

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

Протокол прошел аудит и развернут в основной сети. Сейчас он полностью функционирует.

Планирование звонков может быть выполнено с помощью следующего кода:

const { EAC, Util } = require('@ethereum-alarm-clock/lib');
const moment = require('moment');

const web3 = Util.getWeb3FromProviderUrl('ws://localhost:8545');

const eac = new EAC(web3);

async function scheduleTransaction() {
    const receipt = await eac.schedule({
        toAddress: '0xe87529A6123a74320e13A6Dabf3606630683C029',
        windowStart: moment().add('1', 'day').unix() // 1 day from now
    });

    console.log(receipt);
}

scheduleTransaction();

В приведенном выше примере используется @ethereum-alarm-clock/lib . это минимальная библиотека для использования протокола Ethereum Alarm Clock.

Более подробные пояснительные инструкции можно найти здесь . Так же есть видео урок .

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

При планировании этого вызова развертывается новый контракт, который управляет всеми деталями выполнения вызова.

Исполнение

Службе Alarm требуется учетная запись Ethereum на основе закрытого ключа для выполнения вызова в указанное время. Такое поведение мотивировано значением платежа, которое связано с каждым запланированным вызовом. При возникновении целевой блокировки исполнителю звонка полностью возмещаются затраты на газ, а также выплачивается указанная сумма платежа за его услуги.

Этот процесс отслеживания предстоящих вызовов и их выполнения службой Alarm можно выполнить с помощью TimeNode . Любой может стать TimeNode, вот подробное руководство и видео о том, как им стать: How to Run a TimeNode .

Настраиваемые параметры для запланированных вызовов

  • toAddress- Адрес получателя
  • callData- Данные транзакции
  • callGas- Лимит газа для исполнения транзакций в будущем
  • callValue- Будущая стоимость транзакции в Wei
  • windowSize- Размер временного окна для выполнения, в блоках или секундах
  • windowStart- Номер блока / временная метка UNIX, когда должно открыться окно для выполнения
  • gasPrice- Будущая цена газа для исполнения
  • fee- Плата (в Wei), выплачиваемая сопровождающим Ethereum Alarm Clock за использование расписания.
  • bounty- Оплата исполнителю сделки
  • requiredDeposit- Депозит исполнителя, когда он пытается выполнить запланированную транзакцию

Расходы

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

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

Тестирование

Сервис Alarm доступен для тестирования в тестовых сетях, таких как Kovan и Ropsten. Работают TimeNodes, которые выполняют транзакции в этих сетях.

Гарантии

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

Защита

Как планировщик вызова функции вы можете рассчитывать на следующее:

  • Ваш контракт будет вызван с точными данными вызова, с которыми он был настроен.
  • Ваш контракт не будет вызываться до или после окна блоков между целевым блоком и количеством блоков после указанного льготного периода.

недоверчивость

Служба Alarm не предоставляет каких-либо специальных разрешений какой-либо стороне и имеет 100% открытый исходный код.

Документация и другие ссылки

Смотрите мой комментарий к другому ответу. Первый, кто совместит два, получает галочку!
Я добавил раздел вверху, в котором (кратко) рассматривается концепция контракта, стимулирующего определенные действия.
Это близко, но это не совсем соответствует сути ответа linagee, который заключается в том, что вы часто можете реструктурировать контракт, чтобы «реальные» балансы просто обновлялись до последних цифр при первом обращении к ним. Я также хотел бы увидеть некоторое описание того, как разработчики должны выбирать между подходом «ленивой оценки» и подходом будильника Эфириума, как я упоминал в своем комментарии.
Вы явно имеете в виду что-то конкретное. Я опубликовал ответ, который будет считаться ответом вики сообщества. Не стесняйтесь редактировать ответ, чтобы включить концепцию, о которой вы думаете.
Я добавил краткое описание ленивых вычислений и различных вариантов. Я думаю, что это нуждается в более сильных примерах, хотя.
Мы всегда можем улучшить его позже, но у вас есть основная часть того, что я искал, поэтому я пометил это как принятое.
Вы заявляете: «Ваш контракт не будет вызываться до или после окна блоков между целевым блоком и количеством блоков после указанного льготного периода». Что мешает кому-то назвать контракт в любое время?
Этот проект еще жив? Последний коммит был [6 дней назад][1], но последний релиз был [октябрь 2016 года][2]. [1]: github.com/pipermerriam/ethereum-alarm-clock/commit/… [2]: github.com/pipermerriam/ethereum-alarm-clock/releases/tag/…
С тех пор никаких новостей. К сожалению, похоже, что этот проект мертв.
Я думаю, что ваш ответ должен начинаться с упоминания о том, что нет собственного способа сделать это. Умный контакт не может вызывать себя в будущем без помощи такой службы, как ваша. Вопрос о вашем примере кода. Поскольку будущее время выполнения задается в блоках, а не в значениях времени, означает ли это, что фактическое будущее время выполнения сильно варьируется, поскольку оно зависит от конкретных времен блоков всех блоков до цели?
Проект жив и здоров. Он был интегрирован в mycrypto.com. Вы можете прочитать больше на ethereum-alarm-clock.com .

Вы можете использовать будильник Ethereum, как упоминалось ранее, но вы также можете изменить свой стиль программирования на парадигму «необходим вызов для выполнения».

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

Мой идеальный ответ объединяет эти два лучших, объясняя, когда вы должны использовать один стиль против другого. Кстати, ответ заключается в том, что вы должны использовать парадигму «обязательный вызов для выполнения» для операций, которые влияют только на состояние вашего собственного контракта, и вы должны использовать будильник Ethereum для операций, которые должны обновить какое-то состояние в другом месте в блокчейне. (состояние того, кто не будет напрямую звонить по вашему контракту).

Как уже упоминалось, вы можете использовать будильник или изменить поток вашего контракта.

Другой вариант — использовать Oraclize с пустым запросом:

/*
   Simple Alarm code.

   This contract will be called back automatically 1 day after its birth
*/

import "dev.oraclize.it/api.sol";

contract Alarm is usingOraclize {
    function Alarm() {
       oraclize_query(1*day, "URL", "");
    }

    function __callback(bytes32 myid, string result) {
        if (msg.sender != oraclize_cbAddress()) throw;
        // do something, 1 day after contract creation
    }
} 

Не существует формального способа планирования событий через сам протокол.

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

Вы не можете настроить задания cron в Ethereum. Протокол изначально не поддерживает такого рода операции.

Вы должны использовать протокол автоматизации, который работает поверх Ethereum, например, Gelato Network .

На данный момент существует несколько вариантов для этого.

Главный ответ устарел, и будильник Ethereum долгое время не работал, пока несколько недель назад, и теперь им управляет (похоже) команда Chronologic.

Я копирую ответ здесь, так как сообщество отправляет любой другой ответ о расписании на этот. Я также включаю пример кода того, как это сделать с системой AION в основной сети и Ropsten.

## Aion от ETH-Pantheon : это система, которая позволяет планировать произвольные транзакции байт-кода. Это означает, что вы можете вызывать определенную функцию в контракте с определенными данными в любое время или заблокировать в будущем.
Плюсы : простота, позволяет использовать произвольный байт-код, возвращается неиспользованный газ, низкое потребление газа, надежность, комиссия за транзакцию определена априори, работает в основной и тестовой сетях, приятное приложение, транзакции могут быть отменены без оплаты любого класса.
Минусы : централизованно.


##[Chronologic network](https://app.chronologic.network/): это, по сути, обертка будильника Эфириума (перезагрузка).
**Плюсы**: децентрализовано (поскольку использует EAC), допускает произвольный байт-код, возвращается неиспользованный газ, хорошее приложение, работающее в основной сети и тестовых сетях.
**Минусы**: высокая стоимость газа, комиссия за транзакцию не определена априори, узлы планировщика должны иметь хронологический токен, кроме оплаты исполнителю должна быть предусмотрена базовая комиссия разработчику EAC.

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


Система ##Джоулей: [mywish.io](https://contracts.mywish.io/create). Это децентрализованная система для планирования транзакций эфира.
**Плюсы**: децентрализованное приложение, работа в основной сети и тестовых сетях
. **Минусы**: ограниченный тип транзакций.

Планирование транзакций с использованием системы AION.

В случае AION (от ETH Pantheon) это пример рекуррентного планирования функции.

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

Предположим, у вас есть такой смарт-контракт:

contract mycontract{
    uint256 public result;
    function add(uint256 x, uint256 y) public {
        result = x + y;
    } 

}

и вы хотите вычислять эту сумму каждый час (для примера).

Aion позволяет планировать выполнение вашей функции рекурсивным способом. При подключении вашего контракта к AION решение будет таким:

pragma solidity ^0.4.24; 

// this is the interface with AION
contract Aion {
    uint256 public serviceFee;
    function ScheduleCall(uint256 blocknumber, address to, uint256 value, uint256 gaslimit, uint256 gasprice, bytes data, bool schedType) public payable returns (uint,address);
    
}


contract MyContract{
    uint256 public result;
    Aion aion;
    
    // This function request to schedule the transaction
    function schedule_add(uint256 x, uint y) public {
        aion = Aion(0xFcFB45679539667f7ed55FA59A15c8Cad73d9a4E);
        bytes memory data = abi.encodeWithSelector(bytes4(keccak256('add(uint256,uint256)')),x,y); 
        uint callCost = 200000*1e9 + aion.serviceFee();
        aion.ScheduleCall.value(callCost)( block.timestamp + 1 hours, address(this), 0, 200000, 1e9, data, true);
    }
    

    // this is your original function
    function add(uint x, uint y) public {
        result = x + y;
    }


    function () public payable {}
    
}

Это можно бесплатно протестировать на Ropsten. (это пример для ropsten).

Отказ от ответственности: я написал код для AION.

Надеюсь это поможет

Я использую этот код, и всякий раз, когда я пытаюсь запланировать выполнение функции на будущее с помощью schedule_add(), моя транзакция отклоняется. Я предполагаю, что это должно быть связано с перегрузкой сети и высокой платой за газ. Любая рекомендация для обеспечения моего успеха планирования?

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

Для этого вы можете использовать будильник Chainlink .

Полный пример, показывающий отложенный запуск на 5 минут, показан ниже.

pragma solidity ^0.4.24;

import "chainlink/contracts/ChainlinkClient.sol";

contract ChainlinkAlarmClock is ChainlinkClient {

  uint256 oraclePayment;

  constructor(uint256 _oraclePayment) public {
    setPublicChainlinkToken();
    oraclePayment = _oraclePayment;
  }
  function delayStart(address _oracle, bytes32 _jobId) public onlyOwner {
    Chainlink.Request memory req = buildChainlinkRequest(_jobId, this, this.fulfill.selector);
    req.addUint("until", now + 5 minutes);
    sendChainlinkRequestTo(_oracle, req, oraclePayment);
  }
  function fulfill(bytes32 _requestId) public recordChainlinkFulfillment(_requestId) {
    /* additional computation here */
    /* whatever you'd like to do with the delayed start*/
  }
  
}

Для этого существует полезный интерфейс, который позволяет легко планировать эти задания cron на основе времени без необходимости писать какой-либо код смарт-контракта под названием «Gelato Ops». Отказ от ответственности: я помог создать приложение :).

Проверьте это здесь:

https://app.gelato.network/

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

введите описание изображения здесь

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

Кажется, вы являетесь частью сети Gelato. На сайте есть правило, согласно которому, если вы используете ссылку в ответе, вы должны раскрыть свою принадлежность, иначе она будет расценена как спам и удалена. Также не копируйте и не вставляйте один и тот же ответ, он будет помечен как спам.
@Ismael добавил отказ от ответственности

Альтернативное решение, если вам не нужно быть очень точным, — это проверить незавершенные запланированные задачи в транзакциях, инициированных пользователем.

Простое решение может заключаться в том, чтобы первая транзакция в любом блоке обрабатывала любые невыполненные задачи:

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

Плюсы:

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

Минусы:

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