forked from DecentralizedClimateFoundation/DCIPs
111 lines
7.3 KiB
Markdown
111 lines
7.3 KiB
Markdown
---
|
|
eip: 1154
|
|
title: Oracle Interface
|
|
author: Alan Lu (@cag)
|
|
discussions-to: https://github.com/ethereum/EIPs/issues/1161
|
|
status: Withdrawn
|
|
type: Standards Track
|
|
category: ERC
|
|
created: 2018-06-13
|
|
---
|
|
|
|
## Simple Summary
|
|
A standard interface for oracles.
|
|
|
|
## Abstract
|
|
In order for ethereum smart contracts to interact with off-chain systems, oracles must be used. These oracles report values which are normally off-chain, allowing smart contracts to react to the state of off-chain systems. A distinction and a choice is made between push and pull based oracle systems. Furthermore, a standard interface for oracles is described here, allowing different oracle implementations to be interchangeable.
|
|
|
|
## Motivation
|
|
The Ethereum ecosystem currently has many different oracle implementations available, but they do not provide a unified interface. Smart contract systems would be locked into a single set of oracle implementations, or they would require developers to write adapters/ports specific to the oracle system chosen in a given project.
|
|
|
|
Beyond naming differences, there is also the issue of whether or not an oracle report-resolving transaction _pushes_ state changes by calling affected contracts, or changes the oracle state allowing dependent contracts to _pull_ the updated value from the oracle. These differing system semantics could introduce inefficiencies when adapting between them.
|
|
|
|
Ultimately, the value in different oracle systems comes from their underlying resolution mechanics, and points where these systems are virtually identical should be standardized.
|
|
|
|
These oracles may be used for answering questions about "real-world events", where each ID can be correlated with a specification of a question and its answers (so most likely for prediction markets, basically).
|
|
|
|
Another use case could be for decision-making processes, where the results given by the oracle represent decisions made by the oracle (e.g. futarchies). DAOs may require their use in decision making processes.
|
|
|
|
Both the ID and the results are intentionally unstructured so that things like time series data (via splitting the ID) and different sorts of results (like one of a few, any subset of up to 256, or some value in a range with up to 256 bits of granularity) can be represented.
|
|
|
|
## Specification
|
|
|
|
<dl>
|
|
<dt>Oracle</dt>
|
|
<dd>An entity which reports data to the blockchain.</dd>
|
|
|
|
<dt>Oracle consumer</dt>
|
|
<dd>A smart contract which receives data from an oracle.</dd>
|
|
|
|
<dt>ID</dt>
|
|
<dd>A way of indexing the data which an oracle reports. May be derived from or tied to a question for which the data provides the answer.</dd>
|
|
|
|
<dt>Result</dt>
|
|
<dd>Data associated with an id which is reported by an oracle. This data oftentimes will be the answer to a question tied to the id. Other equivalent terms that have been used include: answer, data, outcome.</dd>
|
|
|
|
<dt>Report</dt>
|
|
<dd>A pair (ID, result) which an oracle sends to an oracle consumer.</dd>
|
|
</dl>
|
|
|
|
```solidity
|
|
interface OracleConsumer {
|
|
function receiveResult(bytes32 id, bytes result) external;
|
|
}
|
|
```
|
|
|
|
`receiveResult` MUST revert if the `msg.sender` is not an oracle authorized to provide the `result` for that `id`.
|
|
|
|
`receiveResult` MUST revert if `receiveResult` has been called with the same `id` before.
|
|
|
|
`receiveResult` MAY revert if the `id` or `result` cannot be handled by the consumer.
|
|
|
|
Consumers MUST coordinate with oracles to determine how to encode/decode results to and from `bytes`. For example, `abi.encode` and `abi.decode` may be used to implement a codec for results in Solidity. `receiveResult` SHOULD revert if the consumer receives a unexpected result format from the oracle.
|
|
|
|
The oracle can be any Ethereum account.
|
|
|
|
## Rationale
|
|
The specs are currently very similar to what is implemented by ChainLink (which can use any arbitrarily-named callback) and Oraclize (which uses `__callback`).
|
|
|
|
With this spec, the oracle _pushes_ state to the consumer, which must react accordingly to the updated state. An alternate _pull_-based interface can be prescribed, as follows:
|
|
|
|
### Alternate Pull-based Interface
|
|
Here are alternate specs loosely based on Gnosis prediction market contracts v1. Reality Check also exposes a similar endpoint (`getFinalAnswer`).
|
|
|
|
```solidity
|
|
interface Oracle {
|
|
function resultFor(bytes32 id) external view returns (bytes result);
|
|
}
|
|
```
|
|
|
|
`resultFor` MUST revert if the result for an `id` is not available yet.
|
|
|
|
`resultFor` MUST return the same result for an `id` after that result is available.
|
|
|
|
### Push vs Pull
|
|
Note that push-based interfaces may be adapted into pull-based interfaces. Simply deploy an oracle consumer which stores the result received and implements `resultFor` accordingly.
|
|
|
|
Similarly, every pull-based system can be adapted into a push-based system: just add a method on the oracle smart contract which takes an oracle consumer address and calls `receiveResult` on that address.
|
|
|
|
In both cases, an additional transaction would have to be performed, so the choice to go with push or pull should be based on the dominant use case for these oracles.
|
|
|
|
In the simple case where a single account has the authority to decide the outcome of an oracle question, there is no need to deploy an oracle contract and store the outcome on that oracle contract. Similarly, in the case where the outcome comes down to a vote, existing multisignature wallets can be used as the authorized oracle.
|
|
|
|
#### Multiple Oracle Consumers
|
|
In the case that many oracle consumers depend on a single oracle result and all these consumers expect the result to be pushed to them, the push and pull adaptations mentioned before may be combined if the pushing oracle cannot be trusted to send the same result to every consumer (in a sense, this forwards the trust to the oracle adaptor implementation).
|
|
|
|
In a pull-based system, each of the consumers would have to be called to pull the result from the oracle contract, but in the proposed push-based system, the adapted oracle would have to be called to push the results to each of the consumers.
|
|
|
|
Transaction-wise, both systems are roughly equivalent in efficiency in this scenario, but in the push-based system, there's a need for the oracle consumers to store the results again, whereas in the pull-based system, the consumers may continue to refer to the oracle for the results. Although this may be somewhat less efficient, requiring the consumers to store the results can also provide security guarantees, especially with regards to result immutability.
|
|
|
|
#### Result Immutability
|
|
In both the proposed specification and the alternate specification, results are immutable once they are determined. This is due to the expectation that typical consumers will require results to be immutable in order to determine a resulting state consistently. With the proposed push-based system, the consumer enforces the result immutability requirement, whereas in the alternate pull-based system, either the oracle would have to be trusted to implement the spec correctly and enforce the immutability requirement, or the consumer would also have to handle result immutability.
|
|
|
|
For data which mutates over time, the `id` field may be structured to specify "what" and "when" for the data (using 128 bits to specify "when" is still safe for many millennia).
|
|
|
|
## Implementation
|
|
|
|
* [Tidbit](https://github.com/levelkdev/tidbit) tracks this EIP.
|
|
|
|
## Copyright
|
|
Copyright and related rights waived via [CC0](../LICENSE.md).
|