Use of BTCRelay without paying fees
See original GitHub issueWith Metropolis, there will be a new opcode, REVERT
(https://github.com/ethereum/EIPs/pull/206) and RETURNDATA
(https://github.com/ethereum/EIPs/pull/211).
The REVERT
opcode will function as a throw
, reverting state-changes, but will not burn the remaining gas. Additionally, it can return some data, in order to provide the callee with information about the error.
Unfortunately, this EVM-change undermines the model for synchronous oracles which accept payment; it’s possible to
- Make a call to
BTCFreelay
- Make a call to
InternalCall
3. Perform call toBTCRelay
for verification, along with payment 4. Performrevert
along with the response from BTCRelay
This would revert the payment(s), but still grant access to the return value.
Note: Even without RETURNDATA
, it would still be possible to perform this attack, albeit with less data being extracted. Example gist showing how to ‘freeload’ on btcrelay using revert
without returndata
: https://gist.github.com/holiman/51f9b02b64f864b896129d329757460c .
Note 2, this can also be performed already today, using a regular throw
, but the attack is quite ‘messy’ since it needs to handle several intricate cases of OOG
due to remaining gas being discarded at every throw
.
I’m filing this as an issue, even if it’s not yet implemented, so there can be a discussion about possible future modifications that can be made. Also, posting it as a ‘known issue’ here makes in not eligible for a reward in the bug bounty.
Issue Analytics
- State:
- Created 7 years ago
- Comments:8 (3 by maintainers)
Top GitHub Comments
Oracles on Ethereum aren’t valuable because of the information itself. They are valuable because they make that information immutably available to contracts via a well defined trust scheme. When one pays for an Oracle, they are paying for the mechanism of getting real-world information into a contract with some well defined level of trust (depends on the oracle).
This opcode will undermine any system that charges for on-chain access to that data to more than one user. It will make it so that once someone has paid to put the data on-chain, any contract can access that data on-chain for free. While in some cases “pay to put on chain” can work, this doesn’t allow distribution of the cost across many users. If you have some kind of data that is expensive to put on the chain you run into a problem where the user that puts the data on-chain has to pay 100% of the cost and the next 1000 users get it for free.
At the moment, I don’t believe there is a live exploit because throw burns all gas, so there is no way for the contract to take the result and store it on-chain.
As an example:
Currently, step 3 would be a throw which would prevent step 4 from completing. This allows an oracle to distribute its costs across all users of the data rather than having to front-load the costs on the first request. This change, as I understand it, will effectively allow for a contract to be able to copy the result of any other contract without paying the contract for that result.
I would consider this a pretty major change in the model and it violates expectations of historic contract authors. My recommendation would be to make it so if you call revert, your stack is wiped rather than allowing the contract to retain its stack on a call to revert.
Of course, one can argue that the first person can pay the low-cost for the data and then publish it for free to everyone else but this can be mitigated by a semi-ponzi scheme where the first person who wants the data pays full price, then the next person pays full-price minus delta to the first person, the third person pays full price minus 2*delta to the second person, etc. This ensures that the contract always gets enough to cover its costs, while making it so if the data is highly sought after everyone will end up paying
delta
for the data. Similar schemes could be developed to have all parties who want the data pay a bond up-front, then after some time-delay they will be refunded such that they all pay the same amount (e.g., automated group discounts).The point of the above two examples are just to show that it is possible to setup an oracle that distributes costs to users of the data without risking itself being underpaid for the service.
The proof/s would be stored on-chain and would thus have costs. Exact economic costs aside, the “altruistic” party that wants to make BTC Relay free for use, may as well use those costs to submit Bitcoin blockheaders instead (and set no fee). EDIT: Or for a “malicious” party, the cost of storing the proof might be higher than just paying the fee.
There’s potentially 2 types of “on-chain oracles”: for-profit and non-profit. Business models for on-chain for-profit oracles may be tenuous or infeasible since the data is public (as @tawaren and others suggest). The fundamental reason for fees in BTC Relay is to strive for sustainable, decentralized infrastructure. BTC Relay needs data regularly and apart from “altruistic benefactor/s” which may not exist, it needs to incentivize the community to provide the data, and the obvious way to do it is to charge a fee (at least for first use of the data).
My understanding is that Oraclize isn’t 100% trustless; maybe increasing its trustlessness is more feasible than a sustainable, decentralized infrastructure. If a decentralized one works, it may have lower cost than a centralized oracle infrastructure (and also the advantage of availability guarantees of the blockchain).