Contract-Design
當您使用乙太坊鬧鐘調度程序進行遞歸調度呼叫時會發生什麼?
我的目標是每天安排一次通話。
$$ 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。