Contract-Design

當您使用乙太坊鬧鐘調度程序進行遞歸調度呼叫時會發生什麼?

  • July 18, 2019

我的目標是每天安排一次通話。

$$ Q $$是否可以使用遞歸函式使用乙太坊鬧鐘調度程序每天安排一次通話? 以下答案範例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().

解決方案

自問題發布以來,協議發生了變化。可以通過建構一個服務來進行遞歸呼叫,例如利用代理錢包(為後續呼叫提供資金)。

乙太坊鬧鐘在其儲存庫中有 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,這意味著你必須在創建它時為合約提供資金。這將為未來的遞歸呼叫提供資金。

很好的例子也是Recurring Alarm Clock。該項目是開源的,您可以查看程式碼。

其他答案/評論中的錯誤資訊

好吧,另一個答案沒有考慮乙太坊鬧鐘的工作原理-該呼叫是預定的,而不是立即呼叫的。這意味著,不會有無限循環,它更像是setInterval在 JavaScript 中。

有人還在評論中誤傳存在gracePeriod,這意味著:“您會發現一個參數“gracePeriod”,它表示您無法在 255 個塊之後進行相同的呼叫。——但這也是錯誤的。

連結的文件本身已經過時,但它說:

uint8 gracePeriod:targetBlock 之後仍然可以執行此呼叫的塊數。不能小於 64。(預設值:255)。

所以這個例子中的gracePeriod可以讀作EXECUTION WINDOW。

引用自:https://ethereum.stackexchange.com/questions/11199