As the Alarm service has evolved a few high level goals have formed with relation to the desired economics of the system. I'd like to spend some time sharing these, because they are important to understanding the motivations behind the technical implementation.
- The service should be an open market.
- The cost of scheduled execution should be cheap (Ideally, negligible so that call scheduling can be pervasive).
- The execution of calls must be profitable.
In order to really understand these, we need to look at the fundamental constraints imposed by the system.
- The cost of the scheduling transaction.
- The cost of the executing transaction.
- The cost of rejecting an execution transaction (like in a situation where the function has already been called).
- Those executing calls should be motivated to use gas prices that are reasonable.
Lets consider a system in which 100 people are competing for call execution. For the sake of simplicity we will assume they are all equally likely to get their transaction accepted first, and thus, any single one of them will be first 1/100 tries. This means, that over the course of 100 calls, they will spend the rejected transaction cost 99 times, and get paid their payment plus gas reimbursement once. In this system, the payment amount would need to be more than the cost of the 99 rejected transaction for this to be profitable.
Also, in any system where there is transaction competition, call executors would be motivated to use ever increasing gas prices to incentivize miners to include their transaction over other transactions. This would further drive up the price of call scheduling.
This rules out any competition based system, meaning that at the time of call execution, and executor must know with 100% certainty that they will be fully reimbursed for their transaction costs. The ideal version of this is that for each call, the system guarantees that the number of transactions that must be reimbursed is as close to one as possible.
The caller pool system has this property at the cost of complexity for both the call executors and the Alarm service itself. An additional cost is that the caller pool is centralized in the Alarm contract, meaning that each call contract is forever tethered to the Alarm service which created it. Ideally, call contracts stand on their own without reliance on another service.
Over the last week, thanks to many discussions with other developers at Devcon, I've begun to work out what looks like a potential alternative approach to this problem. The idea revolves around two changes targeted at improving the open market aspect of the service.
- Schedulers would specify a maximum amount P they are willing to pay for execution (above the gas costs).
- Executors would bid on each call, with an amount B, less than P, that they are willing to perform the execution for.
It turns out that this approach suffers from the same problem as competitive transaction. If a call receives N bids, then the cost of those N bidding transactions must be covered, which in theory drives the cost of scheduling up at a rate linear to the number of bidders. In theory there would be fewer bidders since as the bidding price dropped lower and lower, fewer people would be motivated to bid.
Lets take a moment to clarify the problem statement.
- For each call contract, the mechanism that determines which addresses are allowed to execute the contract must involve as few transactions per call as possible.
- For a call contract to be fully independent of the Alarm service, it cannot rely on any central database. Any reliance on a central database will make migrating a call contract onto a newer version of the Alarm service harder.
I've starting seeing a potential solution for this problem by modeling it as a queue with the following properties.
- Dynamically adjusts size based on demand.
- Some reasonable guarantees about equality in terms of access to joining the queue.
The economics of this work out to each call having two transactions worth of overhead. One transaction to enter the queue, and one transaction to execute the call.
To keep call contracts portable, ideally the mechanisms that govern the queue length and joining mechanism can be built such that they are independent of any central state.
This portion of Alarm's evolution is still being heavily worked out, but each problem seems to be solvable. Stay tuned, and feel free to send me any ideas you have on the subject.