Welcome to Ethereum Alarm Clock’s documentation!¶
The Ethereum Alarm Clock is a service that allows scheduling of contract function calls at a specified block number in the future. These scheduled calls are then executed by other nodes on the ethereum network who are reimbursed for their gas costs plus a small payment for the transaction.
Contents:
Overview¶
The Ethereum Alarm service is a contract on the ethereum network that facilitates scheduling of function calls for a specified block in the future. It is designed to require little or no trust between any of the users of the service, as well as providing no special access to the creator of the contract.
Scheduling Function Calls¶
When a contract, or individual wants to schedule a function call with the Alarm service it will perform the following steps.
- Schedule the function call with the service.
- Register any call data that will be required to make the function call (optional for functions that have no arguments).
Call Scheduling¶
Function calls can be scheduled for any block at least 40 blocks (~10 minutes) in the future. Scheduling is done by providing the Alarm service with the following information:
- Contract address the call should be executed on.
- ABI signature of the function that should be called.
- Target block number that the call should be executed on.
Optionally, these additional pieces of information can be supplied.
- Suggested gas amount that should be provided to the function. default: 0 to indicate no suggestion
- Number of blocks after the target block during which it still ok to execute the call. (between 64 - 255 blocks) default: 255
- Payment amount in wei that will be paid to the executor of the call. default: 1 ether
- Fee amount in wei that will be paid to the creator of the Alarm service. default: 100 finey
The scheduling transaction must also include enough ether to pay for the gas costs of the call as well as the payment and fee values.
Once scheduled, the call waits to be picked up and executed at the desired block.
Registering Call Data¶
The Alarm service is not aware of the function ABI for the calls it executes. Instead, it uses the function ABI signature and raw call data to execute the function call.
To do this, any data that needs to be used in the call must be registered prior to scheduling the call. Functions which do not have any arguments can skip this step.
Execution of scheduled calls¶
Scheduled function calls can ultimately be executed by anyone who wishes to initiate the transaction. This will likely be an automated process that monitors for upcoming scheduled calls and executes them at the appropriate block.
Usage Fees¶
In addition to the gas costs, schedulers are also encouraged to pay the call executor as well as the creator of the service for their effort. This value can be specified by the scheduler, meaning that you may choose to offer any amount (including zero).
The scheduling function uses the following defaults if specific values are not provided.
- Payment to the executor: 1 ether
- Payment to the service creator: 100 finney
Guarantees¶
Will the call happen?¶
There are no guarantees that your function will be called. This is not a shortcoming of the service, but rather a fundamental limitation of the ethereum network. Nobody is capable of forcing a transaction to be included in a specific block.
The design of this service is meant to provide the proper motivation for calls to be executed, but it is entirely possible that certain calls will be missed due to unforseen circumstances. Providing a higher Payment amount is a potential way to get your scheduled call handled at a higher priority as it will be more profitable to execute.
Will I get paid for executing a call?¶
If you are diligent about how you go about executing scheduled calls then executing scheduled calls is guaranteed to be profitable. See the section on executing calls for more information.
Scheduling¶
Call scheduling is the core of the Ethereum Alarm Service. Calls can be scheduled on any block at least 40 blocks (~10 minutes) in the future.
When a call is scheduled, the service deploys a new contract that represents the scheduled function call. This contract is referred to as the call contract. holds all of the metadata associated with the call as well as the funds that will be used to pay for the call.
Lifecycle of a Call Contract¶
- creation - The call contract is created as part of call scheduling.
- data-registered - The data for the call is registered with the contract. This step can be skipped for function calls that take no arguments.
- locked - The contract is locked, preventing cancellation starting 10 blocks before the call’s target block through the last block in the call window.
- execution - The executing transaction is sent, which triggers the call contract to execute the function call.
- payment - payments are sent to the executor and the creator of the alarm service.
- suicide - The contract suicides itself, sending the remainder of it’s funds to the call scheduler.
Scheduling the Call¶
Function calls are scheduled with the scheduleCall
function on the Alarm
service. This creates a new call contract that represents the function
call.
- Solidity Function Signature:
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod, uint basePayment, uint baseFee) public returns (address)
- ABI Signature:
TODO
The scheduleCall
function takes the following parameters:
Required Arguments
- address contractAddress: The contract address that the function should be called on.
- bytes4 abiSignature: The 4 byte ABI function signature for the call.
- uint targetBlock: The block number the call should be executed on.
Optional Arguments
- uint suggestedGas: A suggestion to the call executor as to how much gas should be provided to execute the call. (default: 0)
- uint8 gracePeriod: The number of blocks after
targetBlock
that it is ok to still execute this call. Cannot be less than 64. (default: 255) - uint basePayment: The base amount in wei that should be paid to the executor of the call. (default: 1 ether)
- uint baseFee: The base amount in wei that should be paid to the creator of the alarm service. (default: 100 finney)
The optional arguments are implemented through the following alternate invocation signatures. The default value for each of the optional arguments will be used if any of the following signatures are used.
- Solidity Function Signature:
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock) public returns (address)
- ABI Signature:
TODO
- Solidity Function Signature:
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas) public returns (address)
- ABI Signature:
TODO
- Solidity Function Signature:
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod) public returns (address)
- ABI Signature:
TODO
- Solidity Function Signature:
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod, uint basePayment) public returns (address)
- ABI Signature:
TODO
If the scheduleCall
function is being used from within a contract, the
address of the newly created call contract is returned. If instead, the
function is being called directly in a transaction, the address of the call
contract can be extracted from the transaction logs under the CallScheduled
event.
Contract scheduling its own call¶
Contracts can take care of their own call scheduling.
contract Lottery {
address alarm; // set by some other mechanism.
function beginLottery() public {
... // Do whatever setup needs to take place.
// Now we schedule the picking of the winner.
bytes4 sig = bytes4(sha3("pickWinner()"));
// approximately 24 hours from now
uint targetBlock = block.number + 5760;
// 0xTODO is the ABI signature computed from `bytes4(sha3("scheduleCall(...)"))`.
alarm.call(TODO, address(this), sig, targetBlock)
}
function pickWinner() public {
...
}
}
In this example Lottery
contract, every time the beginLottery
function
is called, a call to the pickWinner
function is scheduled for approximately
24 hours later (5760 blocks).
Scheduling a call for a contract¶
Alternatively, calls can be scheduled to be executed on other contracts
Lets look at an example where we want to schedule a funds transfer for a wallet contract of some sort.
Note
This example assuming that you have the Alarm contract ABI loaded into a web3 contract object.
// Now schedule the call
> signature = ... // the 4-byte ABI function signature for the wallet function that transfers funds.
> targetBlock = eth.getBlock('latest') + 100 // 100 blocks in the future.
> alarm.scheduleCall.sendTransaction(walletAddress, signature, targetBlock, {from: eth.coinbase})
Registering Call Data¶
If a function call requires arguments then it is up to the scheduler to register the call data prior to call execution.
The call contract allows for call data registration via two mechanisms. The primary mechanism is through the fallback function on the contract. This will set the call data as the full call data of the transaction.
// Register some call data
> web3.eth.sendTransaction({to: scheduler.address, data: "0x...."})
Or, from within your contract.
contract Lottery {
address alarm; // set by some other mechanism.
function beginLottery() public {
uint lotteryId = ...;
// Now we schedule the picking of the winner.
bytes4 sig = bytes4(sha3("pickWinner(uint256)"));
// 0x1991313 is the ABI signature computed from `bytes4(sha3("scheduleCall(address,bytes4,uint256)"))`.
alarm.call(0x1991313, address(this), sig, 100)
// Register the call data
alarm.call(lotteryId);
}
function pickWinner(uint lotteryId) public {
...
}
}
If however, your call data either has a bytes4
value as it’s first
argument, or, the first 4 bytes of the call data have a collision with one of
the existing function signatures on the call contract, you can use the
registerData
function instead.
- Solidity Function Signature:
registerData()
- ABI Signature:
0xb0f07e44
In solidity, this would look something like the following.
Upon receiving this call, the Alarm service strips off the first four bytes
from msg.data
to remove the ABI function signature and then stores the full
call data.
Once data has been registered, it cannot be modified. Attempts to do so will result in an exception.
ABI Encoding and address.call¶
The call()
function on an address in solidity does not do any ABI encoding,
so in cases where a scheduled call must pass something like a bytes
variable, you will need to handle the ABI encoding yourself.
Cancelling a call¶
A scheduled call can be cancelled by its scheduler up to 10 blocks
before it’s target block. To cancel a scheduled call use the cancel
function.
- Solidity Function Signature:
cancel(address callAddress)
- ABI Signature:
0xea8a1af0
This will result in the call contract suiciding, and sending any remaining funds to the scheduler’s address.
Looking up a Call¶
You can lookup whether a particular address is a known scheduled call with the
isKnownCall
function.
- Solidity Function Signature:
isKnownCall(address callAddress) returns (bool)
- ABI Signature:
0x523ccfa8
Returns a boolean as to whether this address represents a known scheduled call.
Call Contract API¶
Properties of a Call Contract¶
A call contract for a scheduled call has the following publicly accessible values.
- address contractAddress: the address of the contract the function should be called on.
- address schedulerAddress: the address who scheduled the call.
- uint targetBlock: the block that the function should be called on.
- uint8 gracePeriod: the number of blocks after the
targetBlock
during which it is stll ok to execute the call. - uint anchorGasPrice: the gas price that was used when the call was scheduled.
- uint suggestedGas: a suggestion to the call executor as to how much gas the called function is expected to need.
- uint basePayment: the amount in wei that will be paid to the address that executes the function call.
- uint baseFee: the amount in wei that will be paid the creator of the Alarm service.
- bytes4 abiSignature: the 4 byte ABI function signature of the function on the
contractAddress
for this call. - bytes callData: the data that will be passed to the called function.
Contract Address¶
address contractAddress
The address of the contract that the scheduled function call should be executed
on. Retrieved with the contractAddress
function.
- Solidity Function Signature:
contractAddress() returns (address)
- ABI Signature:
0xf6b4dfb4
Scheduler Address¶
address schedulerAddress
The address that the scheduled function call. Retrieved with the
schedulerAddress
function.
- Solidity Function Signature:
schedulerAddress() returns (address)
- ABI Signature:
0xae45850b
Target Block¶
uint targetBlock
The block number that this call should be executed on. Retrieved with the
targetBlock
function.
- Solidity Function Signature:
targetBlock() returns (uint)
- ABI Signature:
0xa16697a
Grace Period¶
uint8 gracePeriod
The number of blocks after the targetBlock that it is still ok to execute
this call. Retrieved with the gracePeriod
function.
- Solidity Function Signature:
gracePeriod() returns (uint8)
- ABI Signature:
0xa06db7dc
Anchor Gas Price¶
uint anchorGasPrice
The value of tx.gasprice
that was used to schedule this function call.
Retrieved with the anchorGasPrice
function.
- Solidity Function Signature:
anchorGasPrice() returns (uint)
- ABI Signature:
0x37f4c00e
Suggested Gas¶
uint suggestedGas
A suggestion for the amount of gas that a caller should expect the called
function to require. Retrieved with the suggestedGas
function.
- Solidity Function Signature:
suggestedGas() returns (uint)
- ABI Signature:
0x6560a307
Base Payment¶
uint basePayment
The base amount, in wei that the call executor’s payment will be calculated
from. Retrieved with the basePayment
function.
- Solidity Function Signature:
basePayment() returns (uint)
- ABI Signature:
0xc6502da8
Base Fee¶
uint baseFee
The base amount, in wei that the fee to the creator of the alarm service will
be calculate from. Retrieved with the baseFee
function.
- Solidity Function Signature:
baseFee() returns (uint)
- ABI Signature:
0x6ef25c3a
ABI Signature¶
bytes4 abiSignature
The ABI function signature that should be used to execute this function call.
Retrieved with the abiSignature
function.
- Solidity Function Signature:
abiSignature() returns (uint)
- ABI Signature:
0xca94692d
Call Data¶
bytes callData
The full call data that will be used for this function call. Retrieved
with the callData
function.
- Solidity Function Signature:
callData() returns (bytes)
- ABI Signature:
0x4e417a98
Functions of a Call Contract¶
Cancel¶
Cancels the scheduled call, suiciding the call contract and sending any funds to the scheduler’s address. This function cannot be called from 10 blocks prior to the target block for the call through the end of the grace period.
- Solidity Function Signature:
cancel() public onlyscheduler
- ABI Signature:
0xea8a1af0
Is Alive¶
Always returns true
. Useful to check if the contract has been suicided.
Caller Pool¶
The Alarm service maintains a pool of bonded callers who are responsible for executing scheduled calls. By joining the caller pool, an account is committing to executing scheduled calls in a reliable and consistent manner. Any caller who reliably executes the calls which are allocated to them will make a consistent profit from doing so, while callers who don’t get removed from the pool and forfeit some or all of their bond.
Caller Bonding¶
In order to execute scheduled calls, callers put up a small amount of ether up front. This bond, is held for the duration that a caller remains in the caller pool.
Minimum Bond¶
The bond amount is set as the maximum allowed transaction cost for a given
block. This value can be retrieved with the getMinimumBond
function.
- Solidity Function Signature:
getMinimumBond() returns (uint)
- ABI Signature:
0x23306ed6
This value can change from block to block depending on the gas price and gas limit.
Depositing your bond¶
Use the depositBond
function on the Caller Pool to deposit ether towards
your bond.
- Solidity Function Signature:
depositBond()
- ABI Signature:
0x741b3c39
Checking bond balance¶
Use the getBondBalance
function to check the bond balance of an account.
- Solidity Function Signature:
getBondBalance(address) returns (uint)
- ABI Signature:
0x33613cbe
Or to just check the balance of the sender of the transaction.
- Solidity Function Signature:
getBondBalance(address) returns (uint)
- ABI Signature:
0x3cbfed74
Withdrawing your bond¶
Use the withdrawBond
function on the Caller Pool to withdraw the bond
ether.
- Solidity Function Signature:
withdrawBond()
- ABI Signature:
0xc3daab96
If you are currently in a call pool, either active or queued, you will not be able to withdraw your account balance below the minimum bond amount.
Bond Forfeiture¶
In the event that a caller fails to execute a scheduled call during their allocated call window, a portion of their bond is forfeited and they are removed from the caller pool. The amount forfeited is equal to the current minimum bond amount.
There are no restrictions on re-entering the caller pool as long as a caller is willing to put up a new bond.
About Pools¶
The caller pool maintains a lists of caller addresses. Whenever a change is made to the pool, either addition of a new member or removal of an existing member, a new generation is queued to take place of the current generation.
The new generation will be set to begin 160 blocks in the future. During the first 80 blocks of this window, other members may leave or join the generation. The new generation will be frozen for the 80 blocks leading up to it’s starting block. Each new generation overlaps the previous generation by 256 blocks.
For example, if we are currently on block 1000, and a member exits the pool.
- The new generation will become active at block 1160
- The new generation will not allow any membership changes after block 1080
- The current generation will be set to end at block 1416 (1160 + 256)
Each new generation carries over all of the previous members upon creation.
Once the queued generation becomes active, members are once again allowed to enter and exit the pool.
Each time a new generation is created, the ordering of its members is shuffled.
Note
It is worth pointing out that from the block during which you exit the pool, you must still execute the calls that are allocated to you until the current generation has ended. Failing to do so will cause bond forfeiture.
Entering the Pool¶
An address can enter the caller pool if the following conditions are met.
- The caller has deposited the minimum bond amount into their bond account.
- The caller is not already in the active pool, or the next queued pool.
- The next queued pool does not go active within the next 80 blocks.
To enter the pool, call the enterPool
function on the Caller Pool.
- Solidity Function Signature:
enterPool()
- ABI Signature:
0x50a3bd39
If the appropriate conditions are met, you will be added to the next caller pool. This will create a new generation if one has not already been created. Otherwise you will be added to the next queued generation.
You can use the canEnterPool
function to check whether a given address is
currently allowed to enter the pool.
- Solidity Function Signature:
canEnterPool(address callerAddress) returns (bool)
- ABI Signature:
0x8dd5e298
Or to to check for the address sending the transaction.
- Solidity Function Signature:
canEnterPool() returns (bool)
- ABI Signature:
0xc630f92b
Exiting the Pool¶
An address can exit the caller pool if the following conditions are met.
- The caller is in the current active generation.
- The caller has not already exited or been removed from the queued pool (if it exists)
- The next queued pool does not go active within the next 80 blocks.
To exit the pool, use the exitPool
function on the Caller Pool.
- Solidity Function Signature:
exitPool()
- ABI Signature:
0x50a3bd39
If all conditions are met, a new caller pool will be queued if one has not already been created and your address will be removed from it.
You can use the canExitPool
function to check whether a given address is
currently allowed to exit the pool.
- Solidity Function Signature:
canExitPool(address callerAddress) returns (bool)
- ABI Signature:
0xb010d94a
Alernatively, you can check for the address sending the transaction.
- Solidity Function Signature:
canExitPool(address callerAddress) returns (bool)
- ABI Signature:
0x5a5383ac
Call Execution¶
Call execution is the process through which scheduled calls are executed at their desired block number. After a call has been scheduled, it can be executed by account which chooses to initiate the transaction. In exchange for executing the scheduled call, they are paid a small fee of approximately 1% of the gas cost used for executing the transaction.
Executing a call¶
Use the execute
function to execute a scheduled call.
- Solidity Function Signature:
execute(address callAddress)
- ABI Signature:
0xfcf36918
When this function is called, the following things happen.
- A few checks are done to be sure that all of the necessary pre-conditions
pass. If any fail, the function exits early without executing the scheduled
call:
- the call has not already been suicided
- the current block number is within the range this call is allowed to be executed.
- the caller is allowed to execute the function (see caller pool)
- The call is executed
- The gas cost and fees are computed and paid.
- The call contract suicides, sending any remaining funds to the scheduling address.
Payment¶
Each scheduled call sets its own payment value. This can be looked up with the
basePayment
accessor function.
The final payment value for executing the scheduled call is the basePayment
multiplied by a scalar value based on the difference between the gas price of
the executing transaction and the gas price that was used to schedule the
transaction. The formula for this scalar is such that the lower the gas price
of the executing transaction, the higher the payment.
Setting transaction gas and gas price¶
Each call contract has a suggestedGas
property that can be used as a
suggestion for how much gas the function call needs. In the case where this is
set to zero it means the scheduler has not provided a suggestion.
This suggested gas value should be used in conjuction with the basePayment
and baseFee
amounts with respect to the ether balance of the call contract.
The provided gas for the transaction should not exceed (balance - 2 *
(basePayment + baseFee)) / gasPrice
if you want to guarantee that you will be
fully reimbursed for gas expenditures.
Getting your payment¶
Payment for executing a call is sent to you as part of the executing
transaction, as well as being logged by the CallExecuted
event.
Determining what scheduled calls are next¶
You can query the Alarm service for the call key of the next scheduled call on
or after a specified block number using the getNextCall
function
- Solidity Function Signature:
getNextCall(uint blockNumber) returns (address)
- ABI Signature:
0x9f927be7
Since there may be multiple calls on the same block, it is best to also check
if the call has any siblings using the getNextCallSibling
function. This
function takes a call contract address and returns the address that is
scheduled to come next.
When checking for additional calls in this manner, you should check the target block of each subsequent call to be sure it is within a range that you care about.
- Solidity Function Signature:
getNextCallSibling(address callAddress) returns (address)
- ABI Signature:
0x48107843
Note
40 blocks into the future is a good range to monitor since new calls must always be scheduled at least 40 blocks in the future. You should also monitor these functions up to 10 blocks before their target block to be sure they are not cancelled.
Designated Callers¶
If the Caller Pool has any bonded callers in the current active pool, then only designated callers will be allowed to execute a scheduled call. The exception to this restriction is the last few blocks within the call’s grace period which the call enters free-for-all mode during which anyone may execute it.
If there are no bonded callers in the Caller Pool then the Alarm service will operate in free-for-all mode for all calls meaning anyone may execute any call at any block during the call window.
How callers designated¶
Each call has a window during which it is allowed to be executed. This window
begins at the specified targetBlock
and extends through targetBlock +
gracePeriod
. This window is inclusive of it’s bounding blocks.
For each 16 block section of the call window, the caller pool associated with
the targetBlock
is selected. The members of the pool can be though of as a
circular queue, meaning that when you iterate through them, when you reach the
last member, you start back over at the first member. For each call, a random
starting position is selected in the member queue and the 16 block sections of
the call window are assigned in order to the membes of the call pool beginning
at this randomly chosen index..
The last two 16 block sections (17-32 blocks depending on the gracePeriod) are not allocated, but are considered free-for-all allowing anyone to call.
Use the getDesignatedCaller
function to determine which caller from the
caller pool has been designated for the block.
- Solidity Function Signature:
getDesignatedCaller(address callAddress, uint256 blockNumber) returns (bool, address)
- ABI Signature:
0x5a8dd79f
- callAddress: specifies the address of the call contract.
- blockNumber: the block number (during the call window) in question.
This returns a boolean and an address. The boolean designates whether this
scheduled call was designated (if there are no registered caller pool members
then all calls operate in free-for-all mode). The address is the designated
caller. If the returned address is 0x0
then this call can be executed by
anyone on the provided block number.
Missing the call window¶
Anytime a caller fails to execute a scheduled call during the 4 block window reserved for them, the next caller has the opportunity to claim a portion of their bond merely by executing the call during their window. When this happens, the previous caller who missed their call window has the current minimum bond amount deducted from their bond balance and transferred to the caller who executed the call. The caller who missed their call is also removed from the pool. This removal takes 416 blocks to take place as it occurs within the same mechanism as if they removed themselves from the pool.
Free For All¶
When a call enters the last two 16-block chunks of its call window it enters free-for-all mode. During these blocks anyone, even unbonded callers, can execute the call. The sender of the executing transaction will be rewarded the bond bonus from all callers who missed their call window.
Safeguards¶
There are a limited set of safeguards that Alarm protects those executing calls from.
- Enforces the ability to pay for the maximum possible transaction cost up front.
- Ensures that the call cannot cause the executing transaction to fail due to running out of gas (like an infinite loop).
- Ensures that the funds to be used for payment are locked during the call execution.
Tips for executing scheduled calls¶
The following tips may be useful if you wish to execute calls.
Only look in the next 40 blocks¶
Since calls cannot be scheduled less than 40 blocks in the future, you can count on the call ordering remaining static for the next 40 blocks.
No cancellation in next 8 blocks¶
Since calls cannot be cancelled less than 8 blocks in the future, you don’t need to check cancellation status during the 8 blocks prior to its target block.
Check that it was not already called¶
If you are executing a call after the target block but before the grace period has run out, it is good to check that it has not already been called.
Check that the scheduler can pay¶
It is good to check that the scheduler has sufficient funds to pay for the call’s potential gas cost plus fees.
Call pricing and fees¶
The Alarm service operates under a scheduler pays model, which means that the scheduler of a call is responsible for paying for the full gas cost and fees associated with executing the call.
These funds must be presented upfront at the time of scheduling and are held by the call contract until execution.
Call Payment and Fees¶
When a call is scheduled, the scheduler can either provide values for the payment and fee, or leave them off in favor of using the default values.
The account which executes the scheduled call is reimbursed 100% of the gas cost + payment for their service as well as sending the fee to the creator of the service.
The GasPriceScalar multiplier¶
Both the payment and the fee are multiplied by the GasPriceScalar.
GasPriceScalar is a multiplier that ranges from 0 - 2 which is based on the difference between the gas priced used for call execution and the gas price used during call scheduling. This number incentivises the call executor to use as low a gas price as possible.
This multiplier is computed with the following formula.
- IF
gasPrice > anchorGasPrice
anchorGasPrice / gasPrice
- IF
gasPrice <= anchorGasPrice
anchorGasPrice / (2 * anchorGasPrice - gasPrice)
Where:
- anchorGasPrice is the
tx.gasprice
used when the call was scheduled. - gasPrice is the
tx.gasprice
used to execute the call.
At the time of call execution, the anchorGasPrice
has already been set, so
the only value that is variable is the gasPrice
which is set by the account
executing the transaction. Since the scheduler is the one who ends up paying
for the actual gas cost, this multiplier is designed to incentivize the caller
using the lowest gas price that can be expected to be reliably picked up and
promptly executed by miners.
Here are the values this formula produces for a baseGasPrice
of 20 and a
gasPrice
ranging from 10 - 40;
gasPrice | multiplier |
---|---|
15 | 1.20 |
16 | 1.17 |
17 | 1.13 |
18 | 1.09 |
19 | 1.05 |
20 | 1.00 |
21 | 0.95 |
22 | 0.91 |
23 | 0.87 |
24 | 0.83 |
25 | 0.80 |
26 | 0.77 |
27 | 0.74 |
28 | 0.71 |
29 | 0.69 |
30 | 0.67 |
31 | 0.65 |
32 | 0.63 |
33 | 0.61 |
34 | 0.59 |
35 | 0.57 |
36 | 0.56 |
37 | 0.54 |
38 | 0.53 |
39 | 0.51 |
40 | 0.50 |
You can see from this table that as the gasPrice
for the executing
transaction increases, the total payout for executing the call decreases. This
provides a strong incentive for the entity executing the transaction to use a
reasonably low value.
Alternatively, if the gasPrice
is set too low (potentially attempting to
maximize payout) and the call is not picked up by miners in a reasonable amount
of time, then the entity executing the call will not get paid at all. This
provides a strong incentive to provide a value high enough to ensure the
transaction will be executed.
Overhead¶
The gas overhead that you can expect to pay for your function is about 100,000 gas.
Contract ABI¶
Beyond the simplest use cases, the use of address.call
to interact with the
Alarm service is limiting. Beyond the readability issues, it is not possible
to get the return values from function calls when using call()
.
By using an abstract solidity contract which defines all of the function signatures, you can easily call any of the Alarm service’s functions, letting the compiler handle computation of the function ABI signatures.
Abstract Solidity Contracts¶
The following abstract contracts can be used alongside your contract code to interact with the Alarm service.
Abstract Scheduler Contract Source Code¶
The following abstract solidity contract can be used to interact with the scheduling contract from a solidity contract.
contract SchedulerAPI {
/*
* Call Scheduling API
*/
function getMinimumGracePeriod() constant returns (uint);
function getDefaultPayment() constant returns (uint);
function getDefaultFee() constant returns (uint);
function isKnownCall(address callAddress) constant returns (bool);
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock) public returns (address);
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas) public returns (address);
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod) public returns (address);
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod, uint basePayment) public returns (address);
function scheduleCall(address contractAddress, bytes4 abiSignature, uint targetBlock, uint suggestedGas, uint8 gracePeriod, uint basePayment, uint baseFee) public returns (address);
/*
* Call Execution API
*/
function execute(address callAddress) public;
/*
* Caller Pool bonding
*/
function getMinimumBond() constant returns (uint);
function depositBond() public;
function withdrawBond(uint value) public;
function getBondBalance() constant returns (uint);
function getBondBalance(address callerAddress) constant returns (uint);
/*
* Caller Pool Membership
*/
function getGenerationForCall(bytes32 callKey) constant returns (uint);
function getGenerationSize(uint generationId) constant returns (uint);
function getGenerationStartAt(uint generationId) constant returns (uint);
function getGenerationEndAt(uint generationId) constant returns (uint);
function getCurrentGenerationId() constant returns (uint);
function getNextGenerationId() constant returns (uint);
function isInPool() constant returns (bool);
function isInPool(address callerAddress) constant returns (bool);
function isInGeneration(uint generationId) constant returns (bool);
function isInGeneration(address callerAddress, uint generationId) constant returns (bool);
/*
* Caller Pool Metadata
*/
function getPoolFreezePeriod() constant returns (uint);
function getPoolOverlapSize() constant returns (uint);
function getPoolRotationDelay() constant returns (uint);
/*
* Caller Pool Entering and Exiting
*/
function canEnterPool() constant returns (bool);
function canEnterPool(address callerAddress) constant returns (bool);
function canExitPool() constant returns (bool);
function canExitPool(address callerAddress) constant returns (bool);
function enterPool() public;
function exitPool() public;
/*
* Next Call API
*/
function getCallWindowSize() constant returns (uint);
function getGenerationIdForCall(address callAddress) constant returns (uint);
function getDesignatedCaller(address callAddress, uint blockNumber) constant returns (bool, address);
function getNextCall(uint blockNumber) constant returns (bytes32);
function getNextCallSibling(address callAddress) constant returns (bytes32);
}
Abstract Call Contract Source Code¶
The following abstract solidity contract can be used to interact with a call contract from a solidity contract.
contract CallContractAPI {
uint public targetBlock;
uint8 public gracePeriod;
address public owner;
address public schedulerAddress;
uint public basePayment;
uint public baseFee;
function contractAddress() constant returns (address);
function abiSignature() constant returns (bytes4);
function callData() constant returns (bytes);
function anchorGasPrice() constant returns (uint);
function suggestedGas() constant returns (uint);
function isAlive() constant public;
// cancel and registerData are only callable by the scheduler of the
call contract.
function cancel() public onlyscheduler;
function registerData() public onlyscheduler;
}
Only use what you need¶
The contracts above have stub functions for every API exposed by Alarm and CallerPool. It is safe to remove any functions or events from the abstract contracts that you do not intend to use.
Caller Pool API¶
The Caller Pool contract exposes the following api functions.
Bond Management¶
The following functions are available for managing the ether deposited as a bond with the Caller Pool.
Get Minimum Bond¶
Use the getMinimumBond
function to retrieve the current minimum bond value
required to be able to enter the caller pool.
- Solidity Function Signature:
getMinimumBond() returns (uint)
- ABI Signature:
0x23306ed6
Check Bond Balance¶
Use the getBondBalance
function to check the bond balance for the provided
address.
- Solidity Function Signature:
getBondBalance(address callerAddress) returns (uint)
- ABI Signature:
0x33613cbe
Or to check the balance of the sender of the transaction.
- Solidity Function Signature:
getBondBalance() returns (uint)
- ABI Signature:
0x3cbfed74
Deposit Bond¶
Use the depositBond
function to deposit you bond with the caller pool.
- Solidity Function Signature:
depositBond()
- ABI Signature:
0x741b3c39
Withdraw Bond¶
Use the withdrawBond
function to withdraw funds from your bond.
- Solidity Function Signature:
withdrawBond()
- ABI Signature:
0xc3daab96
When in either an active or queued caller pool, you cannot withdraw your account below the minimum bond value.
Call Scheduling and Execution¶
The following function is available for callers.
Get Designated Caller¶
Use the getDesignatedCaller
function to retrieve which caller address, if
any, is designated as the caller for a given block and scheduled call.
- Solidity Function Signature:
getDesignatedCaller(bytes32 callKey, uint256 blockNumber)
- ABI Signature:
0x3c941423
- callKey: specifies the scheduled call.
- blockNumber: the block number (during the call window) in question.
This returns the address of the caller who is designated for this block, or
0x0
if this call can be executed by anyone on the specified block.
Pool Information¶
The following functions are available to query information about call pools.
Pool Generations¶
Use the getCurrentGenerationId
function to lookup the id of the pool
generation that is currently active. (returns 0 if no generations exist)
- Solidity Function Signature:
getCurrentGenerationId() returns (uint)
- ABI Signature:
0xb0171fa4
Use the getNextGenerationId
function to lookup the generation that is
queued to become active. Returns 0x0
if there is no next generation
queued.
- Solidity Function Signature:
getNextGenerationId() returns (uint)
- ABI Signature:
0xa502aae8
Use the getGenerationStartAt
function to lookup the block on which a given
generation will become active.
- Solidity Function Signature:
getGenerationStartAt(uint generationId) returns (uint)
- ABI Signature:
0xf8b11853
Use the getGenerationEndAt
function to lookup the block on which a given
generation will end and become inactive. Returns 0
if the generation is
still open ended.
- Solidity Function Signature:
getGenerationEndAt(uint generationId) returns (uint)
- ABI Signature:
0x306b031d
Use the getGenerationSize
function to query the number of members in a
given generation.
- Solidity Function Signature:
getGenerationSize(uint generationId) returns (uint)
- ABI Signature:
0xb3559460
Get Pool Key for Block¶
Use the getGenerationIdForCall
function to return the generationId
that
should be used for the given call key. This can be helpful to determine
whether your call execution script should pay attention to specific calls if
you are in the process of entering or exiting the pool.
- Solidity Function Signature:
getGenerationIdForCall(bytes32 callKey) returns (uint)
- ABI Signature:
0xdb681e54
Pool Membership¶
The following functions can be used to query about an address’s pool membership.
Is In Pool¶
Use the isInPool
function to query whether an address is in either the
currently active generation or the queued generation.
- Solidity Function Signature:
isInPool(address callerAddress) returns (bool)
- ABI Signature:
0x8baced64
Or to check whether the current calling address is in the pool.
- Solidity Function Signature:
isInPool() returns (bool)
- ABI Signature:
0x1ae460e5
Is In Generation¶
Use the isInGeneration
function to query whether an address is in a
specific generation.
- Solidity Function Signature:
isInGeneration(address callerAddress, uint256 generationId) returns (bool)
- ABI Signature:
0x7772a380
Or to query whether the current calling address is in the pool.
- Solidity Function Signature:
isInGeneration(uint256 generationId) returns (bool)
- ABI Signature:
0xa6c01cfd
Entering and Exiting Pools¶
The following functions can be used for actions related to entering and exiting the call pool.
Can Enter Pool¶
Use the canEnterPool
function to query whether a given address is allowed to
enter the caller pool.
- Solidity Function Signature:
canEnterPool(address callerAddress) returns (bool)
- ABI Signature:
0x8dd5e298
Or to query whether the current calling address is allowed.
- Solidity Function Signature:
canEnterPool() returns (bool)
- ABI Signature:
0xc630f92b
Can Exit Pool¶
Use the canExitPool
function to query whether or not you are allowed to
exit the caller pool.
- Solidity Function Signature:
canExitPool(address callerAddress) returns (bool)
- ABI Signature:
0xb010d94a
Or to query whether the current calling address is allowed.
- Solidity Function Signature:
canExitPool(address callerAddress) returns (bool)
- ABI Signature:
0x5a5383ac
Enter Pool¶
Use the enterPool
function to enter the caller pool.
- Solidity Function Signature:
enterPool() returns (bool)
- ABI Signature:
0x50a3bd39
Exit Pool¶
Use the exitPool
function to exit the caller pool.
- Solidity Function Signature:
exitPool() returns (bool)
- ABI Signature:
0x29917954
Events¶
The following events are used to log notable events within the Alarm service.
Scheduler Events¶
The Scheduler contract logs the following events.
Call Scheduled¶
- Solidity Event Signature:
CallScheduled(address callAddress)
- ABI Signature:
0x2b05d346
Logged when a new scheduled call is created.
Call Rejected¶
- Solidity Event Signature:
CallRejected(address indexed schedulerAddress, bytes32 reason)
- ABI Signature:
0x513485fc
Logged when an attempt to schedule a function call fails.
Awarded Missed Block Bonus¶
- Solidity Event Signature:
AwardedMissedBlockBonus(address indexed fromCaller, address indexed toCaller, uint indexed generationId, address callAddress, uint blockNumber, uint bonusAmount)
- ABI Signature:
0x1effaa2
Executed anytime a pool member’s bond is awarded to another address due to them missing a scheduled call that was designated as theirs to execute.
Call Contract Events¶
Each CallContract logs the following events.
Call Executed¶
- Solidity Event Signature:
CallExecuted(address indexed executor, uint gasCost, uint payment, uint fee, bool success)
;
- Solidity Event Signature:
ABI Signature:
0x4538b7ec
Executed when the call is executed.
Call Aborted¶
- Solidity Event Signature:
_CallAborted(address executor, bytes32 reason)
- ABI Signature:
0xe92bb686
Executed when an attempt is made to execute a scheduled call is rejected. The
reason
value in this log entry contains a short string representation of
why the call was rejected. (Note that this event name starts with an underscore)
Caller Pool Events¶
The following events are logged related to the caller pool.
Added To Generation¶
- Solidity Event Signature:
_AddedToGeneration(address indexed callerAddress, uint indexed pool)
- ABI Signature:
0x4327115b
Executed anytime a new address is added to the caller pool.
Removed From Generation¶
- Solidity Event Signature:
_RemovedFromGeneration(address indexed callerAddress, uint indexed pool)
- ABI Signature:
0xd6940c8c
Executed anytime an address is removed from the caller pool.
Terminology¶
Definitions for various terms that are used regularly to describe parts of the Alarm service.
General¶
- Ethereum Alarm Clock
Alarm
Alarm Service - Generic terms for the service as a whole.
- Scheduler
Scheduler Contract - The solidity contract responsible for scheduling a function call.
- Call Contract
- The solidity contract that is deployed for each scheduled call. This contract handles execution of the call, registration of call data, gas reimbursment, and payment and fee dispursment.
- Scheduled Call
- A contract function call that has been registered with the Alarm service to be executed at a specified time in the future (currently denoted by a block number).
- Caller Pool
- A group of ethereum addresses that have registered to be execute scheduled function calls.
Calls and Call Scheduling¶
- Scheduler
- The account which scheduled the function call.
- Executor
- The account which initiates the transaction which executes a scheduled function call.
- Target Block
- The first block number that a scheduled call can be called.
- Grace Period
- The number of blocks after the target block that a scheduled call can be be called.
- Call Window
- Used to refer to either the full window of blocks during which a scheduled call can be executed, or a portion of this window that has been designated to a specific caller.
- Payment
- The ethereum amount that is paid to the executor of the scheduled call.
- Fee
- The ethereum amount that is paid to the creator of the Alarm service.
- Anchor Gas Price
- The gas price that was used when scheduling the scheduled call.
- Gas Price Scalar
- A number ranging from 0 - 2 that is derived from the difference between the gas price of the executing transaction and the anchor gas grice. This number equals 1 when the two numbers are equal. It approaches 2 as the executing gas grice drops below the anchor gas price. It approaches zero as the executing gas price rises above the anchor gas price. This multiplier is applied to the payment and fee values, intending to motivate the executor to use a reasonable gas price.
Changelog¶
0.5.0¶
- Each scheduled call now exists as it’s own contract, referred to as a call contract.
- The authorization API has been removed. It is now possible for the contract
being called to look up
msg.sender
on the scheduling contract and find out who scheduled the call. - The account management API has been removed. Each call contract now manages it’s own gas money, the remainder of which is given back to the scheduler after the call is executed.
- All of the information that used to be stored about the call execution is now placed in event logs (gasUsed, wasSuccessful, wasCalled, etc)
0.4.0¶
- Convert Alarm service to use library contracts for all functionality.
- CallerPool contract API is now integrated into the Alarm API
0.3.0¶
- Convert Alarm service to use Grove for tracking scheduled call ordering.
- Enable logging most notable Alarm service events.
- Two additional convenience functions for invoking
scheduleCall
with gracePeriod and nonce as optional parameters.
0.2.0¶
- Fix for Issue 42. Make the free-for-all bond bonus restrict itself to the correct set of callers.
- Re-enable the right tree rotation in favor of removing three
getLastX
function. This is related to the pi-million gas limit which is restricting the code size of the contract.
0.1.0¶
- Initial release.