В моем блокчейн-приложении я хотел бы, чтобы событие инициировалось позже, через несколько часов или даже дней после того, как приложение в последний раз получило транзакцию от пользователя. Как я могу создать «событие», которое сработает по прошествии определенного времени?
Существует два основных способа разработки контракта, который будет вызываться позже: ленивая оценка или энергичная оценка .
Ленивая оценка означает, что состояние контракта будет обновляться только при необходимости. Это часто имеет смысл для контрактов, которые естественным образом побуждают пользователей звонить им в будущем.
Примером этого может быть контракт трастового фонда, который будет оставаться заблокированным до 18-летия. Этот человек будет мотивирован на то, чтобы осуществить рассредоточение этих средств в то время.
Более сложным примером является процентный договор. Скажем, я вношу 1 ETH и каждый месяц получаю 1% годовых, начисляя сложные проценты.
Есть два способа сделать это:
claimInterest()
функции контракта, которая вычисляет проценты за этот месяц и дебетует мой баланс.В этом случае ленивое вычисление имеет смысл, поскольку легко вычислить текущее состояние на основе прошлого состояния и прошедшего времени.
Нетерпеливая оценка полезна, когда переходы состояний
Служба будильника 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
- Будущая стоимость транзакции в WeiwindowSize
- Размер временного окна для выполнения, в блоках или секундахwindowStart
- Номер блока / временная метка UNIX, когда должно открыться окно для выполненияgasPrice
- Будущая цена газа для исполненияfee
- Плата (в Wei), выплачиваемая сопровождающим Ethereum Alarm Clock за использование расписания.bounty
- Оплата исполнителю сделкиrequiredDeposit
- Депозит исполнителя, когда он пытается выполнить запланированную транзакциюСлужба сигнализации пытается создать открытый рынок для планирования вызовов. Планировщик может указать любую сумму как для значений Bounty , так и для Fee , и те, кто выполняет вызовы, могут свободно выбирать, какие вызовы они хотят выполнять.
Во время планирования должно быть предоставлено достаточное количество эфира для оплаты как стоимости газа, так и связанных платежей и комиссий. После выполнения любой оставшийся эфир автоматически возвращается планировщику звонка.
Сервис Alarm доступен для тестирования в тестовых сетях, таких как Kovan и Ropsten. Работают TimeNodes, которые выполняют транзакции в этих сетях.
Служба аварийных сигналов представляет собой рынок для планирования вызовов и не может предоставить никаких гарантий того, что запланированный вызов будет выполнен. Для работы службы требуется, чтобы люди инициировали транзакции, выполняющие запланированные вызовы.
Как планировщик вызова функции вы можете рассчитывать на следующее:
Служба Alarm не предоставляет каких-либо специальных разрешений какой-либо стороне и имеет 100% открытый исходный код.
Вы можете использовать будильник 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 : это система, которая позволяет планировать произвольные транзакции байт-кода. Это означает, что вы можете вызывать определенную функцию в контракте с определенными данными в любое время или заблокировать в будущем.
Плюсы : простота, позволяет использовать произвольный байт-код, возвращается неиспользованный газ, низкое потребление газа, надежность, комиссия за транзакцию определена априори, работает в основной и тестовой сетях, приятное приложение, транзакции могут быть отменены без оплаты любого класса.
Минусы : централизованно.
## Oraclize : это работает, вызывая функцию обратного вызова через определенный период, выбранный пользователем, затем вы помещаете код, который хотите выполнить, внутрь этой функции.
Плюсы : простой, работающий в основной сети и тестовых сетях
Минусы : централизованный, не допускается произвольный байт-код, неиспользованный газ не возвращается, комиссия за транзакцию может быть изменена в любое время и на любое значение, что означает, что вы должны доверять Oraclize.
В случае 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.
Надеюсь это поможет
Вы можете использовать внешнюю службу для запуска транзакции в цепочке, которая запускает ваш контракт.
Для этого вы можете использовать будильник 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». Отказ от ответственности: я помог создать приложение :).
Проверьте это здесь:
Там вы можете просто ввести адрес смарт-контракта и функцию, которую хотите выполнить, а затем выбрать временной интервал, который должен определять, когда эта функция должна выполняться, например:
Однако вы также можете иметь любое другое произвольное условие, запускающее ваши смарт-контракты, а не только время.
Альтернативное решение, если вам не нужно быть очень точным, — это проверить незавершенные запланированные задачи в транзакциях, инициированных пользователем.
Простое решение может заключаться в том, чтобы первая транзакция в любом блоке обрабатывала любые невыполненные задачи:
Вы можете сделать это, сохранив состояние текущего номера блока. В начале транзакции проверьте, не соответствует ли номер текущего блока этой переменной состояния, что означает, что мы находимся в новом блоке. Обновите переменную состояния, указав текущий номер блока, а затем обработайте все невыполненные задачи. Вы можете хранить в той или иной форме список незавершенных задач вместе с их самым ранним номером блока или отметкой времени. Вы также можете проверять невыполненные задачи только каждый, например, пятый блок. Если целевой блок/время достигнут, необходимый код может быть выполнен.
Плюсы:
Минусы:
Джефф Коулман
Пайпер Мерриам
Джефф Коулман
Пайпер Мерриам
Тьяден Хесс
Джефф Коулман
авелки
Атлантида
Карма
Мэтью
Даниэль Кмак