Что происходит, когда вы ставите рекурсивный вызов расписания с помощью планировщика будильника Ethereum?

Моя цель — запланировать звонок один раз в день.

[В] Можно ли использовать рекурсивную функцию для планирования звонка один раз в день с помощью планировщика Ethereum Alarm Clock?

Пример из следующего ответа https://ethereum.stackexchange.com/a/87/4575 :

contract SchedulerAPI { 
    function scheduleCall(address contractAddress,
                          bytes4 abiSignature,
                          uint targetBlock) public returns (address); }

contract CallMeLater {
    // The address of the v0.6.0 Alarm Clock scheduler contract.
    address constant Scheduler = SchedulerAPI(0xe109ecb193841af9da3110c80fdd365d1c23be2a);

    function CallMeLater() {
        // Schedule a call to the `callback` function
        Scheduler.value(2 ether).scheduleCall(
            address(this),               // the address that should be called.
            bytes4(sha3("callback()")),  // 4-byte abi signature of callback fn
            block.number + 5082,          // the block number to execute the call 
        );               //As we know 1 day duration (1440 minutes): 5082 blocks.
    }

    function callback() public {
        // whatever code you want executed.
          CallMeLater(); //added: recursive call.
    } }

Я добавил CallMeLater();в конец callback()функции, я полагаю, что будет новое расписание (на 1 день вперед), чтобы вызвать callback().

Ответы (2)

Решение

Протокол изменился с момента публикации вопроса. Можно выполнять рекурсивные вызовы, создав службу, которая, например, использует преимущества прокси-кошелька (для финансирования следующих вызовов).

Будильник Ethereum имеет пример RecurringPayment в своем репозитории. Это договор:

pragma solidity 0.4.24;

import "contracts/Interface/SchedulerInterface.sol";

/// Example of using the Scheduler from a smart contract to delay a payment.
contract RecurringPayment {
    SchedulerInterface public scheduler;

    uint paymentInterval;
    uint paymentValue;
    uint lockedUntil;

    address recipient;
    address public currentScheduledTransaction;

    event PaymentScheduled(address indexed scheduledTransaction, address recipient, uint value);
    event PaymentExecuted(address indexed scheduledTransaction, address recipient, uint value);

    function RecurringPayment(
        address _scheduler,
        uint _paymentInterval,
        uint _paymentValue,
        address _recipient
    )  public payable {
        scheduler = SchedulerInterface(_scheduler);
        paymentInterval = _paymentInterval;
        recipient = _recipient;
        paymentValue = _paymentValue;

        schedule();
    }

    function ()
        public payable 
    {
        if (msg.value > 0) { //this handles recieving remaining funds sent while scheduling (0.1 ether)
            return;
        } 

        process();
    }

    function process() public returns (bool) {
        payout();
        schedule();
    }

    function payout()
        private returns (bool)
    {
        require(block.number >= lockedUntil);
        require(address(this).balance >= paymentValue);

        recipient.transfer(paymentValue);

        emit PaymentExecuted(currentScheduledTransaction, recipient, paymentValue);
        return true;
    }

    function schedule() 
        private returns (bool)
    {
        lockedUntil = block.number + paymentInterval;

        currentScheduledTransaction = scheduler.schedule.value(0.1 ether)( // 0.1 ether is to pay for gas, bounty and fee
            this,                   // send to self
            "",                     // and trigger fallback function
            [
                1000000,            // The amount of gas to be sent with the transaction. Accounts for payout + new contract deployment
                0,                  // The amount of wei to be sent.
                255,                // The size of the execution window.
                lockedUntil,        // The start of the execution window.
                20000000000 wei,    // The gasprice for the transaction (aka 20 gwei)
                20000000000 wei,    // The fee included in the transaction.
                20000000000 wei,         // The bounty that awards the executor of the transaction.
                30000000000 wei     // The required amount of wei the claimer must send as deposit.
            ]
        );

        emit PaymentScheduled(currentScheduledTransaction, recipient, paymentValue);
    }
}

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

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

Дезинформация в других ответах/комментариях

Что ж, другой ответ не учитывает, как работает будильник Ethereum — этот вызов запланирован, а не вызывается мгновенно. Это означает, что не будет бесконечного цикла, это больше похоже setIntervalна JavaScript.

Кто-то также дезинформирует в комментарии, что есть gracePeriod, что означает: «Вы найдете параметр «gracePeriod», который говорит, что вы не можете сделать тот же вызов после 255 блоков». - но это тоже неправильно.

Сама связанная документация устарела, но в ней говорится:

uint8 gracePeriod: количество блоков после targetBlock, в течение которого этот вызов можно продолжать выполнять. Не может быть меньше 64 (по умолчанию: 255).

Таким образом, в этом примере gracePeriod может быть прочитан как ОКНО ВЫПОЛНЕНИЯ.

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

@alpher Вы смогли это проверить?
Согласно этому документу. Вы найдете параметр «gracePeriod», который говорит, что вы не можете сделать один и тот же вызов после 255 блоков. Так не означает ли это, что у рекурсии есть предел?