mirror of https://github.com/status-im/EIPs.git
Merge branch 'master' of https://github.com/ethereum/EIPs into sp-account-versioining
This commit is contained in:
commit
02e4eda418
|
@ -5,7 +5,8 @@ status: Active
|
|||
type: Meta
|
||||
author: Martin Becze <mb@ethereum.org>, Hudson Jameson <hudson@ethereum.org>, and others
|
||||
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1.md
|
||||
created: 2015-10-27, 2017-02-01
|
||||
created: 2015-10-27
|
||||
updated: 2015-12-07, 2016-02-01, 2018-03-21, 2018-05-29, 2018-10-17
|
||||
---
|
||||
|
||||
## What is an EIP?
|
||||
|
@ -25,7 +26,7 @@ There are three types of EIP:
|
|||
- A **Standard Track EIP** describes any change that affects most or all Ethereum implementations, such as a change to the the network protocol, a change in block or transaction validity rules, proposed application standards/conventions, or any change or addition that affects the interoperability of applications using Ethereum. Furthermore Standard EIPs can be broken down into the following categories. Standards Track EIPs consist of three parts, a design document, implementation, and finally if warranted an update to the [formal specification].
|
||||
- **Core** - improvements requiring a consensus fork (e.g. [EIP5], [EIP101]), as well as changes that are not necessarily consensus critical but may be relevant to [“core dev” discussions](https://github.com/ethereum/pm) (for example, [EIP90], and the miner/node strategy changes 2, 3, and 4 of [EIP86]).
|
||||
- **Networking** - includes improvements around [devp2p] ([EIP8]) and [Light Ethereum Subprotocol], as well as proposed improvements to network protocol specifications of [whisper] and [swarm].
|
||||
- **Interface** - includes improvements around client [API/RPC] specifications and standards, and also certain language-level standards like method names ([EIP59], [EIP6]) and [contract ABIs]. The label “interface” aligns with the [interfaces repo] and discussion should primarily occur in that repository before an EIP is submitted to the EIPs repository.
|
||||
- **Interface** - includes improvements around client [API/RPC] specifications and standards, and also certain language-level standards like method names ([EIP6]) and [contract ABIs]. The label “interface” aligns with the [interfaces repo] and discussion should primarily occur in that repository before an EIP is submitted to the EIPs repository.
|
||||
- **ERC** - application-level standards and conventions, including contract standards such as token standards ([ERC20]), name registries ([ERC26], [ERC137]), URI schemes ([ERC67]), library/package formats ([EIP82]), and wallet formats ([EIP75], [EIP85]).
|
||||
- An **Informational EIP** describes an Ethereum design issue, or provides general guidelines or information to the Ethereum community, but does not propose a new feature. Informational EIPs do not necessarily represent Ethereum community consensus or a recommendation, so users and implementers are free to ignore Informational EIPs or follow their advice.
|
||||
- A **Meta EIP** describes a process surrounding Ethereum or proposes a change to (or an event in) a process. Process EIPs are like Standards Track EIPs but apply to areas other than the Ethereum protocol itself. They may propose an implementation, but not to Ethereum's codebase; they often require community consensus; unlike Informational EIPs, they are more than recommendations, and users are typically not free to ignore them. Examples include procedures, guidelines, changes to the decision-making process, and changes to the tools or environment used in Ethereum development. Any meta-EIP is also considered a Process EIP.
|
||||
|
@ -55,7 +56,7 @@ Each status change is requested by the EIP author and reviewed by the EIP editor
|
|||
* **Draft** -- Once the first draft has been merged, you may submit follow-up pull requests with further changes to your draft until such point as you believe the EIP to be mature and ready to proceed to the next status. An EIP in draft status must be implemented to be considered for promotion to the next status (ignore this requirement for core EIPs).
|
||||
* :arrow_right: Last Call -- If agreeable, the EIP editor will assign Last Call status and set a review end date (`review-period-end`), normally 14 days later.
|
||||
* :x: Last Call -- A request for Last Call status will be denied if material changes are still expected to be made to the draft. We hope that EIPs only enter Last Call once, so as to avoid unnecessary noise on the RSS feed.
|
||||
* **Last Call** -- This EIP will listed prominently on the http://eips.ethereum.org/ website (subscribe via RSS at [last-call.xml](/last-call.xml)).
|
||||
* **Last Call** -- This EIP will listed prominently on the https://eips.ethereum.org/ website (subscribe via RSS at [last-call.xml](/last-call.xml)).
|
||||
* :x: -- A Last Call which results in material changes or substantial unaddressed technical complaints will cause the EIP to revert to Draft.
|
||||
* :arrow_right: Accepted (Core EIPs only) -- A successful Last Call without material changes or unaddressed technical complaints will become Accepted.
|
||||
* :arrow_right: Final (Not core EIPs) -- A successful Last Call without material changes or unaddressed technical complaints will become Final.
|
||||
|
@ -67,7 +68,7 @@ Other exceptional statuses include:
|
|||
|
||||
* **Deferred** -- This is for core EIPs that have been put off for a future hard fork.
|
||||
* **Rejected** -- An EIP that is fundamentally broken or a Core EIP that was rejected by the Core Devs and will not be implemented.
|
||||
* **Active** -- This is similar to Final, but denotes an EIP which which may be updated without changing its EIP number.
|
||||
* **Active** -- This is similar to Final, but denotes an EIP which may be updated without changing its EIP number.
|
||||
* **Superseded** -- An EIP which was previously final but is no longer considered state-of-the-art. Another EIP will be in Final status and reference the Superseded EIP.
|
||||
|
||||
## What belongs in a successful EIP?
|
||||
|
@ -112,6 +113,8 @@ Each EIP must begin with an RFC 822 style header preamble, preceded and followed
|
|||
|
||||
` created:` <date created on>
|
||||
|
||||
` * updated:` <comma separated list of dates>
|
||||
|
||||
` * requires:` <EIP number(s)>
|
||||
|
||||
` * replaces:` <EIP number(s)>
|
||||
|
@ -164,6 +167,10 @@ The `category` header specifies the EIP's category. This is required for standar
|
|||
|
||||
The `created` header records the date that the EIP was assigned a number. Both headers should be in yyyy-mm-dd format, e.g. 2001-08-14.
|
||||
|
||||
#### `updated` header
|
||||
|
||||
The `updated` header records the date(s) when the EIP was updated with "substantional" changes. This header is only valid for EIPs of Draft and Active status.
|
||||
|
||||
#### `requires` header
|
||||
|
||||
EIPs may have a `requires` header, indicating the EIP numbers that this EIP depends on.
|
||||
|
@ -224,14 +231,16 @@ The editors don't pass judgment on EIPs. We merely do the administrative & edito
|
|||
|
||||
This document was derived heavily from [Bitcoin's BIP-0001] written by Amir Taaki which in turn was derived from [Python's PEP-0001]. In many places text was simply copied and modified. Although the PEP-0001 text was written by Barry Warsaw, Jeremy Hylton, and David Goodger, they are not responsible for its use in the Ethereum Improvement Process, and should not be bothered with technical questions specific to Ethereum or the EIP. Please direct all comments to the EIP editors.
|
||||
|
||||
December 7, 2016: EIP 1 has been improved and will be placed as a PR.
|
||||
December 7, 2015: EIP 1 has been improved and will be placed as a PR.
|
||||
|
||||
February 1, 2016: EIP 1 has added editors, made draft improvements to process, and has merged with Master stream.
|
||||
|
||||
March 21, 2018: Minor edits to accommodate the new automatically-generated EIP directory on [eips.ethereum.org](http://eips.ethereum.org/).
|
||||
March 21, 2018: Minor edits to accommodate the new automatically-generated EIP directory on [eips.ethereum.org](https://eips.ethereum.org/).
|
||||
|
||||
May 29, 2018: A last call process was added.
|
||||
|
||||
Oct 17, 2018: The `updated` header was introduced.
|
||||
|
||||
See [the revision history for further details](https://github.com/ethereum/EIPs/commits/master/EIPS/eip-1.md), which is also available by clicking on the History button in the top right of the EIP.
|
||||
|
||||
### Bibliography
|
||||
|
@ -246,7 +255,6 @@ See [the revision history for further details](https://github.com/ethereum/EIPs/
|
|||
[whisper]: https://github.com/ethereum/go-ethereum/wiki/Whisper-Overview
|
||||
[swarm]: https://github.com/ethereum/go-ethereum/pull/2959
|
||||
[API/RPC]: https://github.com/ethereum/wiki/wiki/JSON-RPC
|
||||
[EIP59]: https://github.com/ethereum/EIPs/issues/59
|
||||
[EIP6]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-6.md
|
||||
[contract ABIs]: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
||||
[interfaces repo]: https://github.com/ethereum/interfaces
|
||||
|
|
|
@ -3,9 +3,9 @@ eip: 1013
|
|||
title: "Hardfork Meta: Constantinople"
|
||||
author: Nick Savers (@nicksavers)
|
||||
type: Meta
|
||||
status: Draft
|
||||
status: Final
|
||||
created: 2018-04-20
|
||||
requires: 145, 1014, 1052, 1234, 1283
|
||||
requires: 145, 609, 1014, 1052, 1234, 1283
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
@ -17,18 +17,21 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Cons
|
|||
- Codename: Constantinople
|
||||
- Aliases: Metropolis/Constantinople, Metropolis part 2
|
||||
- Activation:
|
||||
- Block >= TBD on the Ethereum mainnet
|
||||
- Block >= 4,230,000 on the Ropsten testnet
|
||||
- `Block >= 7_280_000` on the Ethereum mainnet
|
||||
- `Block >= 4,230,000` on the Ropsten testnet
|
||||
- `Block >= 9_200_000` on the Kovan testnet
|
||||
- `Block >= 3_660_663` on the Rinkeby testnet
|
||||
- Included EIPs:
|
||||
- [EIP 145](./eip-145.md): Bitwise shifting instructions in EVM
|
||||
- [EIP 1014](./eip-1014.md): Skinny CREATE2
|
||||
- [EIP 1052](./eip-1052.md): EXTCODEHASH Opcode
|
||||
- [EIP 1234](./eip-1234.md): Delay difficulty bomb, adjust block reward
|
||||
- [EIP 1283](./eip-1283.md): Net gas metering for SSTORE without dirty maps
|
||||
- [EIP 145](https://eips.ethereum.org/EIPS/eip-145): Bitwise shifting instructions in EVM
|
||||
- [EIP 1014](https://eips.ethereum.org/EIPS/eip-1014): Skinny CREATE2
|
||||
- [EIP 1052](https://eips.ethereum.org/EIPS/eip-1052): EXTCODEHASH Opcode
|
||||
- [EIP 1234](https://eips.ethereum.org/EIPS/eip-1234): Delay difficulty bomb, adjust block reward
|
||||
- [EIP 1283](https://eips.ethereum.org/EIPS/eip-1283): Net gas metering for SSTORE without dirty maps
|
||||
|
||||
## References
|
||||
|
||||
The list above includes the EIPs discussed as candidates for Constantinople at the All Core Dev [Constantinople Session #1](https://github.com/ethereum/pm/issues/55). See also [Constantinople Progress Tracker](https://github.com/ethereum/pm/wiki/Constantinople-Progress-Tracker).
|
||||
1. The list above includes the EIPs discussed as candidates for Constantinople at the All Core Dev [Constantinople Session #1](https://github.com/ethereum/pm/issues/55). See also [Constantinople Progress Tracker](https://github.com/ethereum/pm/wiki/Constantinople-Progress-Tracker).
|
||||
2. https://blog.ethereum.org/2019/02/22/ethereum-constantinople-st-petersburg-upgrade-announcement/
|
||||
|
||||
## Copyright
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ title: Skinny CREATE2
|
|||
author: Vitalik Buterin (@vbuterin)
|
||||
category: Core
|
||||
type: Standards Track
|
||||
status: Draft
|
||||
status: Final
|
||||
created: 2018-04-20
|
||||
---
|
||||
|
||||
### Specification
|
||||
|
||||
Adds a new opcode at 0xf5, which takes 4 stack arguments: endowment, memory_start, memory_length, salt. Behaves identically to CREATE, except using `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]` instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
||||
Adds a new opcode at 0xf5, which takes 4 stack arguments: endowment, memory_start, memory_length, salt. Behaves identically to CREATE, except using `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:]` instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
||||
|
||||
The `CREATE2` has the same `gas` schema as `CREATE`, but also an extra `hashcost` of `GSHA3WORD * ceil(len(init_code) / 32)`, to account for the hashing that must be performed. The `hashcost` is deducted at the same time as memory-expansion gas and `CreateGas` is deducted: _before_ evaluation of the resulting address and the execution of `init_code`.
|
||||
|
||||
|
@ -52,7 +52,7 @@ With [EIP 161](https://eips.ethereum.org/EIPS/eip-161)
|
|||
|
||||
> Account creation transactions and the CREATE operation SHALL, prior to the execution of the initialisation code, increment the nonce over and above its normal starting value by one
|
||||
|
||||
This means that if a contract is created in a transaction, the `nonce` is immediately non-zero, with the side-effect that a collision within the same transaction will always fail -- even if it's carried out from the `init_code` itself/
|
||||
This means that if a contract is created in a transaction, the `nonce` is immediately non-zero, with the side-effect that a collision within the same transaction will always fail -- even if it's carried out from the `init_code` itself.
|
||||
|
||||
It should also be noted that `SELFDESTRUCT` has no immediate effect on `nonce` or `code`, thus a contract cannot be destroyed and recreated within one transaction.
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ eip: 1015
|
|||
title: Configurable On Chain Issuance
|
||||
author: Alex Van de Sande <avsa@ethereum.org>
|
||||
discussions-to: https://ethereum-magicians.org/t/eip-dynamic-block-rewards-with-governance-contract/204
|
||||
status: Draft
|
||||
status: Deferred
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2018-04-20
|
||||
|
@ -28,16 +28,16 @@ Moving to PoS has been on the roadmap since day 0 for ethereum, along with a red
|
|||
|
||||
#### Asics and advantadges of PoW
|
||||
|
||||
[EIP 960](http://eips.ethereum.org/EIPS/eip-969) proposes a change in algorithm to avoid mining being dominated by ASICS. Counter arguments by Phil Daian argue among others than [resisting economies of scale is futile and there might be specific security advantadges to specialized hardware](https://pdaian.com/blog/anti-asic-forks-considered-harmful/). One of the main arguments for PoW mining, even when it doesn't provide security, it is useful as a fair distribution mechanism, that **PoW allows any person with a computer, internet access and electricity to obtain currency without having to deal with government imposed currency controls**.
|
||||
[EIP 960](https://eips.ethereum.org/EIPS/eip-969) proposes a change in algorithm to avoid mining being dominated by ASICS. Counter arguments by Phil Daian argue among others than [resisting economies of scale is futile and there might be specific security advantadges to specialized hardware](https://pdaian.com/blog/anti-asic-forks-considered-harmful/). One of the main arguments for PoW mining, even when it doesn't provide security, it is useful as a fair distribution mechanism, that **PoW allows any person with a computer, internet access and electricity to obtain currency without having to deal with government imposed currency controls**.
|
||||
|
||||
#### Recovery Forks
|
||||
|
||||
After the Parity Multisig library self destruction, three different strategies have been attempted to recover the funds: [a general protocol improvement to allow reviving self destructed contracts](https://gist.github.com/5chdn/a9bb8617cc8523a030126a3d1c60baf3) (which was considered dangerous), a [general process to recover funds](https://github.com/ethereum/EIPs/pull/867) and a [specific recovery of the multisig library](http://eips.ethereum.org/EIPS/eip-999). The latter two are finding a lot of resistance from the community, but it's unlikely that these issues are going away soon. The affected parties have a large incentive (fluctuating at almost half a billion dollars) to keep trying, and it's an issue that is likely to occur again in the future. If they get reimbursed, [there are many other special cases of ether provably burnt or stuck](https://github.com/ethereum/EIPs/issues/156) that might deserve the same treatment. If they get shut down, they have an incentive to move forward a fork implementation: even if they are a minority chain, it's likely they'll recover an amount larger than 0, which is what they would otherwise, and it means the main ethereum community might lose a valuable team of developers.
|
||||
After the Parity Multisig library self destruction, three different strategies have been attempted to recover the funds: [a general protocol improvement to allow reviving self destructed contracts](https://gist.github.com/5chdn/a9bb8617cc8523a030126a3d1c60baf3) (which was considered dangerous), a [general process to recover funds](https://github.com/ethereum/EIPs/pull/867) and a [specific recovery of the multisig library](https://eips.ethereum.org/EIPS/eip-999). The latter two are finding a lot of resistance from the community, but it's unlikely that these issues are going away soon. The affected parties have a large incentive (fluctuating at almost half a billion dollars) to keep trying, and it's an issue that is likely to occur again in the future. If they get reimbursed, [there are many other special cases of ether provably burnt or stuck](https://github.com/ethereum/EIPs/issues/156) that might deserve the same treatment. If they get shut down, they have an incentive to move forward a fork implementation: even if they are a minority chain, it's likely they'll recover an amount larger than 0, which is what they would otherwise, and it means the main ethereum community might lose a valuable team of developers.
|
||||
|
||||
|
||||
#### Other Public Goods
|
||||
|
||||
There are many other types of public goods that could be funded by issuance. By *Public Good*, I'm using a strict definition of something that brings value to everyone, both those who funded it and free-loaders, making it hard to fund it exclusively by traditional private incentives. They can be research, whole network security, [incentivize full clients and networking](http://eips.ethereum.org/EIPS/eip-908), fair distribution of tokens etc.
|
||||
There are many other types of public goods that could be funded by issuance. By *Public Good*, I'm using a strict definition of something that brings value to everyone, both those who funded it and free-loaders, making it hard to fund it exclusively by traditional private incentives. They can be research, whole network security, [incentivize full clients and networking](https://eips.ethereum.org/EIPS/eip-908), fair distribution of tokens etc.
|
||||
|
||||
## Proposed Solution
|
||||
### Issuance Contract
|
||||
|
|
|
@ -3,7 +3,7 @@ eip: 1052
|
|||
title: EXTCODEHASH opcode
|
||||
author: Nick Johnson <arachnid@notdot.net>, Paweł Bylica <pawel@ethereum.org>
|
||||
discussions-to: https://ethereum-magicians.org/t/extcodehash-opcode/262
|
||||
status: Draft
|
||||
status: Final
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2018-05-02
|
||||
|
|
563
EIPS/eip-1057.md
563
EIPS/eip-1057.md
|
@ -11,80 +11,150 @@ created: 2018-05-02
|
|||
|
||||
## Simple Summary
|
||||
|
||||
The following is a proposal for an alternate proof-of-work algorithm - **“ProgPoW”** - tuned for commodity hardware in order to close the efficiency gap available to specialized ASICs.
|
||||
A new Proof-of-Work algorithm to replace Ethash that utilizes almost all parts of commodity GPUs.
|
||||
|
||||
## Abstract
|
||||
|
||||
The security of proof-of-work is built on a fair, randomized lottery where miners with similar resources have a similar chance of generating the next block.
|
||||
|
||||
For Ethereum - a community based on widely distributed commodity hardware - specialized ASICs enable certain participants to gain a much greater chance of generating the next block, and undermine the distributed security.
|
||||
|
||||
ASIC-resistance is a misunderstood problem. FPGAs, GPUs and CPUs can themselves be considered ASICs. Any algorithm that executes on a commodity ASIC can have a specialized ASIC made for it; most existing algorithms provide opportunities that reduce power usage and cost. Thus, the proper question to ask when solving ASIC-resistance is “how much more efficient will a specialized ASIC be, in comparison with commodity hardware?”
|
||||
|
||||
EIP<NaN> presents an algorithm that is tuned for commodity GPUs where there is minimal opportunity for ASIC specialization. This prevents specialized ASICs without resorting to a game of whack-a-mole where the network changes algorithms every few months.
|
||||
ProgPoW is a proof-of-work algorithm designed to close the efficency gap available to specialized ASICs. It utilizes almost all parts of commodity hardware (GPUs), and comes pre-tuned for the most common hardware utilized in the Ethereum network.
|
||||
|
||||
## Motivation
|
||||
|
||||
Until Ethereum transitions to a pure proof-of-stake model, proof-of-work will continue to be a part of the security of the network - whether it’s adapted into a hybrid model (as is the case of Casper FFG), or adopted by a hard fork.
|
||||
Ever since the first bitcoin mining ASIC was released, many new Proof of Work algorithms have been created with the intention of being “ASIC-resistant”. The goal of “ASIC-resistance” is to resist the centralization of PoW mining power such that these coins couldn’t be so easily manipulated by a few players.
|
||||
|
||||
Ethash allows for the creation of an ASIC that is roughly twice as efficient as a commodity GPU. Ethash’s memory accesses are paired with a very small amount of fixed compute. Most of a GPU’s capacity and complexity sits idle, wasting power, while waiting for DRAM accesses. A specialized ASIC can implement a much smaller (and cheaper) compute engine that burns much less power.
|
||||
This document presents an overview of the algorithm and examines what it means to be “ASIC-resistant.” Next, we compare existing PoW designs by analyzing how each algorithm executes in hardware. Finally, we present the detailed implementation by walking through the code.
|
||||
|
||||
As miner rewards are reduced with Casper FFG, it will remain profitable to mine on a specialized ASIC long after GPUs have exited the network. This will make it easier for an entity that has access to private ASICs to stage a 51% attack on the Ethereum network.
|
||||
### ProgPoW Overview
|
||||
The design goal of ProgPoW is to have the algorithm’s requirements match what is available on commodity GPUs: If the algorithm were to be implemented on a custom ASIC there should be little opportunity for efficiency gains compared to a commodity GPU.
|
||||
|
||||
The main elements of the algorithm are:
|
||||
* Changes keccak_f1600 (with 64-bit words) to keccak_f800 (with 32-bit words) to reduce impact on total power
|
||||
* Increases mix state.
|
||||
* Adds a random sequence of math in the main loop.
|
||||
* Adds reads from a small, low-latency cache that supports random addresses.
|
||||
* Increases the DRAM read from 128 bytes to 256 bytes.
|
||||
|
||||
The random sequence changes every `PROGPOW_PERIOD` (about 2 to 12 minutes depending on the configured value). When mining source code is generated for the random sequence and compiled on the host CPU. The GPU will execute the compiled code where what math to perform and what mix state to use are already resolved.
|
||||
|
||||
While a custom ASIC to implement this algorithm is still possible, the efficiency gains available are minimal. The majority of a commodity GPU is required to support the above elements. The only optimizations available are:
|
||||
* Remove the graphics pipeline (displays, geometry engines, texturing, etc)
|
||||
* Remove floating point math
|
||||
* A few ISA tweaks, like instructions that exactly match the merge() function
|
||||
|
||||
These would result in minimal, roughly 1.1-1.2x, efficiency gains. This is much less than the 2x for Ethash or 50x for Cryptonight.
|
||||
|
||||
### Rationale for PoW on Commodity Hardware
|
||||
With the growth of large mining pools, the control of hashing power has been delegated to the top few pools to provide a steadier economic return for small miners. While some have made the argument that large centralized pools defeats the purpose of “ASIC resistance,” it’s important to note that ASIC based coins are even more centralized for several reasons.
|
||||
|
||||
1. No natural distribution: There isn’t an economic purpose for ultra-specialized hardware outside of mining and thus no reason for most people to have it.
|
||||
2. No reserve group: Thus, there’s no reserve pool of hardware or reserve pool of interested parties to jump in when coin price is volatile and attractive for manipulation.
|
||||
3. High barrier to entry: Initial miners are those rich enough to invest capital and ecological resources on the unknown experiment a new coin may be. Thus, initial coin distribution through mining will be very limited causing centralized economic bias.
|
||||
4. Delegated centralization vs implementation centralization: While pool centralization is delegated, hardware monoculture is not: only the limiter buyers of this hardware can participate so there isn’t even the possibility of divesting control on short notice.
|
||||
5. No obvious decentralization of control even with decentralized mining: Once large custom ASIC makers get into the game, designing back-doored hardware is trivial. ASIC makers have no incentive to be transparent or fair in market participation.
|
||||
|
||||
While the goal of “ASIC resistance” is valuable, the entire concept of “ASIC resistance” is a bit of a fallacy. CPUs and GPUs are themselves ASICs. Any algorithm that can run on a commodity ASIC (a CPU or GPU) by definition can have a customized ASIC created for it with slightly less functionality. Some algorithms are intentionally made to be “ASIC friendly” - where an ASIC implementation is drastically more efficient than the same algorithm running on general purpose hardware. The protection that this offers when the coin is unknown also makes it an attractive target for a dedicate mining ASIC company as soon as it becomes useful.
|
||||
|
||||
Therefore, ASIC resistance is: the efficiency difference of specilized hardware versus hardware that has a wider adoption and applicability. A smaller efficiency difference between custom vs general hardware mean higher resistance and a better algorithm. This efficiency difference is the proper metric to use when comparing the quality of PoW algorithms. Efficiency could mean absolute performance, performance per watt, or performance per dollar - they are all highly correlated. If a single entity creates and controls an ASIC that is drastically more efficient, they can gain 51% of the network hashrate and possibly stage an attack.
|
||||
|
||||
### Review of Existing PoW Algorithms
|
||||
|
||||
#### SHA256
|
||||
* Potential ASIC efficiency gain ~ 1000X
|
||||
|
||||
The SHA algorithm is a sequence of simple math operations - additions, logical ops, and rotates.
|
||||
|
||||
To process a single op on a CPU or GPU requires fetching and decoding an instruction, reading data from a register file, executing the instruction, and then writing the result back to a register file. This takes significant time and power.
|
||||
|
||||
A single op implemented in an ASIC takes a handful of transistors and wires. This means every individual op takes negligible power, area, or time. A hashing core is built by laying out the sequence of required ops.
|
||||
|
||||
The hashing core can execute the required sequence of ops in much less time, and using less power or area, than doing the same sequence on a CPU or GPU. A bitcoin ASIC consists of a number of identical hashing cores and some minimal off-chip communication.
|
||||
|
||||
#### Scrypt and NeoScrypt
|
||||
* Potential ASIC efficiency gain ~ 1000X
|
||||
|
||||
Scrypt and NeoScrypt are similar to SHA in the arithmetic and bitwise operations used. Unfortunately, popular coins such as Litecoin only use a scratchpad size between 32kb and 128kb for their PoW mining algorithm. This scratch pad is small enough to trivially fit on an ASIC next to the math core. The implementation of the math core would be very similar to SHA, with similar efficiency gains.
|
||||
|
||||
#### X11 and X16R
|
||||
* Potential ASIC efficiency gain ~ 1000X
|
||||
|
||||
X11 (and similar X##) require an ASIC that has 11 unique hashing cores pipelined in a fixed sequence. Each individual hashing core would have similar efficiency to an individual SHA core, so the overall design will have the same efficiency gains.
|
||||
|
||||
X16R requires the multiple hashing cores to interact through a simple sequencing state machine. Each individual core will have similar efficiency gains and the sequencing logic will take minimal power, area, or time.
|
||||
|
||||
The Baikal BK-X is an existing ASIC with multiple hashing cores and a programmable sequencer. It has been upgraded to enable new algorithms that sequence the hashes in different orders.
|
||||
|
||||
#### Equihash
|
||||
* Potential ASIC efficiency gain ~ 100X
|
||||
|
||||
The ~150mb of state is large but possible on an ASIC. The binning, sorting, and comparing of bit strings could be implemented on an ASIC at extremely high speed.
|
||||
|
||||
#### Cuckoo Cycle
|
||||
* Potential ASIC efficiency gain ~ 100X
|
||||
|
||||
The amount of state required on-chip is not clear as there are Time/Memory Tradeoff attacks. A specialized graph traversal core would have similar efficiency gains to a SHA compute core.
|
||||
|
||||
#### CryptoNight
|
||||
* Potential ASIC efficiency gain ~ 50X
|
||||
|
||||
Compared to Scrypt, CryptoNight does much less compute and requires a full 2mb of scratch pad (there is no known Time/Memory Tradeoff attack). The large scratch pad will dominate the ASIC implementation and limit the number of hashing cores, limiting the absolute performance of the ASIC. An ASIC will consist almost entirely of just on-die SRAM.
|
||||
|
||||
#### Ethash
|
||||
* Potential ASIC efficiency gain ~ 2X
|
||||
|
||||
Ethash requires external memory due to the large size of the DAG. However that is all that it requires - there is minimal compute that is done on the result loaded from memory. As a result a custom ASIC could remove most of the complexity, and power, of a GPU and be just a memory interface connected to a small compute engine.
|
||||
|
||||
## Specification
|
||||
|
||||
ProgPoW is based on Ethash and follows the same general structure. The algorithm has five main changes from Ethash, each tuned for commodity GPUs while minimizing the possible advantage of a specialized ASIC.
|
||||
|
||||
The name of the algorithm comes from the fact that the inner loop between global memory accesses is a randomly generated program based on the block number. The random program is designed to both run efficiently on commodity GPUs and also cover most of the GPU's functionality. The random program sequence prevents the creation of a fixed pipeline implementation as seen in a specialized ASIC. The access size has also been tweaked to match contemporary GPUs.
|
||||
|
||||
In contrast to Ethash, the changes detailed below make ProgPoW dependent on the core compute capabilities in addition to memory bandwidth and size.
|
||||
|
||||
**Changes keccak_f1600 (with 64-bit words) to keccak_f800 (with 32-bit words).**
|
||||
|
||||
*On 64-bit architectures f1600 processes twice as many bits as f800 in roughly the same time. As GPUs are natively 32-bit architectures, f1600 takes twice as long as f800. ProgPow doesn’t require all the bits f1600 can consume, thus reducing the size reduces the optimization opportunity for a specialized ASIC.*
|
||||
|
||||
**Increases mix state.**
|
||||
|
||||
*A significant part of a GPU’s area, power, and complexity is the large register file. A large mix state ensures that a specialized ASIC would need to implement similar state storage, limiting any advantage.*
|
||||
|
||||
**Adds a random sequence of math in the main loop.**
|
||||
|
||||
*The random math changes every 50 blocks to amortize compilation overhead. Having a random sequence of math that reads and writes random locations within the state ensures that the ASIC executing the algorithm is fully programmable. There is no possibility to create an ASIC with a fixed pipeline that is much faster or lower power.*
|
||||
|
||||
**Adds reads from a small, low-latency cache that supports random addresses.**
|
||||
|
||||
*Another significant part of a GPU’s area, power, and complexity is the memory hierarchy. Adding cached reads makes use of this hierarchy and ensures that a specialized ASIC also implements a similar hierarchy, preventing power or area savings.*
|
||||
|
||||
**Increases the DRAM read from 128 bytes to 256 bytes.**
|
||||
|
||||
*The DRAM read from the DAG is the same as Ethash’s, but with the size increased to `256 bytes`. This better matches the workloads seen on commodity GPUs, preventing a specialized ASIC from being able to gain performance by optimizing the memory controller for abnormally small accesses.*
|
||||
|
||||
The DAG file is generated according to traditional Ethash specifications.
|
||||
The DAG is generated exactly as in Ethash. All the parameters (ephoch length, DAG size, etc) are unchanged. See the original [Ethash](https://github.com/ethereum/wiki/wiki/Ethash) spec for details on generating the DAG.
|
||||
|
||||
ProgPoW can be tuned using the following parameters. The proposed settings have been tuned for a range of existing, commodity GPUs:
|
||||
* `PROGPOW_PERIOD`: Number of blocks before changing the random program
|
||||
* `PROGPOW_LANES`: The number of parallel lanes that coordinate to calculate a single hash instance
|
||||
* `PROGPOW_REGS`: The register file usage size
|
||||
* `PROGPOW_DAG_LOADS`: Number of uint32 loads from the DAG per lane
|
||||
* `PROGPOW_CACHE_BYTES`: The size of the cache
|
||||
* `PROGPOW_CNT_DAG`: The number of DAG accesses, defined as the outer loop of the algorithm (64 is the same as ethash)
|
||||
* `PROGPOW_CNT_CACHE`: The number of cache accesses per loop
|
||||
* `PROGPOW_CNT_MATH`: The number of math operations per loop
|
||||
|
||||
* `PROGPOW_PERIOD`: Number of blocks before changing the random program; default is `50`.
|
||||
* `PROGPOW_LANES`: The number of parallel lanes that coordinate to calculate a single hash instance; default is `16`.
|
||||
* `PROGPOW_REGS`: The register file usage size; default is `32`.
|
||||
* `PROGPOW_DAG_LOADS`: Number of uint32 loads from the DAG per lane; default is `4`;
|
||||
* `PROGPOW_CACHE_BYTES`: The size of the cache; default is `16 x 1024`.
|
||||
* `PROGPOW_CNT_DAG`: The number of DAG accesses, defined as the outer loop of the algorithm; default is `64` (same as Ethash).
|
||||
* `PROGPOW_CNT_CACHE`: The number of cache accesses per loop; default is `12`.
|
||||
* `PROGPOW_CNT_MATH`: The number of math operations per loop; default is `20`.
|
||||
The value of these parameters has been tweaked between version 0.9.2 (live on the gangnum testnet) and 0.9.3 (proposed for Ethereum adoption). See [this medium post](https://medium.com/@ifdefelse/progpow-progress-da5bb31a651b) for details.
|
||||
|
||||
The random program changes every `PROGPOW_PERIOD` blocks (default `50`, roughly 12.5 minutes) to ensure the hardware executing the algorithm is fully programmable. If the program only changed every DAG epoch (roughly 5 days) certain miners could have time to develop hand-optimized versions of the random sequence, giving them an undue advantage.
|
||||
| Parameter | 0.9.2 | 0.9.3 |
|
||||
|-----------------------|-----------|-----------|
|
||||
| `PROGPOW_PERIOD` | `50` | `10` |
|
||||
| `PROGPOW_LANES` | `16` | `16` |
|
||||
| `PROGPOW_REGS` | `32` | `32` |
|
||||
| `PROGPOW_DAG_LOADS` | `4` | `4` |
|
||||
| `PROGPOW_CACHE_BYTES` | `16x1024` | `16x1024` |
|
||||
| `PROGPOW_CNT_DAG` | `64` | `64` |
|
||||
| `PROGPOW_CNT_CACHE` | `12` | `11` |
|
||||
| `PROGPOW_CNT_MATH` | `20` | `18` |
|
||||
|
||||
ProgPoW uses **FNV1a** for merging data. The existing Ethash uses FNV1 for merging, but FNV1a provides better distribution properties.
|
||||
|
||||
The random program changes every `PROGPOW_PERIOD` blocks to ensure the hardware executing the algorithm is fully programmable. If the program only changed every DAG epoch (roughly 5 days) certain miners could have time to develop hand-optimized versions of the random sequence, giving them an undue advantage.
|
||||
|
||||
Sample code is written in C++, this should be kept in mind when evaluating the code in the specification.
|
||||
|
||||
All numerics are computed using unsinged 32 bit integers. Any overflows are trimmed off before proceeding to the next computation. Languages that use numerics not fixed to bit lenghts (such as Python and JavaScript) or that only use signed integers (such as Java) will need to keep their languages' quirks in mind. The extensive use of 32 bit data values aligns with modern GPUs internal data architectures.
|
||||
|
||||
ProgPoW uses a 32-bit variant of **FNV1a** for merging data. The existing Ethash uses a similar vaiant of FNV1 for merging, but FNV1a provides better distribution properties.
|
||||
|
||||
Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#fnv1a).
|
||||
|
||||
```cpp
|
||||
const uint32_t FNV_PRIME = 0x1000193;
|
||||
const uint32_t FNV_OFFSET_BASIS = 0x811c9dc5;
|
||||
|
||||
uint32_t fnv1a(uint32_t h, uint32_t d)
|
||||
{
|
||||
return (h ^ d) * FNV_PRIME;
|
||||
}
|
||||
```
|
||||
|
||||
ProgPow uses [KISS99](https://en.wikipedia.org/wiki/KISS_(algorithm)) for random number generation. This is the simplest (fewest instruction) random generator that passes the TestU01 statistical test suite. A more complex random number generator like Mersenne Twister can be efficiently implemented on a specialized ASIC, providing an opportunity for efficiency gains.
|
||||
|
||||
Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#kiss99).
|
||||
|
||||
```cpp
|
||||
|
||||
uint32_t fnv1a(uint32_t &h, uint32_t d)
|
||||
{
|
||||
return h = (h ^ d) * 0x1000193;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t z, w, jsr, jcong;
|
||||
} kiss99_t;
|
||||
|
@ -105,7 +175,9 @@ uint32_t kiss99(kiss99_t &st)
|
|||
}
|
||||
```
|
||||
|
||||
The `LANES*REGS` of mix data is initialized from the hash’s seed.
|
||||
The `fill_mix` function populates an array of `int32` values used by each lane in the hash calculations.
|
||||
|
||||
Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#fill_mix).
|
||||
|
||||
```cpp
|
||||
void fill_mix(
|
||||
|
@ -116,26 +188,32 @@ void fill_mix(
|
|||
{
|
||||
// Use FNV to expand the per-warp seed to per-lane
|
||||
// Use KISS to expand the per-lane seed to fill mix
|
||||
uint32_t fnv_hash = 0x811c9dc5;
|
||||
kiss99_t st;
|
||||
st.z = fnv1a(fnv_hash, seed);
|
||||
st.w = fnv1a(fnv_hash, seed >> 32);
|
||||
st.jsr = fnv1a(fnv_hash, lane_id);
|
||||
st.jcong = fnv1a(fnv_hash, lane_id);
|
||||
st.z = fnv1a(FNV_OFFSET_BASIS, seed);
|
||||
st.w = fnv1a(st.z, seed >> 32);
|
||||
st.jsr = fnv1a(st.w, lane_id);
|
||||
st.jcong = fnv1a(st.jsr, lane_id);
|
||||
for (int i = 0; i < PROGPOW_REGS; i++)
|
||||
mix[i] = kiss99(st);
|
||||
}
|
||||
```
|
||||
|
||||
Like ethash Keccak is used to seed the sequence per-nonce and to produce the final result. The keccak-f800 variant is used as the 32-bit word size matches the native word size of modern GPUs. The implementation is a variant of SHAKE with width=800, bitrate=576, capacity=224, output=256, and no padding. The result of keccak is treated as a 256-bit big-endian number - that is result byte 0 is the MSB of the value.
|
||||
Like Ethash Keccak is used to seed the sequence per-nonce and to produce the final result. The keccak-f800 variant is used as the 32-bit word size matches the native word size of modern GPUs. The implementation is a variant of SHAKE with width=800, bitrate=576, capacity=224, output=256, and no padding. The result of keccak is treated as a 256-bit big-endian number - that is result byte 0 is the MSB of the value.
|
||||
|
||||
As with Ethash the input and output of the keccak function are fixed and relatively small. This means only a single "absorb" and "squeeze" phase are required. For a pseudo-code imenentation of the `keccak_f800_round` function see the `Round[b](A,RC)` function in the "Pseudo-code description of the permutations" section of the [official Keccak specs](https://keccak.team/keccak_specs_summary.html).
|
||||
|
||||
Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#keccak_f800_progpow).
|
||||
|
||||
```cpp
|
||||
hash32_t keccak_f800_progpow(hash32_t header, uint64_t seed, hash32_t digest)
|
||||
{
|
||||
uint32_t st[25];
|
||||
|
||||
// Initialization
|
||||
for (int i = 0; i < 25; i++)
|
||||
st[i] = 0;
|
||||
|
||||
// Absorb phase for fixed 18 words of input
|
||||
for (int i = 0; i < 8; i++)
|
||||
st[i] = header.uint32s[i];
|
||||
st[8] = seed;
|
||||
|
@ -143,29 +221,206 @@ hash32_t keccak_f800_progpow(hash32_t header, uint64_t seed, hash32_t digest)
|
|||
for (int i = 0; i < 8; i++)
|
||||
st[10+i] = digest.uint32s[i];
|
||||
|
||||
// keccak_f800 call for the single absorb pass
|
||||
for (int r = 0; r < 22; r++)
|
||||
keccak_f800_round(st, r);
|
||||
|
||||
// Squeeze phase for fixed 8 words of output
|
||||
hash32_t ret;
|
||||
for (int i=0; i<8; i++)
|
||||
ret.uint32s[i] = st[i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
The inner loop uses FNV and KISS99 to generate a random sequence from the `prog_seed`. This random sequence determines which mix state is accessed and what random math is performed.
|
||||
|
||||
Since the `prog_seed` changes only once per `PROGPOW_PERIOD` it is expected that while mining `progPowLoop` will be evaluated on the CPU to generate source code for that period's sequence. The source code will be compiled on the CPU before running on the GPU.
|
||||
|
||||
Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#progPowInit).
|
||||
|
||||
```cpp
|
||||
kiss99_t progPowInit(uint64_t prog_seed, int mix_seq_dst[PROGPOW_REGS], int mix_seq_src[PROGPOW_REGS])
|
||||
{
|
||||
kiss99_t prog_rnd;
|
||||
prog_rnd.z = fnv1a(FNV_OFFSET_BASIS, prog_seed);
|
||||
prog_rnd.w = fnv1a(prog_rnd.z, prog_seed >> 32);
|
||||
prog_rnd.jsr = fnv1a(prog_rnd.w, prog_seed);
|
||||
prog_rnd.jcong = fnv1a(prog_rnd.jsr, prog_seed >> 32);
|
||||
// Create a random sequence of mix destinations for merge() and mix sources for cache reads
|
||||
// guarantees every destination merged once
|
||||
// guarantees no duplicate cache reads, which could be optimized away
|
||||
// Uses Fisher-Yates shuffle
|
||||
for (int i = 0; i < PROGPOW_REGS; i++)
|
||||
{
|
||||
mix_seq_dst[i] = i;
|
||||
mix_seq_src[i] = i;
|
||||
}
|
||||
for (int i = PROGPOW_REGS - 1; i > 0; i--)
|
||||
{
|
||||
int j;
|
||||
j = kiss99(prog_rnd) % (i + 1);
|
||||
swap(mix_seq_dst[i], mix_seq_dst[j]);
|
||||
j = kiss99(prog_rnd) % (i + 1);
|
||||
swap(mix_seq_src[i], mix_seq_src[j]);
|
||||
}
|
||||
return prog_rnd;
|
||||
}
|
||||
```
|
||||
|
||||
The math operations that merges values into the mix data are ones chosen to maintain entropy.
|
||||
|
||||
Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#math).
|
||||
|
||||
```cpp
|
||||
// Merge new data from b into the value in a
|
||||
// Assuming A has high entropy only do ops that retain entropy
|
||||
// even if B is low entropy
|
||||
// (IE don't do A&B)
|
||||
uint32_t merge(uint32_t a, uint32_t b, uint32_t r)
|
||||
{
|
||||
switch (r % 4)
|
||||
{
|
||||
case 0: return (a * 33) + b;
|
||||
case 1: return (a ^ b) * 33;
|
||||
// prevent rotate by 0 which is a NOP
|
||||
case 2: return ROTL32(a, ((r >> 16) % 31) + 1) ^ b;
|
||||
case 3: return ROTR32(a, ((r >> 16) % 31) + 1) ^ b;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The math operations chosen for the random math are ones that are easy to implement in CUDA and OpenCL, the two main programming languages for commodity GPUs. The [mul_hi](https://www.khronos.org/registry/OpenCL/sdk/1.1/docs/man/xhtml/mul_hi.html), [min](https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/integerMax.html), [clz](https://www.khronos.org/registry/OpenCL/sdk/1.1/docs/man/xhtml/clz.html), and [popcount](https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/popcount.html) functions match the corresponding OpenCL functions. ROTL32 matches the OpenCL [rotate](https://www.khronos.org/registry/OpenCL/sdk/1.0/docs/man/xhtml/rotate.html) function. ROTR32 is rotate right, which is equivalent to `rotate(i, 32-v)`.
|
||||
|
||||
Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#math).
|
||||
|
||||
```cpp
|
||||
// Random math between two input values
|
||||
uint32_t math(uint32_t a, uint32_t b, uint32_t r)
|
||||
{
|
||||
switch (r % 11)
|
||||
{
|
||||
case 0: return a + b;
|
||||
case 1: return a * b;
|
||||
case 2: return mul_hi(a, b);
|
||||
case 3: return min(a, b);
|
||||
case 4: return ROTL32(a, b);
|
||||
case 5: return ROTR32(a, b);
|
||||
case 6: return a & b;
|
||||
case 7: return a | b;
|
||||
case 8: return a ^ b;
|
||||
case 9: return clz(a) + clz(b);
|
||||
case 10: return popcount(a) + popcount(b);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
The flow of the inner loop is:
|
||||
* Lane `(loop % LANES)` is chosen as the leader for that loop iteration
|
||||
* The leader's `mix[0]` value modulo the number of 256-byte DAG entries is is used to select where to read from the full DAG
|
||||
* Each lane reads `DAG_LOADS` sequential words, using `(lane ^ loop) % LANES` as the starting offset within the entry.
|
||||
* The random sequence of math and cache accesses is performed
|
||||
* The DAG data read at the start of the loop is merged at the end of the loop
|
||||
|
||||
`prog_seed` and `loop` come from the outer loop, corresponding to the current program seed (which is block_number/PROGPOW_PERIOD) and the loop iteration number. `mix` is the state array, initially filled by `fill_mix`. `dag` is the bytes of the Ethash DAG grouped into 32 bit unsigned ints in litte-endian format. On little-endian architectures this is just a normal int32 pointer to the existing DAG.
|
||||
|
||||
`DAG_BYTES` is set to the number of bytes in the current DAG, which is generated identically to the existing Ethash algorithm.
|
||||
|
||||
Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#progPowLoop).
|
||||
|
||||
```cpp
|
||||
void progPowLoop(
|
||||
const uint64_t prog_seed,
|
||||
const uint32_t loop,
|
||||
uint32_t mix[PROGPOW_LANES][PROGPOW_REGS],
|
||||
const uint32_t *dag)
|
||||
{
|
||||
// dag_entry holds the 256 bytes of data loaded from the DAG
|
||||
uint32_t dag_entry[PROGPOW_LANES][PROGPOW_DAG_LOADS];
|
||||
// On each loop iteration rotate which lane is the source of the DAG address.
|
||||
// The source lane's mix[0] value is used to ensure the last loop's DAG data feeds into this loop's address.
|
||||
// dag_addr_base is which 256-byte entry within the DAG will be accessed
|
||||
uint32_t dag_addr_base = mix[loop%PROGPOW_LANES][0] %
|
||||
(DAG_BYTES / (PROGPOW_LANES*PROGPOW_DAG_LOADS*sizeof(uint32_t)));
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
{
|
||||
// Lanes access DAG_LOADS sequential words from the dag entry
|
||||
// Shuffle which portion of the entry each lane accesses each iteration by XORing lane and loop.
|
||||
// This prevents multi-chip ASICs from each storing just a portion of the DAG
|
||||
size_t dag_addr_lane = dag_addr_base * PROGPOW_LANES + (l ^ loop) % PROGPOW_LANES;
|
||||
for (int i = 0; i < PROGPOW_DAG_LOADS; i++)
|
||||
dag_entry[l][i] = dag[dag_addr_lane * PROGPOW_DAG_LOADS + i];
|
||||
}
|
||||
|
||||
// Initialize the program seed and sequences
|
||||
// When mining these are evaluated on the CPU and compiled away
|
||||
int mix_seq_dst[PROGPOW_REGS];
|
||||
int mix_seq_src[PROGPOW_REGS];
|
||||
int mix_seq_dst_cnt = 0;
|
||||
int mix_seq_src_cnt = 0;
|
||||
kiss99_t prog_rnd = progPowInit(prog_seed, mix_seq_dst, mix_seq_src);
|
||||
|
||||
int max_i = max(PROGPOW_CNT_CACHE, PROGPOW_CNT_MATH);
|
||||
for (int i = 0; i < max_i; i++)
|
||||
{
|
||||
if (i < PROGPOW_CNT_CACHE)
|
||||
{
|
||||
// Cached memory access
|
||||
// lanes access random 32-bit locations within the first portion of the DAG
|
||||
int src = mix_seq_src[(mix_seq_src_cnt++)%PROGPOW_REGS];
|
||||
int dst = mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS];
|
||||
int sel = kiss99(prog_rnd);
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
{
|
||||
uint32_t offset = mix[l][src] % (PROGPOW_CACHE_BYTES/sizeof(uint32_t));
|
||||
mix[l][dst] = merge(mix[l][dst], dag[offset], sel);
|
||||
}
|
||||
}
|
||||
if (i < PROGPOW_CNT_MATH)
|
||||
{
|
||||
// Random Math
|
||||
// Generate 2 unique sources
|
||||
int src_rnd = kiss99(prog_rnd) % (PROGPOW_REGS * (PROGPOW_REGS-1));
|
||||
int src1 = src_rnd % PROGPOW_REGS; // 0 <= src1 < PROGPOW_REGS
|
||||
int src2 = src_rnd / PROGPOW_REGS; // 0 <= src2 < PROGPOW_REGS - 1
|
||||
if (src2 >= src1) ++src2; // src2 is now any reg other than src1
|
||||
int sel1 = kiss99(prog_rnd);
|
||||
int dst = mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS];
|
||||
int sel2 = kiss99(prog_rnd);
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
{
|
||||
uint32_t data = math(mix[l][src1], mix[l][src2], sel1);
|
||||
mix[l][dst] = merge(mix[l][dst], data, sel2);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Consume the global load data at the very end of the loop to allow full latency hiding
|
||||
// Always merge into mix[0] to feed the offset calculation
|
||||
for (int i = 0; i < PROGPOW_DAG_LOADS; i++)
|
||||
{
|
||||
int dst = (i==0) ? 0 : mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS];
|
||||
int sel = kiss99(prog_rnd);
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
mix[l][dst] = merge(mix[l][dst], dag_entry[l][i], sel);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The flow of the overall algorithm is:
|
||||
* A keccak hash of the header + nonce to create a seed
|
||||
* Use the seed to generate initial mix data
|
||||
* Loop multiple times, each time hashing random loads and random math into the mix data
|
||||
* Hash all the mix data into a single 256-bit value
|
||||
* A final keccak hash that is compared against the target
|
||||
* A final keccak hash is computed
|
||||
* When mining this final value is compared against a `hash32_t` target
|
||||
|
||||
```cpp
|
||||
bool progpow_search(
|
||||
hash32_t progPowHash(
|
||||
const uint64_t prog_seed, // value is (block_number/PROGPOW_PERIOD)
|
||||
const uint64_t nonce,
|
||||
const hash32_t header,
|
||||
const hash32_t target, // miner can use a uint64_t target, doesn't need the full 256 bit target
|
||||
const uint32_t *dag // gigabyte DAG located in framebuffer - the first portion gets cached
|
||||
)
|
||||
{
|
||||
|
@ -191,171 +446,21 @@ bool progpow_search(
|
|||
uint32_t digest_lane[PROGPOW_LANES];
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
{
|
||||
digest_lane[l] = 0x811c9dc5
|
||||
digest_lane[l] = FNV_OFFSET_BASIS
|
||||
for (int i = 0; i < PROGPOW_REGS; i++)
|
||||
fnv1a(digest_lane[l], mix[l][i]);
|
||||
digest_lane[l] = fnv1a(digest_lane[l], mix[l][i]);
|
||||
}
|
||||
// Reduce all lanes to a single 256-bit digest
|
||||
for (int i = 0; i < 8; i++)
|
||||
digest.uint32s[i] = 0x811c9dc5;
|
||||
digest.uint32s[i] = FNV_OFFSET_BASIS;
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
fnv1a(digest.uint32s[l%8], digest_lane[l])
|
||||
digest.uint32s[l%8] = fnv1a(digest.uint32s[l%8], digest_lane[l])
|
||||
|
||||
// keccak(header .. keccak(header..nonce) .. digest);
|
||||
return (keccak_f800_progpow(header, seed, digest) <= target);
|
||||
keccak_f800_progpow(header, seed, digest);
|
||||
}
|
||||
```
|
||||
|
||||
The inner loop uses FNV and KISS99 to generate a random sequence from the `prog_seed`. This random sequence determines which mix state is accessed and what random math is performed. Since the `prog_seed` changes relatively infrequently it is expected that `progPowLoop` will be compiled while mining instead of interpreted on the fly.
|
||||
|
||||
```cpp
|
||||
kiss99_t progPowInit(uint64_t prog_seed, int mix_seq_dst[PROGPOW_REGS], int mix_seq_cache[PROGPOW_REGS])
|
||||
{
|
||||
kiss99_t prog_rnd;
|
||||
uint32_t fnv_hash = 0x811c9dc5;
|
||||
prog_rnd.z = fnv1a(fnv_hash, prog_seed);
|
||||
prog_rnd.w = fnv1a(fnv_hash, prog_seed >> 32);
|
||||
prog_rnd.jsr = fnv1a(fnv_hash, prog_seed);
|
||||
prog_rnd.jcong = fnv1a(fnv_hash, prog_seed >> 32);
|
||||
// Create a random sequence of mix destinations for merge() and mix sources for cache reads
|
||||
// guarantees every destination merged once
|
||||
// guarantees no duplicate cache reads, which could be optimized away
|
||||
// Uses Fisher-Yates shuffle
|
||||
for (int i = 0; i < PROGPOW_REGS; i++)
|
||||
{
|
||||
mix_seq_dst[i] = i;
|
||||
mix_seq_cache[i] = i;
|
||||
}
|
||||
for (int i = PROGPOW_REGS - 1; i > 0; i--)
|
||||
{
|
||||
int j;
|
||||
j = kiss99(prog_rnd) % (i + 1);
|
||||
swap(mix_seq_dst[i], mix_seq_dst[j]);
|
||||
j = kiss99(prog_rnd) % (i + 1);
|
||||
swap(mix_seq_cache[i], mix_seq_cache[j]);
|
||||
}
|
||||
return prog_rnd;
|
||||
}
|
||||
```
|
||||
|
||||
The math operations that merge values into the mix data are ones chosen to maintain entropy.
|
||||
|
||||
```cpp
|
||||
// Merge new data from b into the value in a
|
||||
// Assuming A has high entropy only do ops that retain entropy
|
||||
// even if B is low entropy
|
||||
// (IE don't do A&B)
|
||||
void merge(uint32_t &a, uint32_t b, uint32_t r)
|
||||
{
|
||||
switch (r % 4)
|
||||
{
|
||||
case 0: a = (a * 33) + b; break;
|
||||
case 1: a = (a ^ b) * 33; break;
|
||||
// prevent rotate by 0 which is a NOP
|
||||
case 2: a = ROTL32(a, ((r >> 16) % 31) + 1) ^ b; break;
|
||||
case 3: a = ROTR32(a, ((r >> 16) % 31) + 1) ^ b; break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The math operations chosen for the random math are ones that are easy to implement in CUDA and OpenCL, the two main programming languages for commodity GPUs.
|
||||
|
||||
```cpp
|
||||
// Random math between two input values
|
||||
uint32_t math(uint32_t a, uint32_t b, uint32_t r)
|
||||
{
|
||||
switch (r % 11)
|
||||
{
|
||||
case 0: return a + b;
|
||||
case 1: return a * b;
|
||||
case 2: return mul_hi(a, b);
|
||||
case 3: return min(a, b);
|
||||
case 4: return ROTL32(a, b);
|
||||
case 5: return ROTR32(a, b);
|
||||
case 6: return a & b;
|
||||
case 7: return a | b;
|
||||
case 8: return a ^ b;
|
||||
case 9: return clz(a) + clz(b);
|
||||
case 10: return popcount(a) + popcount(b);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The main loop:
|
||||
|
||||
```cpp
|
||||
void progPowLoop(
|
||||
const uint64_t prog_seed,
|
||||
const uint32_t loop,
|
||||
uint32_t mix[PROGPOW_LANES][PROGPOW_REGS],
|
||||
const uint32_t *dag)
|
||||
{
|
||||
// All lanes share a base address for the global load
|
||||
// Global offset uses mix[0] to guarantee it depends on the load result
|
||||
uint32_t data_g[PROGPOW_LANES][PROGPOW_DAG_LOADS];
|
||||
uint32_t offset_g = mix[loop%PROGPOW_LANES][0] % (DAG_BYTES / (PROGPOW_LANES*PROGPOW_DAG_LOADS*sizeof(uint32_t)));
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
{
|
||||
// global load to the 256 byte DAG entry
|
||||
// every lane can access every part of the entry
|
||||
uint32_t offset_l = offset_g * PROGPOW_LANES + (l ^ loop) % PROGPOW_LANES;
|
||||
for (int i = 0; i < PROGPOW_DAG_LOADS; i++)
|
||||
data_g[l][i] = dag[offset_l * PROGPOW_DAG_LOADS + i];
|
||||
}
|
||||
|
||||
// Initialize the program seed and sequences
|
||||
// When mining these are evaluated on the CPU and compiled away
|
||||
int mix_seq_dst[PROGPOW_REGS];
|
||||
int mix_seq_src[PROGPOW_REGS];
|
||||
int mix_seq_dst_cnt = 0;
|
||||
int mix_seq_src_cnt = 0;
|
||||
kiss99_t prog_rnd = progPowInit(prog_seed, mix_seq_dst, mix_seq_src);
|
||||
|
||||
int max_i = max(PROGPOW_CNT_CACHE, PROGPOW_CNT_MATH);
|
||||
for (int i = 0; i < max_i; i++)
|
||||
{
|
||||
if (i < PROGPOW_CNT_CACHE)
|
||||
{
|
||||
// Cached memory access
|
||||
// lanes access random 32-bit locations within the first portion of the DAG
|
||||
int src = mix_seq_src[(mix_seq_src_cnt++)%PROGPOW_REGS];
|
||||
int dst = mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS];
|
||||
int sel = kiss99(prog_rnd);
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
{
|
||||
uint32_t offset = mix[l][src] % (PROGPOW_CACHE_BYTES/sizeof(uint32_t));
|
||||
merge(mix[l][dst], dag[offset], sel);
|
||||
}
|
||||
}
|
||||
if (i < PROGPOW_CNT_MATH)
|
||||
{
|
||||
// Random Math
|
||||
// Generate 2 unique sources
|
||||
int src_rnd = kiss99(prog_rnd) % (PROGPOW_REGS * (PROGPOW_REGS-1));
|
||||
int src1 = src_rnd % PROGPOW_REGS; // 0 <= src1 < PROGPOW_REGS
|
||||
int src2 = src_rnd / PROGPOW_REGS; // 0 <= src2 < PROGPOW_REGS - 1
|
||||
if (src2 >= src1) ++src2; // src2 is now any reg other than src
|
||||
int sel1 = kiss99(prog_rnd);
|
||||
int dst = mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS];
|
||||
int sel2 = kiss99(prog_rnd);
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
{
|
||||
uint32_t data = math(mix[l][src1], mix[l][src2], sel1);
|
||||
merge(mix[l][dst], data, sel2);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Consume the global load data at the very end of the loop to allow full latency hiding
|
||||
// Always merge into mix[0] to feed the offset calculation
|
||||
for (int i = 0; i < PROGPOW_DAG_LOADS; i++)
|
||||
{
|
||||
int dst = (i==0) ? 0 : mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS];
|
||||
int sel = kiss99(prog_rnd);
|
||||
for (int l = 0; l < PROGPOW_LANES; l++)
|
||||
merge(mix[l][dst], data_g[l][i], sel);
|
||||
}
|
||||
}
|
||||
```
|
||||
## Rationale
|
||||
|
||||
ProgPoW utilizes almost all parts of a commodity GPU, excluding:
|
||||
|
@ -371,10 +476,24 @@ Since the GPU is almost fully utilized, there’s little opportunity for specia
|
|||
|
||||
This algorithm is not backwards compatible with the existing Ethash, and will require a fork for adoption. Furthermore, the network hashrate will halve since twice as much memory is loaded per hash.
|
||||
|
||||
## Test Cases
|
||||
|
||||
The algorithm run on block 30,000 produces the following digest and result:
|
||||
```
|
||||
header ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff
|
||||
nonce 123456789abcdef0
|
||||
|
||||
digest: 11f19805c58ab46610ff9c719dcf0a5f18fa2f1605798eef770c47219274767d
|
||||
result: 5b7ccd472dbefdd95b895cac8ece67ff0deb5a6bd2ecc6e162383d00c3728ece
|
||||
```
|
||||
|
||||
Additional test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#progPowHash).
|
||||
|
||||
## Implementation
|
||||
|
||||
Please refer to the official code located at [ProgPOW](https://github.com/ifdefelse/ProgPOW) for the full code, implemented in the standard ethminer.
|
||||
The reference ProgPoW mining implementation located at [ProgPOW](https://github.com/ifdefelse/ProgPOW) is a derivative of ethminer so retains the GPL license.
|
||||
## License and Copyright
|
||||
|
||||
## Copyright
|
||||
The ProgPoW algorithm and this specification are a new work. Copyright and related rights are waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
The reference ProgPoW mining implementation located at [ProgPOW](https://github.com/ifdefelse/ProgPOW) is a derivative of ethminer so retains the GPL license.
|
|
@ -3,9 +3,10 @@ eip: 1066
|
|||
title: Status Codes
|
||||
author: Brooklyn Zelenka (@expede), Tom Carchrae (@carchrae), Gleb Naumenko (@naumenkogs)
|
||||
discussions-to: https://ethereum-magicians.org/t/erc-1066-ethereum-status-codes-esc/
|
||||
status: Draft
|
||||
status: Last Call
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
review-period-end: 2019-02-25
|
||||
created: 2018-05-05
|
||||
version: 1.0.0
|
||||
---
|
||||
|
@ -46,7 +47,7 @@ At time of writing, other than stepping through EVM execution and inspecting mem
|
|||
|
||||
Having a fixed set of codes also makes it possible to write common helper functions to react in common ways to certain signals. This can live off- or on-chain library, lowering the overhead in building smart contracts, and helping raise code quality with trusted shared components.
|
||||
|
||||
We also see a desire for this [in transactions](http://eips.ethereum.org/EIPS/eip-658), and there's no reason that these status codes couldn't be used by the EVM itself.
|
||||
We also see a desire for this [in transactions](https://eips.ethereum.org/EIPS/eip-658), and there's no reason that these status codes couldn't be used by the EVM itself.
|
||||
|
||||
### Smart Contract Autonomy
|
||||
|
||||
|
@ -229,7 +230,7 @@ Special token and financial concepts. Many related concepts are included in othe
|
|||
| `0x5C` | [reserved] |
|
||||
| `0x5D` | [reserved] |
|
||||
| `0x5E` | [reserved] |
|
||||
| `0x5F` | Token or Fiunancial Information |
|
||||
| `0x5F` | Token or Financial Information |
|
||||
|
||||
#### `0x6*` TBD
|
||||
|
||||
|
@ -351,7 +352,7 @@ Among other things, the meta code `0xFF` may be used to describe what the off-ch
|
|||
| `0x*C` | `0x0C` [reserved] | `0x1C` [reserved] | `0x2C` [reserved] | `0x3C` [reserved] | `0x4C` [reserved] | `0x5C` [reserved] | `0x6C` [reserved] | `0x7C` [reserved] | `0x8C` [reserved] | `0x9C` [reserved] | `0xAC` [reserved] | `0xBC` [reserved] | `0xCC` [reserved] | `0xDC` [reserved] | `0xEC` [reserved] | `0xFC` [reserved] |
|
||||
| `0x*D` | `0x0D` [reserved] | `0x1D` [reserved] | `0x2D` [reserved] | `0x3D` [reserved] | `0x4D` [reserved] | `0x5D` [reserved] | `0x6D` [reserved] | `0x7D` [reserved] | `0x8D` [reserved] | `0x9D` [reserved] | `0xAD` [reserved] | `0xBD` [reserved] | `0xCD` [reserved] | `0xDD` [reserved] | `0xED` [reserved] | `0xFD` [reserved] |
|
||||
| `0x*E` | `0x0E` [reserved] | `0x1E` [reserved] | `0x2E` [reserved] | `0x3E` [reserved] | `0x4E` [reserved] | `0x5E` [reserved] | `0x6E` [reserved] | `0x7E` [reserved] | `0x8E` [reserved] | `0x9E` [reserved] | `0xAE` [reserved] | `0xBE` [reserved] | `0xCE` [reserved] | `0xDE` [reserved] | `0xEE` [reserved] | `0xFE` [reserved] |
|
||||
| `0x*F` | `0x0F` Informational or Metadata | `0x1F` Permission Details or Control Conditions | `0x2F` Matching Meta or Info | `0x3F` Negotiation Rules or Participation Info | `0x4F` Availability Rules or Info (ex. time since or until) | `0x5F` Token or Fiunancial Information | `0x6F` [reserved] | `0x7F` [reserved] | `0x8F` [reserved] | `0x9F` [reserved] | `0xAF` App-Specific Meta or Info | `0xBF` [reserved] | `0xCF` [reserved] | `0xDF` [reserved] | `0xEF` Cryptography, ID, or Proof Metadata | `0xFF` Off-Chain Info or Meta |
|
||||
| `0x*F` | `0x0F` Informational or Metadata | `0x1F` Permission Details or Control Conditions | `0x2F` Matching Meta or Info | `0x3F` Negotiation Rules or Participation Info | `0x4F` Availability Rules or Info (ex. time since or until) | `0x5F` Token or Financial Information | `0x6F` [reserved] | `0x7F` [reserved] | `0x8F` [reserved] | `0x9F` [reserved] | `0xAF` App-Specific Meta or Info | `0xBF` [reserved] | `0xCF` [reserved] | `0xDF` [reserved] | `0xEF` Cryptography, ID, or Proof Metadata | `0xFF` Off-Chain Info or Meta |
|
||||
|
||||
### Example Function Change
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
eip: 1081
|
||||
Title: Standard Bounties
|
||||
Authors: Mark Beylin <mark.beylin@consensys.net>, Kevin Owocki <kevin.owocki@consensys.net>, Ricardo Guilherme Schmidt (@3esmit)
|
||||
Discussions-to: https://gitter.im/bounties-network/Lobby
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Category: ERC
|
||||
Created: 2018-05-14
|
||||
Requires: 20
|
||||
title: Standard Bounties
|
||||
author: Mark Beylin <mark.beylin@consensys.net>, Kevin Owocki <kevin.owocki@consensys.net>, Ricardo Guilherme Schmidt (@3esmit)
|
||||
discussions-to: https://gitter.im/bounties-network/Lobby
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
created: 2018-05-14
|
||||
requires: 20
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
|
|
|
@ -77,7 +77,7 @@ contracts.
|
|||
> **Note**
|
||||
>
|
||||
> A [hosted
|
||||
> version](http://ethpm.github.io/ethpm-spec) of this
|
||||
> version](https://ethpm.github.io/ethpm-spec) of this
|
||||
> specification is available via GitHub Pages. This EIP and the hosted
|
||||
> HTML document were both autogenerated from the same documentation
|
||||
> source.
|
||||
|
@ -174,7 +174,7 @@ name collisions with future versions of the specification.
|
|||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><p>See Also</p></td>
|
||||
<td><p>Formalized (<a href="http://json-schema.org">JSON-Schema</a>) version of this specification: <a href="https://github.com/ethpm/ethpm-spec/tree/v2.0.0/spec/package.spec.json">package.spec.json</a></p></td>
|
||||
<td><p>Formalized (<a href="https://json-schema.org">JSON-Schema</a>) version of this specification: <a href="https://github.com/ethpm/ethpm-spec/tree/v2.0.0/spec/package.spec.json">package.spec.json</a></p></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><p>Jump To</p></td>
|
||||
|
@ -286,7 +286,7 @@ be included in all Packages.
|
|||
|
||||
The `version` field declares the version number of this release. This
|
||||
value **must** be included in all Packages. This value **should**
|
||||
conform to the [semver](http://semver.org/) version
|
||||
conform to the [semver](https://semver.org/) version
|
||||
numbering specification.
|
||||
|
||||
<table>
|
||||
|
@ -1404,7 +1404,7 @@ The `name` field defines which compiler was used in compilation.
|
|||
The `version` field defines the version of the compiler. The field
|
||||
**should** be OS agnostic (OS not included in the string) and take the
|
||||
form of either the stable version in
|
||||
[semver](http://semver.org/) format or if built on a
|
||||
[semver](https://semver.org/) format or if built on a
|
||||
nightly should be denoted in the form of `<semver>-<commit-hash>` ex:
|
||||
`0.4.8-commit.60cc1668`.
|
||||
|
||||
|
@ -1435,7 +1435,7 @@ nightly should be denoted in the form of `<semver>-<commit-hash>` ex:
|
|||
The `settings` field defines any settings or configuration that was used
|
||||
in compilation. For the `"solc"` compiler, this **should** conform to
|
||||
the [Compiler Input and Output
|
||||
Description](http://solidity.readthedocs.io/en/latest/using-the-compiler.html#compiler-input-and-output-json-description).
|
||||
Description](https://solidity.readthedocs.io/en/latest/using-the-compiler.html#compiler-input-and-output-json-description).
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
|
@ -1848,7 +1848,7 @@ a supporting implementation.
|
|||
|
||||
- [Truffle](http://trufflesuite.com/)
|
||||
|
||||
- [Populus](http://populus.readthedocs.io/en/latest/)
|
||||
- [Populus](https://populus.readthedocs.io/en/latest/)
|
||||
|
||||
- [Embark](https://embark.status.im/)
|
||||
|
||||
|
|
211
EIPS/eip-1155.md
211
EIPS/eip-1155.md
|
@ -4,7 +4,8 @@ title: ERC-1155 Multi Token Standard
|
|||
author: Witek Radomski <witek@enjin.com>, Andrew Cooke <andrew@enjin.com>, Philippe Castonguay <pc@horizongames.net>, James Therien <james@enjin.com>, Eric Binet <eric@enjin.com>
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
status: Draft
|
||||
status: Last Call
|
||||
review-period-end: 2019-03-28
|
||||
created: 2018-06-17
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/1155
|
||||
requires: 165
|
||||
|
@ -16,7 +17,7 @@ A standard interface for contracts that manage multiple token types. A single de
|
|||
|
||||
## Abstract
|
||||
|
||||
This standard outlines a smart contract interface where one can represent any number of Fungible and Non-Fungible token types in a single contract. Existing standards such as ERC-20 require deployment of separate contracts per token type. The ERC-721 standard's Token ID is a single non-fungible index and the group of these non-fungibles is deployed as a single contract with settings for the entire collection. In contrast, the ERC-1155 Multi Token Standard allows for each Token ID to represent a new configurable token type, which may have its own metadata, supply and other attributes.
|
||||
This standard outlines a smart contract interface that can represent any number of Fungible and Non-Fungible token types. Existing standards such as ERC-20 require deployment of separate contracts per token type. The ERC-721 standard's Token ID is a single non-fungible index and the group of these non-fungibles is deployed as a single contract with settings for the entire collection. In contrast, the ERC-1155 Multi Token Standard allows for each Token ID to represent a new configurable token type, which may have its own metadata, supply and other attributes.
|
||||
|
||||
The `_id` parameter is contained in each function's parameters and indicates a specific token or token type in a transaction.
|
||||
|
||||
|
@ -26,37 +27,37 @@ Tokens standards like ERC-20 and ERC-721 require a separate contract to be deplo
|
|||
|
||||
New functionality is possible with this design, such as transferring multiple token types at once, saving on transaction costs. Trading (escrow / atomic swaps) of multiple tokens can be built on top of this standard and it removes the need to "approve" individual token contracts separately. It is also easy to describe and mix multiple fungible or non-fungible token types in a single contract.
|
||||
|
||||
# Specification
|
||||
## Specification
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
|
||||
|
||||
**Smart contracts implementing the ERC-1155 standard MUST implement the `ERC1155` and `ERC165` interfaces.**
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.5.2;
|
||||
pragma solidity ^0.5.7;
|
||||
|
||||
/**
|
||||
@title ERC-1155 Multi Token Standard
|
||||
@dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
|
||||
@dev See https://eips.ethereum.org/EIPS/eip-1155
|
||||
Note: The ERC-165 identifier for this interface is 0xd9b67a26.
|
||||
*/
|
||||
interface ERC1155 /* is ERC165 */ {
|
||||
/**
|
||||
@dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning.
|
||||
Operator will always be msg.sender.
|
||||
Either event from address `0x0` signifies a minting operation.
|
||||
An event to address `0x0` signifies a burning or melting operation.
|
||||
The total value transferred from address 0x0 minus the total value transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID.
|
||||
Operator MUST be msg.sender.
|
||||
When minting/creating tokens, the `_from` field MUST be set to `0x0`
|
||||
When burning/destroying tokens, the `_to` field MUST be set to `0x0`
|
||||
The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID.
|
||||
To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0.
|
||||
*/
|
||||
event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value);
|
||||
|
||||
/**
|
||||
@dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning.
|
||||
Operator will always be msg.sender.
|
||||
Either event from address `0x0` signifies a minting operation.
|
||||
An event to address `0x0` signifies a burning or melting operation.
|
||||
The total value transferred from address 0x0 minus the total value transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID.
|
||||
Operator MUST be msg.sender.
|
||||
When minting/creating tokens, the `_from` field MUST be set to `0x0`
|
||||
When burning/destroying tokens, the `_to` field MUST be set to `0x0`
|
||||
The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID.
|
||||
To broadcast the existence of multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0.
|
||||
*/
|
||||
event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values);
|
||||
|
@ -119,7 +120,7 @@ interface ERC1155 /* is ERC165 */ {
|
|||
@notice Get the balance of multiple account/token pairs
|
||||
@param _owners The addresses of the token holders
|
||||
@param _ids ID of the Tokens
|
||||
@return The _owner's balance of the Token types requested
|
||||
@return The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair)
|
||||
*/
|
||||
function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
|
||||
|
||||
|
@ -140,14 +141,13 @@ interface ERC1155 /* is ERC165 */ {
|
|||
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
## ERC-1155 Token Receiver
|
||||
### ERC-1155 Token Receiver
|
||||
|
||||
Smart contracts **MUST** implement this interface to accept transfers.
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.5.2;
|
||||
pragma solidity ^0.5.7;
|
||||
|
||||
interface ERC1155TokenReceiver {
|
||||
/**
|
||||
|
@ -182,20 +182,20 @@ interface ERC1155TokenReceiver {
|
|||
}
|
||||
```
|
||||
|
||||
## Metadata
|
||||
### Metadata
|
||||
|
||||
The URI value allows for ID substitution by clients. If the string `%s` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/%s.json` would be replaced with `https://token-cdn-domain/780000000000001e000000000000000000000000000000000000000000000000.json` if the client is referring to token ID `780000000000001e000000000000000000000000000000000000000000000000`.
|
||||
The URI value allows for ID substitution by clients. If the string `{id}` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/{id}.json` would be replaced with `https://token-cdn-domain/780000000000001e000000000000000000000000000000000000000000000000.json` if the client is referring to token ID `780000000000001e000000000000000000000000000000000000000000000000`.
|
||||
|
||||
The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: `[0-9a-f]` with no 0x prefix.
|
||||
|
||||
### Metadata Extensions
|
||||
#### Metadata Extensions
|
||||
|
||||
The following optional extensions can be identified with the (ERC-165 Standard Interface Detection)[https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md].
|
||||
The following optional extensions can be identified with the (ERC-165 Standard Interface Detection)[https://eips.ethereum.org/EIPS/eip-165].
|
||||
|
||||
Changes to the URI MUST emit the `URI` event if the change can be expressed with an event. If the optional ERC1155Metadata_URI extension is included, the value returned by this function SHOULD be used to retrieve values for which no event was emitted. The function MUST return the same value as the event if it was emitted.
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.5.2;
|
||||
pragma solidity ^0.5.7;
|
||||
|
||||
/**
|
||||
Note: The ERC-165 identifier for this interface is 0x0e89341c.
|
||||
|
@ -211,9 +211,9 @@ interface ERC1155Metadata_URI {
|
|||
}
|
||||
```
|
||||
|
||||
### ERC-1155 Metadata URI JSON Schema
|
||||
#### ERC-1155 Metadata URI JSON Schema
|
||||
|
||||
This JSON schema is loosely based on the "ERC721 Metadata JSON Schema", but includes optional formatting to allow for ID substitution by clients. If the string `%s` exists in any JSON value, it MUST be replaced with the actual token ID, by all client software that follows this standard.
|
||||
This JSON schema is loosely based on the "ERC721 Metadata JSON Schema", but includes optional formatting to allow for ID substitution by clients. If the string `{id}` exists in any JSON value, it MUST be replaced with the actual token ID, by all client software that follows this standard.
|
||||
|
||||
The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: `[0-9a-f]` with no 0x prefix.
|
||||
|
||||
|
@ -252,7 +252,7 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo
|
|||
{
|
||||
"name": "Asset Name",
|
||||
"description": "Lorem ipsum...",
|
||||
"image": "https:\/\/s3.amazonaws.com\/your-bucket\/images\/%s.png",
|
||||
"image": "https:\/\/s3.amazonaws.com\/your-bucket\/images\/{id}.png",
|
||||
"properties": {
|
||||
"simple_property": "example value",
|
||||
"rich_property": {
|
||||
|
@ -275,58 +275,128 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo
|
|||
}
|
||||
```
|
||||
|
||||
##### Localization
|
||||
|
||||
Metadata localization should be standardized to increase presentation uniformity accross all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content MAY be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software.
|
||||
|
||||
##### JSON Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Token Metadata",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Identifies the asset to which this token represents",
|
||||
},
|
||||
"decimals": {
|
||||
"type": "integer",
|
||||
"description": "The number of decimal places that the token amount should display - e.g. 18, means to divide the token amount by 1000000000000000000 to get its user representation.",
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Describes the asset to which this token represents",
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"description": "A URI pointing to a resource with mime type image/* representing the asset to which this token represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive.",
|
||||
},
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"description": "Arbitrary properties. Values may be strings, numbers, object or arrays.",
|
||||
},
|
||||
"localization": {
|
||||
"type": "object",
|
||||
"required": ["uri", "default", "locales"],
|
||||
"properties": {
|
||||
"uri": {
|
||||
"type": "string",
|
||||
"description": "The URI pattern to fetch localized data from. This URI should contain the substring `{locale}` which will be replaced with the appropriate locale value before sending the request."
|
||||
},
|
||||
"default": {
|
||||
"type": "string",
|
||||
"description": "The locale of the default data within the base JSON"
|
||||
},
|
||||
"locales": {
|
||||
"type": "array",
|
||||
"description": "The list of locales for which data is available. These locales should conform to those defined in the Unicode Common Locale Data Repository (http://cldr.unicode.org/)."
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### Localized Sample
|
||||
|
||||
Base URI:
|
||||
```json
|
||||
{
|
||||
"name": "Advertising Space",
|
||||
"description": "Each token represents a unique Ad space in the city.",
|
||||
"localization": {
|
||||
"uri": "ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/{locale}.json",
|
||||
"default": "en",
|
||||
"locales": ["en", "es", "fr"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
es.json:
|
||||
```json
|
||||
{
|
||||
"name": "Espacio Publicitario",
|
||||
"description": "Cada token representa un espacio publicitario único en la ciudad."
|
||||
}
|
||||
```
|
||||
|
||||
fr.json:
|
||||
```json
|
||||
{
|
||||
"name": "Espace Publicitaire",
|
||||
"description": "Chaque jeton représente un espace publicitaire unique dans la ville."
|
||||
}
|
||||
```
|
||||
|
||||
### Approval
|
||||
|
||||
The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) is suggested.
|
||||
|
||||
## Rationale
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Metadata Choices</summary>
|
||||
### Metadata Choices
|
||||
|
||||
The `symbol` function (found in the ERC-20 and ERC-721 standards) was not included as we do not believe this is a globally useful piece of data to identify a generic virtual item / asset and are also prone to collisions. Short-hand symbols are used in tickers and currency trading, but they aren't as useful outside of that space.
|
||||
|
||||
The `name` function (for human-readable asset names, on-chain) was removed from the standard to allow the Metadata JSON to be the definitive asset name and reduce duplication of data. This also allows localization for names, which would otherwise be prohibitively expensive if each language string was stored on-chain, not to mention bloating the standard interface. While this decision may add a small burden on implementers to host a JSON file containing metadata, we believe any serious implementation of ERC-1155 will already utilize JSON Metadata.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Upgrades</summary>
|
||||
### Upgrades
|
||||
|
||||
The requirement to emit `TransferSingle` or `TransferBatch` on balance change implies that a valid implementation of ERC-1155 redeploying to a new contract address MUST emit events from the new contract address to replicate the deprecated contract final state. It is valid to only emit a minimal number of events to reflect only the final balance and omit all the transactions that led to that state. The event emit requirement is to ensure that the current state of the contract can always be traced only through events. To alleviate the need to emit events when changing contract address, consider using the proxy pattern, such as described in ERC-1538. This will also have the added benefit of providing a stable contract address for users.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Design decision: Supporting non-batch</summary>
|
||||
### Design decision: Supporting non-batch
|
||||
|
||||
The standard supports `safeTransferFrom` and `onERC1155Received` functions because they are significantly cheaper for single token-type transfers, which is arguably a common use case.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Design decision: Safe transfers only</summary>
|
||||
### Design decision: Safe transfers only
|
||||
|
||||
The standard only supports safe-style transfers, making it possible for receiver contracts to depend on `onERC1155Received` or `onERC1155BatchReceived` function to be always called at the end of a transfer.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Guaranteed log trace</summary>
|
||||
### Guaranteed log trace
|
||||
|
||||
As the Ethereum ecosystem continues to grow, many dapps are relying on traditional databases and explorer API services to retrieve and categorize data. The ERC-1155 standard guarantees that event logs emitted by the smart contract will provide enough data to create an accurate record of all current token balances. A database or explorer may listen to events and be able to provide indexed and categorized searches of every ERC-1155 token in the contract.
|
||||
|
||||
</details>
|
||||
### Approval
|
||||
|
||||
The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. It enables frictionless interaction with exchange and trade contracts.
|
||||
|
||||
Restricting approval to a certain set of Token IDs, quantities or other rules MAY be done with an additional interface or an external contract. The rationale is to keep the ERC-1155 standard as generic as possible for all use-cases without imposing a specific approval scheme on implementations that may not need it. Standard token approval interfaces can be used, such as the suggested [ERC-1761 Scoped Approval Interface](https://github.com/ethereum/EIPs/issues/1761) which is compatible with ERC-1155.
|
||||
|
||||
## Usage
|
||||
|
||||
This standard can be used to represent multiple token types for an entire domain. Both Fungible and Non-Fungible tokens can be stored in the same smart-contract.
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Batch Operations</summary>
|
||||
|
||||
### Batch Transfers
|
||||
|
||||
The `safeBatchTransferFrom` function allows for batch transfers of multiple token ids and values. The design of ERC-1155 makes batch transfers possible without the need for a wrapper contract, as with existing token standards. This reduces gas costs when more than one token type is included in a batch transfer, as compared to single transfers with multiple transactions.
|
||||
|
@ -337,34 +407,12 @@ Another advantage of standardized batch transfers is the ability for a smart con
|
|||
|
||||
The `balanceOfBatch` function allows clients to retrieve balances of multiple owners and token ids with a single call.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Approval</summary>
|
||||
|
||||
### Approval
|
||||
|
||||
The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. Single-token based approval of specific token values is not part of the standard. To scope an approval to a specific set or quantity of tokens, we recommend deploying a contract that contains the desired rules, and directing end-users to approve this contract to manage their set of tokens.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Enumeration</summary>
|
||||
|
||||
### Enumerating from events
|
||||
|
||||
In order to keep storage requirements light for contracts implementing ERC-1155, enumeration (discovering the IDs and values of tokens) must be done using event logs. It is RECOMMENDED that clients such as exchanges and blockchain explorers maintain a local database containing the Token ID, Supply, and URI at the minimum. This can be built from each TransferSingle, TransferBatch, and URI event, starting from the block the smart contract was deployed until the latest block.
|
||||
|
||||
ERC-1155 contracts must therefore carefully emit TransferSingle or TransferBatch events in any instance where tokens are created, minted, or destroyed.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Non-Fungible Tokens</summary>
|
||||
|
||||
### Non-Fungible Tokens
|
||||
|
||||
The following strategy is an example of how to mix fungible and non-fungible tokens together in the same contract. The top 128 bits of the uint256 `_id` parameter in any ERC-1155 function could represent the base token ID, while the bottom 128 bits might be used for any extra data passed to the contract.
|
||||
|
@ -383,21 +431,20 @@ balanceOf(baseToken, msg.sender); // Get balance of the base token
|
|||
balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible token index
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## References
|
||||
|
||||
**Standards**
|
||||
- [ERC-721 Non-Fungible Token Standard](https://raw.githubusercontent.com/ethereum/EIPs/master/EIPS/eip-721.md)
|
||||
- [ERC-165 Standard Interface Detection](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md)
|
||||
- [ERC-1538 Transparent Contract Standard](https://github.com/ethereum/EIPs/issues/1538)
|
||||
- [JSON Schema](http://json-schema.org/)
|
||||
- [ERC-721 Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721)
|
||||
- [ERC-165 Standard Interface Detection](https://eips.ethereum.org/EIPS/eip-165)
|
||||
- [ERC-1538 Transparent Contract Standard (DRAFT)](https://eips.ethereum.org/EIPS/eip-1538)
|
||||
- [JSON Schema](https://json-schema.org/)
|
||||
- [RFC 2119 Key words for use in RFCs to Indicate Requirement Levels](https://www.ietf.org/rfc/rfc2119.txt)
|
||||
|
||||
**Implementations**
|
||||
- [ERC-1155 Reference Implementation](https://github.com/enjin/erc-1155)
|
||||
- [Horizon Games - Multi-Token Standard](https://github.com/horizon-games/multi-token-standard)
|
||||
- [Enjin Coin](https://enjincoin.io) ([github](https://github.com/enjin))
|
||||
- [Enjin Coin](https://enjincoin.io) ([GitHub](https://github.com/enjin))
|
||||
- [The Sandbox - Dual ERC-1155/721 Contract](https://github.com/pixowl/thesandbox-contracts/tree/master/src/Asset)
|
||||
|
||||
**Articles & Discussions**
|
||||
- [Github - Original Discussion Thread](https://github.com/ethereum/EIPs/issues/1155)
|
||||
|
|
|
@ -7,6 +7,7 @@ status: Final
|
|||
type: Standards Track
|
||||
category: ERC
|
||||
created: 2018-06-22
|
||||
requires: 211
|
||||
---
|
||||
|
||||
<!--You can leave these HTML comments in your merged EIP and delete the visible duplicate text guides, they will not appear and may be helpful to refer to if you edit it again. This is the suggested template for new EIPs. Note that an EIP number will be assigned by an editor. When opening a pull request to submit your EIP, please use an abbreviated title in the filename, `eip-draft_title_abbrev.md`. The title should be 44 characters or less.-->
|
||||
|
@ -25,7 +26,7 @@ This standard supports use-cases wherein it is desireable to clone exact contrac
|
|||
|
||||
## Specification
|
||||
<!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (go-ethereum, parity, cpp-ethereum, ethereumj, ethereumjs, and [others](https://github.com/ethereum/wiki/wiki/Clients)).-->
|
||||
The exact bytecode of the standard clone contract is this: `363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3` wherein the bytes at idices 10 - 29 (inclusive) are replaced with the 20 byte address of the master functionality contract.
|
||||
The exact bytecode of the standard clone contract is this: `363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3` wherein the bytes at indices 10 - 29 (inclusive) are replaced with the 20 byte address of the master functionality contract.
|
||||
|
||||
A reference implementation of this can be found at the [optionality/clone-factory](https://github.com/optionality/clone-factory) github repo.
|
||||
|
||||
|
|
|
@ -88,10 +88,10 @@ for chainid, cases in test_cases.items():
|
|||
| RSK Mainnet | 30 | Yes |
|
||||
| RSK Testnet | 31 | Yes |
|
||||
|
||||
|
||||
| Wallet | Implements this EIP|
|
||||
|--------------|--------------------|
|
||||
| MyCrypto | In progress |
|
||||
| Ledger | In progress |
|
||||
| Trezor | In progress |
|
||||
|
||||
### Implementation Table
|
||||
| Wallet | Adopted this EIP | Implementation |
|
||||
|----------------|------------------| -------------- |
|
||||
| MyCrypto | Yes | [JavaScript](https://github.com/MyCryptoHQ/MyCrypto/blob/develop/common/utils/formatters.ts#L126) |
|
||||
| MyEtherWallet | Yes | [JavaScript](https://github.com/MyEtherWallet/MyEtherWallet/blob/73c4a24f8f67c655749ac990c5b62efd92a2b11a/src/helpers/addressUtils.js#L22) |
|
||||
| Ledger | Yes | [C](https://github.com/LedgerHQ/ledger-app-eth/blob/master/src_common/ethUtils.c#L203) |
|
||||
| Trezor | Yes | [Python](https://github.com/trezor/trezor-core/blob/270bf732121d004a4cd1ab129adaccf7346ff1db/src/apps/ethereum/get_address.py#L32) and [C](https://github.com/trezor/trezor-crypto/blob/4153e662b60a0d83c1be15150f18483a37e9092c/address.c#L62) |
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
---
|
||||
eip: 1193
|
||||
title: Ethereum Provider JavaScript API
|
||||
author: Ryan Ghods (@ryanio), Marc Garreau (@marcgarreau)
|
||||
author: Fabian Vogelsteller (@frozeman), Ryan Ghods (@ryanio), Marc Garreau (@marcgarreau), Victor Maia (@MaiaVictor)
|
||||
discussions-to: https://ethereum-magicians.org/t/eip-1193-ethereum-provider-javascript-api/640
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Interface
|
||||
created: 2018-06-30
|
||||
requires: 1102
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This EIP formalizes an Ethereum Provider JavaScript API for consistency across clients and applications.
|
||||
|
||||
The provider is designed to be minimal containing 2 methods: `send` and `on`. It emits 5 types of events: `notification`, `connect`, `close`, `networkChanged`, and `accountsChanged`.
|
||||
|
||||
It is intended to be available on `window.ethereum`.
|
||||
This EIP formalizes an Ethereum Provider JavaScript API for consistency across clients and applications. The provider is designed to be minimal and is intended to be available on `window.ethereum` for cross environment compatibility.
|
||||
|
||||
## API
|
||||
|
||||
|
@ -34,11 +29,11 @@ See the [available methods](https://github.com/ethereum/wiki/wiki/JSON-RPC#json-
|
|||
|
||||
#### eth_requestAccounts
|
||||
|
||||
By default, the provider supplied to a new dapp has is a "read-only" provider with no accounts authenticated.
|
||||
By default, the provider supplied to a new dapp has is a "read-only" provider with no accounts authenticated. See [EIP 1102: Opt-in account exposure](https://eips.ethereum.org/EIPS/eip-1102).
|
||||
|
||||
To request accounts, call `ethereum.send('eth_requestAccounts')`. This will ask the user which account(s) they would like to authenticate to the dapp.
|
||||
|
||||
Promise resolves with an array of the account(s) public keys.
|
||||
Promise resolves with an array of the enabled account(s) addresses.
|
||||
|
||||
### Events
|
||||
|
||||
|
@ -46,13 +41,22 @@ Events are emitted using [EventEmitter](https://nodejs.org/api/events.html).
|
|||
|
||||
#### notification
|
||||
|
||||
All subscriptions from the node emit on `notification`. Attach listeners with:
|
||||
All subscriptions from the node emit on "subscription type" (e.g. `eth_subscription`, or `ssh_subscription`). Attach listeners with:
|
||||
|
||||
```js
|
||||
ethereum.on('notification', listener: (result: any) => void): this;
|
||||
ethereum.on('eth_subscription', listener: (result: any) => void): this;
|
||||
```
|
||||
|
||||
To create a subscription, call `ethereum.send('eth_subscribe')` or `ethereum.send('shh_subscribe')`. The subscription `result` object will emit through `notification`.
|
||||
To create a subscription, call `ethereum.send('eth_subscribe')` or `ethereum.send('shh_subscribe')`. The subscription object will emit through the specifc subscription type.
|
||||
|
||||
The result object will look as follows:
|
||||
|
||||
```js
|
||||
{
|
||||
"subscription":"0xc3b33aa549fb9a60e95d21862596617c",
|
||||
"result": {...}
|
||||
}
|
||||
```
|
||||
|
||||
See the [eth subscription methods](https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB#supported-subscriptions) and [shh subscription methods](https://github.com/ethereum/go-ethereum/wiki/Whisper-v6-RPC-API#shh_subscribe).
|
||||
|
||||
|
@ -99,24 +103,18 @@ The provider emits `accountsChanged` if the accounts returned from the provider
|
|||
ethereum.on('accountsChanged', listener: (accounts: Array<String>) => void): this;
|
||||
```
|
||||
|
||||
The event emits with `accounts`, an array of the accounts' public keys.
|
||||
|
||||
### Constructor
|
||||
|
||||
```js
|
||||
ethereum.constructor.name;
|
||||
> 'EthereumProvider'
|
||||
```
|
||||
The event emits with `accounts`, an array of the accounts' addresses.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
const ethereum = window.ethereum;
|
||||
|
||||
// A) Primary use case - set provider in web3.js
|
||||
web3.setProvider(ethereum);
|
||||
// A) Set provider in web3.js
|
||||
var web3 = new Web3(ethereum);
|
||||
|
||||
// B) Secondary use case - use provider object directly
|
||||
|
||||
// B) Use provider object directly
|
||||
// Example 1: Log last block
|
||||
ethereum
|
||||
.send('eth_getBlockByNumber', ['latest', 'true'])
|
||||
|
@ -130,6 +128,7 @@ ethereum
|
|||
);
|
||||
});
|
||||
|
||||
|
||||
// Example 2: Request accounts
|
||||
ethereum
|
||||
.send('eth_requestAccounts')
|
||||
|
@ -147,6 +146,7 @@ ethereum
|
|||
);
|
||||
});
|
||||
|
||||
|
||||
// Example 3: Log available accounts
|
||||
ethereum
|
||||
.send('eth_accounts')
|
||||
|
@ -160,13 +160,14 @@ ethereum
|
|||
);
|
||||
});
|
||||
|
||||
|
||||
// Example 4: Log new blocks
|
||||
let subId;
|
||||
ethereum
|
||||
.send('eth_subscribe', ['newHeads'])
|
||||
.then(subscriptionId => {
|
||||
subId = subscriptionId;
|
||||
ethereum.on('notification', result => {
|
||||
ethereum.on('eth_subscription', result => {
|
||||
if (result.subscription === subscriptionId) {
|
||||
if (result.result instanceof Error) {
|
||||
const error = result.result;
|
||||
|
@ -187,6 +188,7 @@ ethereum
|
|||
Code: ${error.code}. Data: ${error.data}`
|
||||
);
|
||||
});
|
||||
|
||||
// to unsubscribe
|
||||
ethereum
|
||||
.send('eth_unsubscribe', [subId])
|
||||
|
@ -200,6 +202,7 @@ ethereum
|
|||
);
|
||||
});
|
||||
|
||||
|
||||
// Example 5: Log when accounts change
|
||||
const logAccounts = accounts => {
|
||||
console.log(`Accounts:\n${accounts.join('\n')}`);
|
||||
|
@ -216,19 +219,13 @@ ethereum.on('close', (code, reason) => {
|
|||
|
||||
## Specification
|
||||
|
||||
### Send
|
||||
### Errors
|
||||
|
||||
The `send` method **MUST** send a properly formatted [JSON-RPC request](https://www.jsonrpc.org/specification#request_object).
|
||||
|
||||
If the Ethereum JSON-RPC API returns a response object with no error, then the Promise **MUST** resolve with the `response.result` object untouched by the implementing Ethereum Provider.
|
||||
|
||||
If the Ethereum JSON-RPC API returns response object that contains an error property then the Promise **MUST** reject with an Error object containing the `response.error.message` as the Error message, `response.error.code` as a code property on the error and `response.error.data` as a data property on the error.
|
||||
If the Ethereum Provider request returns an error property then the Promise **MUST** reject with an Error object containing the `error.message` as the Error message, `error.code` as a code property on the error and `error.data` as a data property on the error.
|
||||
|
||||
If an error occurs during processing, such as an HTTP error or internal parsing error, then the Promise **MUST** reject with an `Error` object.
|
||||
|
||||
If the implementing Ethereum Provider is not talking to an external Ethereum JSON-RPC API provider then it **MUST** resolve with an object that matches the JSON-RPC API object as specified in the [Ethereum JSON-RPC documentation](https://github.com/ethereum/wiki/wiki/JSON-RPC).
|
||||
|
||||
If the JSON-RPC request requires an account that is not yet authenticated, the Promise **MUST** reject with Error code 4100.
|
||||
If the request requires an account that is not yet authenticated, the Promise **MUST** reject with Error code 4100.
|
||||
|
||||
#### eth_requestAccounts
|
||||
|
||||
|
@ -238,13 +235,17 @@ If the dapp has been previously authenticated and remembered by the user, then t
|
|||
|
||||
If no accounts are authenticated, the `eth_requestAccounts` method **MUST** ask the user which account(s) they would like to authenticate to the dapp. If the request has been previously granted and remembered, the `eth_requestAccounts` method **MAY** immediately return.
|
||||
|
||||
The `eth_requestAccounts` method **MUST** resolve with an array of the account(s) public keys or reject with an `Error`. If the account(s) enabled by the provider change, the `accountsChanged` event **MUST** also emit.
|
||||
The `eth_requestAccounts` method **MUST** resolve with an array of the account(s) addresses or reject with an `Error`. If the account(s) enabled by the provider change, the `accountsChanged` event **MUST** also emit.
|
||||
|
||||
For full specification of the `eth_requestAccounts` RPC method, see [EIP 1102: Opt-in account exposure](https://eips.ethereum.org/EIPS/eip-1102).
|
||||
|
||||
### Events
|
||||
|
||||
The provider **SHOULD** extend from `EventEmitter` to provide dapps flexibility in listening to events. In place of full `EventEmitter` functionality, the provider **MAY** provide as many methods as it can reasonably provide, but **MUST** provide at least `on`, `emit`, and `removeListener`.
|
||||
|
||||
#### notification
|
||||
|
||||
All subscriptions received from the node **MUST** emit the `message.params` to the eventName `notification` without modification.
|
||||
All subscriptions received from the node **MUST** emit the `subscription` property with the subscription ID and a `results` property.
|
||||
|
||||
#### connect
|
||||
|
||||
|
@ -260,15 +261,11 @@ If the network the provider is connected to changes, the provider **MUST** emit
|
|||
|
||||
#### accountsChanged
|
||||
|
||||
If the accounts connected to the Ethereum Provider change, the Ethereum Provider **MUST** send an event with the name `accountsChanged` with args `accounts: Array<String>` containing the accounts' public key(s).
|
||||
|
||||
### Class
|
||||
|
||||
The name of the constructor of the Ethereum Provider **MUST** be `EthereumProvider`.
|
||||
If the accounts connected to the Ethereum Provider change at any time, the Ethereum Provider **MUST** send an event with the name `accountsChanged` with args `accounts: Array<String>` containing the accounts' addresses.
|
||||
|
||||
### web3.js Backwards Compatibility
|
||||
|
||||
If the implementing Ethereum Provider would like to be compatible with `web3.js` prior to `1.0.0-beta37`, it **MUST** provide two methods: `sendAsync(payload: Object, callback: (error: any, result: any) => void): void` and `isConnected(): Boolean`.
|
||||
If the implementing Ethereum Provider would like to be compatible with `web3.js` prior to `1.0.0-beta38`, it **MUST** provide the method: `sendAsync(payload: Object, callback: (error: any, result: any) => void): void`.
|
||||
|
||||
### Error object and codes
|
||||
|
||||
|
@ -276,11 +273,12 @@ If an Error object is returned, it **MUST** contain a human readable string mess
|
|||
|
||||
Appropriate error codes **SHOULD** follow the table of [`CloseEvent` status codes](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes), along with the following table:
|
||||
|
||||
| Status code | Name | Description |
|
||||
| ----------- | ---------------------------- | ---------------------------------------------------------- |
|
||||
| 4001 | User Denied Request Accounts | User denied authorizing any accounts for the dapp. |
|
||||
| 4010 | User Denied Create Account | User denied creating a new account. |
|
||||
| 4100 | Unauthorized | The requested account has not been authorized by the user. |
|
||||
| Status code | Name | Description |
|
||||
| ----------- | ---------------------------- | --------------------------------------------------------------------- |
|
||||
| 4001 | User Denied Request Accounts | User denied authorizing any accounts for the dapp. |
|
||||
| 4010 | User Denied Create Account | User denied creating a new account. |
|
||||
| 4100 | Unauthorized | The requested account has not been authorized by the user. |
|
||||
| 4200 | Unsupported Method | The requested method is not supported by the given Ethereum Provider. |
|
||||
|
||||
## Sample Class Implementation
|
||||
|
||||
|
@ -291,7 +289,6 @@ class EthereumProvider extends EventEmitter {
|
|||
super();
|
||||
|
||||
// Init storage
|
||||
this._isConnected = false;
|
||||
this._nextJsonrpcId = 0;
|
||||
this._promises = {};
|
||||
|
||||
|
@ -395,12 +392,10 @@ class EthereumProvider extends EventEmitter {
|
|||
}
|
||||
|
||||
_emitConnect() {
|
||||
this._isConnected = true;
|
||||
this.emit('connect');
|
||||
}
|
||||
|
||||
_emitClose(code, reason) {
|
||||
this._isConnected = false;
|
||||
this.emit('close', code, reason);
|
||||
}
|
||||
|
||||
|
@ -429,10 +424,6 @@ class EthereumProvider extends EventEmitter {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
isConnected() {
|
||||
return this._isConnected;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ author: Afri Schoedon (@5chdn)
|
|||
discussions-to: https://ethereum-magicians.org/t/eip-1234-constantinople-difficulty-bomb-delay-and-block-reward-adjustment/833
|
||||
type: Standards Track
|
||||
category: Core
|
||||
status: Accepted
|
||||
status: Final
|
||||
created: 2018-07-19
|
||||
---
|
||||
|
||||
|
|
|
@ -365,7 +365,7 @@ Membership Verification Token ERC1261 -- a reference implementation
|
|||
1. ERC-165 Standard Interface Detection. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
|
||||
1. ERC-725/735 Claim Registry https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md
|
||||
1. ERC-173 Owned Standard. https://github.com/ethereum/EIPs/issues/173
|
||||
1. JSON Schema. http://json-schema.org/
|
||||
1. JSON Schema. https://json-schema.org/
|
||||
1. Multiaddr. https://github.com/multiformats/multiaddr
|
||||
1. RFC 2119 Key words for use in RFCs to Indicate Requirement Levels. https://www.ietf.org/rfc/rfc2119.txt
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ eip: 1283
|
|||
title: Net gas metering for SSTORE without dirty maps
|
||||
author: Wei Tang (@sorpaas)
|
||||
discussions-to: https://github.com/sorpaas/EIPs/issues/1
|
||||
status: Accepted
|
||||
status: Final
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2018-08-01
|
||||
|
@ -155,7 +155,7 @@ When *original value* is not 0:
|
|||
|
||||
## Rationale
|
||||
|
||||
This EIP mostly archives what a transient storage tries to do
|
||||
This EIP mostly achieves what a transient storage tries to do
|
||||
(EIP-1087 and EIP-1153), but without the complexity of introducing the
|
||||
concept of "dirty maps", or an extra storage struct.
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
eip: 1319
|
||||
title: Smart Contract Package Registry Interface
|
||||
author: Piper Merriam <piper@ethereum.org>, Christopher Gewecke <christophergewecke@gmail.com>, g. nicholas d'andrea <nick.dandrea@consensys.net>
|
||||
author: Piper Merriam <piper@ethereum.org>, Christopher Gewecke <christophergewecke@gmail.com>, g. nicholas d'andrea <nick.dandrea@consensys.net>, Nick Gheorghita <nickg@ethereum.org>
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
status: Draft
|
||||
|
@ -94,6 +94,16 @@ details the contents of the release.
|
|||
function release(string packageName, string version, string manifestURI) public
|
||||
returns (bytes32 releaseId);
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
#### VersionRelease
|
||||
MUST be triggered when `release` is successfully called.
|
||||
|
||||
```solidity
|
||||
event VersionRelease(string packageName, string version, string manifestURI)
|
||||
```
|
||||
|
||||
### Read API Specification
|
||||
|
||||
The read API consists of a set of methods that allows tooling to extract all consumable data from a registry.
|
||||
|
@ -103,7 +113,7 @@ The read API consists of a set of methods that allows tooling to extract all con
|
|||
// `offset` and `limit` enable paginated responses / retrieval of the complete set. (See note below)
|
||||
function getAllPackageIds(uint offset, uint limit) public view
|
||||
returns (
|
||||
bytes32 packageIds,
|
||||
bytes32[] packageIds,
|
||||
uint offset
|
||||
);
|
||||
|
||||
|
@ -135,6 +145,12 @@ function generateReleaseId(string packageName, string version)
|
|||
public
|
||||
view
|
||||
returns (bytes32);
|
||||
|
||||
// Returns the total number of unique packages in a registry.
|
||||
function numPackageIds() public view returns (uint totalCount);
|
||||
|
||||
// Returns the total number of unique releases belonging to the given packageName in a registry.
|
||||
function numReleaseIds(string packageName) public view returns (uint totalCount);
|
||||
```
|
||||
**Pagination**
|
||||
|
||||
|
|
|
@ -7,12 +7,11 @@ category: ERC
|
|||
status: Draft
|
||||
created: 2018-08-15
|
||||
discussions-to: https://ethereum-magicians.org/t/wallet-connect-eip/850
|
||||
requires: 831
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
|
||||
A standard to create WalletConnect URIs for establishing connections between wallets and applications.
|
||||
A standard to create WalletConnect URIs to initiate connections between applications and wallets.
|
||||
|
||||
## Abstract
|
||||
|
||||
|
@ -22,33 +21,33 @@ This standard defines how the data to connect some application and a wallet can
|
|||
|
||||
### Syntax
|
||||
|
||||
Function call URIs follow the ERC-831 URI format, with the following parameters:
|
||||
WalletConnect request URI with the following parameters:
|
||||
|
||||
request = "ethereum" ":" [ "wc-" ]sessionId [ "@" version ][ "?" parameters ]
|
||||
sessionId = STRING
|
||||
request = "wc" ":" topic [ "@" version ][ "?" parameters ]
|
||||
topic = STRING
|
||||
version = 1*DIGIT
|
||||
parameters = parameter *( "&" parameter )
|
||||
parameter = key "=" value
|
||||
key = "name" / "bridge" / "symKey"
|
||||
value = NUMBER / STRING
|
||||
key = "bridge" / "key"
|
||||
value = STRING
|
||||
|
||||
### Semantics
|
||||
|
||||
Required parameters are dependent on the WalletConnect standard version which currently is specified to only include mobile-to-desktop connection sessions which only require `name` which describes the dapp name, `bridge` which includes the bridge URL, `symKey` which includes the symmetric key in base64.
|
||||
Required parameters are dependent on the Walletconnect protocol version which currently includes the `key`, hex string of symmetric key, and `bridge`, encoded url of the bridge used for establishing the connection.
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
ethereum:wc-8a5e5bdc-a0e4-4702-ba63-8f1a5655744f@1?name=DappExample&bridge=https://bridge.example.com&symKey=KzpSTk1pezg5eTJRNmhWJmoxdFo6UDk2WlhaOyQ5N0U=
|
||||
wc:8a5e5bdc-a0e4-4702-ba63-8f1a5655744f@1?bridge=https%3A%2F%2Fbridge.walletconnect.org&key=41791102999c339c844880b23950704cc43aa840f3739e365323cda4dfa89e7a
|
||||
```
|
||||
|
||||
## Rationale
|
||||
|
||||
The need for this ERC stems from the discussion to move away from JSON format used in current beta version of the WalletConnect standard which makes for very inneficient parsing of the intent of the QR code, making it easier to create better QR code parsers APIs for Wallets to implement for other compatible EIPs using the ERC-831 URI format for Ethereum. Also by using a URI instead of a JSON inside the QR-Code the Android Intent system can be leveraged.
|
||||
The need for this ERC stems from the discussion to move away from JSON format used in the alpha version of the WalletConnect protocol which makes for very inneficient parsing of the intent of the QR code, making it easier to create better QR code parsers APIs for Wallets to implement. Also by using a URI instead of a JSON inside the QR-Code the Android Intent system can be leveraged.
|
||||
|
||||
## References
|
||||
|
||||
1. ERC-831, http://eips.ethereum.org/EIPS/eip-831
|
||||
1. WalletConnect Technical Specification, https://docs.walletconnect.org/tech-spec
|
||||
|
||||
## Copyright
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
eip: 1344
|
||||
title: ChainID opcode
|
||||
author: Richard Meissner (@rmeissner)
|
||||
discussions-to: https://ethereum-magicians.org/t/add-chain-id-opcode-for-replay-protection-when-handling-signed-messages-in-contracts/1131
|
||||
category: Core
|
||||
type: Standards Track
|
||||
status: Draft
|
||||
created: 2018-08-22
|
||||
---
|
||||
### Specification
|
||||
Adds a new opcode at 0x46, which takes 0 stack arguments. It will return the chain id of the chain where the block was mined. It should cost 2 gas (G_base) to execute this opcode.
|
||||
### Motivation
|
||||
[EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) proposes to use the chain id to prevent replay attacks between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling signatures.
|
||||
The current approach proposed by [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md) is to specify the chain id on compile time. Using this approach will result in problems after a hardfork.
|
||||
By adding the opcode it would be possible to access the current chain id and validate signatures based on that.
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
eip: 1355
|
||||
title: Ethash 1a
|
||||
author: Paweł Bylica <pawel@ethereum.org>, Jean M. Cyr [@jean-m-cyr](https://github.com/jean-m-cyr)
|
||||
author: Paweł Bylica (@chfast) <pawel@ethereum.org>, Jean M. Cyr (@jean-m-cyr)
|
||||
discussions-to: https://ethereum-magicians.org/t/eip-1355-ethash-1a/1167
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
|
|
|
@ -70,10 +70,10 @@ Because the `namehash` procedure depends only on the name itself, this can be pr
|
|||
ENS names must conform to the following syntax:
|
||||
|
||||
<pre><domain> ::= <label> | <domain> "." <label>
|
||||
<label> ::= any valid string label per [UTS46](http://unicode.org/reports/tr46/)
|
||||
<label> ::= any valid string label per [UTS46](https://unicode.org/reports/tr46/)
|
||||
</pre>
|
||||
|
||||
In short, names consist of a series of dot-separated labels. Each label must be a valid normalised label as described in [UTS46](http://unicode.org/reports/tr46/) with the options `transitional=false` and `useSTD3AsciiRules=true`. For Javascript implementations, a [library](https://www.npmjs.com/package/idna-uts46) is available that normalises and checks names.
|
||||
In short, names consist of a series of dot-separated labels. Each label must be a valid normalised label as described in [UTS46](https://unicode.org/reports/tr46/) with the options `transitional=false` and `useSTD3AsciiRules=true`. For Javascript implementations, a [library](https://www.npmjs.com/package/idna-uts46) is available that normalises and checks names.
|
||||
|
||||
Note that while upper and lower case letters are allowed in names, the UTS46 normalisation process case-folds labels before hashing them, so two names with different case but identical spelling will produce the same namehash.
|
||||
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
---
|
||||
eip: 1418
|
||||
title: Blockchain Storage Rent Payment
|
||||
author: William Entriken <@fulldecent>
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/1418
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2018-09-16
|
||||
---
|
||||
|
||||
# Simple Summary
|
||||
|
||||
At each block, deduct an amount of value from every account based on the quantity of storage used by that account.
|
||||
|
||||
# Abstract
|
||||
|
||||
The most naive implementation would be to simply loop through every account on each block and deduct a certain fee. We show that a better implementation could achieve reasonable performance. Also we review practical considerations of switching to a fee-based rent system.
|
||||
|
||||
In other words, `product=0; while(factor1--)product+= factor2;` is slow, but equivalently `product = factor1 * factor2` is fast. And we can reason about both at the same time.
|
||||
|
||||
# Motivation
|
||||
|
||||
Ethereum is a public utility and we are underpricing the long-term costs of storage. Storage cost can be approximately modeled as bytes × time.
|
||||
|
||||
# Specification
|
||||
|
||||
**New state variables (per account)**
|
||||
|
||||
* rent -- σ[a]_r -- an amount of value, in Wei
|
||||
* rentLastPaid -- σ[a]_p -- a block number that is set when:
|
||||
* Value is transferred into an account
|
||||
* Code is set for an account (CREATE)
|
||||
* An account's storage is updated (SSTORE)
|
||||
* storageWords -- σ[a]_w -- number of words in storage
|
||||
* rentEvictBlock -- σ[a]_e -- the block number when this account will be destructed
|
||||
* Note: it is possible that a client could implement the Yellow Paper without storing this value explicitly. It can be calculated simply on demand.
|
||||
|
||||
**New constants**
|
||||
|
||||
* RENT_WORD_COST -- The rent cost, in Wei, paid for each word-block
|
||||
* RENT_ACCOUNT_COST -- The rent cost, in Wei, paid for each account-block
|
||||
* RENT_STIPEND -- The amount of rent, in Wei, given to accounts when touched
|
||||
|
||||
**New opcodes**
|
||||
|
||||
* RENTBALANCE(address) -- G_BALANCE -- Similar to BALANCE
|
||||
* SENDRENT(address, amount) -- G_BASE -- Convert value to rent and send to account
|
||||
1. σ[account]_rent += amount
|
||||
2. σ[msg.sender]_balance -= amount
|
||||
|
||||
**Updated opcodes**
|
||||
|
||||
A new subroutine, paying for rent, is established as such:
|
||||
|
||||
```pseudocode
|
||||
PAYRENT(account)
|
||||
ASSERT(σ[account]_rentEviction >= NUMBER) // TODO: I'm not sure if should be > or >=
|
||||
blocks_to_pay = NUMBER - σ[account]_rentLastPaid
|
||||
cost_per_block = RENT_ACCOUNT_COST + RENT_WORD_COST * ⌈∥σ[account]_code∥ / 32⌉ + RENT_WORD_COST * σ[a]_storageWords
|
||||
rent_to_pay = blocks_to_pay * cost_per_block
|
||||
σ[account]_rent -= rent_to_pay
|
||||
σ[account]_rentLastPaid = NUMBER
|
||||
σ[account]_rentEvictBlock = NUMBER + ⌊σ[account]_rent / cost_per_block⌋
|
||||
END PAYRENT
|
||||
```
|
||||
|
||||
* SSTORE(account, key, value)
|
||||
* Perform PAYRENT(account)
|
||||
* Set σ[account]_rent = MAX(σ[account]_rent, RENT_STIPEND)
|
||||
* Do normal SSTORE operation
|
||||
* If the old value was zero for this [account, key] and the new value is non-zero, then σ[account]_storageSize++
|
||||
* If the old value was non-zero for this [account, key] and the new value is zero, then σ[account]_storageSize--
|
||||
* CALL (and derivatives)
|
||||
* If value > 0 then perform PAYRENT(account)
|
||||
* Do normal CALL operation
|
||||
* CREATE
|
||||
* Set σ[account]_rent = MAX(σ[account]_rent, RENT_STIPEND)
|
||||
* Set σ[account]_rentLastPaid = HEIGHT
|
||||
* Do normal CREATE operation
|
||||
* Note: it is possible there is a pre-existing rent balance here
|
||||
|
||||
**Updated substate**
|
||||
|
||||
The substate tuple is defined as:
|
||||
|
||||
> A ≡ (As, Al, At, Ar)
|
||||
|
||||
This includes A_t, "the set of touched accounts, of which the empty ones are deleted at the end of a transaction".
|
||||
|
||||
This definition is updated to: "the set of touched accounts, of which the empty ones or evicted ones (BLOCK >= σ[a]_rentEvictBlock) are deleted at the end of a transaction"
|
||||
|
||||
// TODO: I'm not sure if that should be > or >=
|
||||
|
||||
**New built-in contract**
|
||||
|
||||
* PAYRENT(address, amount) -- Calls PAYRENT opcode
|
||||
|
||||
*This is a convenience for humans to send Ether from their accounts and turn it into rent. Note that simple accounts (CODESIZE == 0) cannot call arbitrary opcodes, they can only call CREATE or CALL.*
|
||||
|
||||
The gas cost of PAYRENT will be 10,000.
|
||||
|
||||
**No changes to current opcode gas costs.**
|
||||
|
||||
# Rationale
|
||||
|
||||
**No call**
|
||||
|
||||
A contract will not know or react to the receipt of rent. This is okay. Workaround: if a contract really needed to know who provided rent payments then it could create a function in its ABI to attribute these payments. It is already possible to send payments to a contract without attribution by using SELFDESTRUCT.
|
||||
|
||||
**Eviction responsibility / lazy evaluation**
|
||||
|
||||
The specification gives responsibility for eviction to the consensus clients. This is the most predictable behavior because it happens exactly when it should. Also there need not be any incentive mechanism (refund gas, bounty) for outside participants (off chain) to monitor accounts and request removal.
|
||||
|
||||
This adds a computational responsibility to the clients to track eviction dates. This is possible in efficient time (at double the memory) using a double-ended priority queue (one for addressing by account address, the other for addressing by eviction date). There may be other ways of implementing this with different time-memory guarantees.
|
||||
|
||||
**No converting rent to value**
|
||||
|
||||
Ether converted to rent cannot be converted back. Anybody that works in accounting and knows about gifts cards should tell you this is a good idea. It makes reasoning about the system much easier.
|
||||
|
||||
**Accounts pay rent**
|
||||
|
||||
Yes, they pay rent. It costs money to keep their balances so we charge them rent.
|
||||
|
||||
**You can lose all your money**
|
||||
|
||||
Yes, if you do not pay rent for your account or contract then you lose it all. User education is required.
|
||||
|
||||
Alternative: spend value (Ether balance) when rent is depleted
|
||||
* Rename rentEvictBlock to rentUsingValueBlock
|
||||
* Update eviction calculation to include RENT + VALUE. Also update CALL (and friends) operations to recalculate eviction date when value is transferred. This is the new rentEvictBlock.
|
||||
* Update CALL (and friends), RENTBALANCE and SENDRENT operations. If HEIGHT >= rentUsingValueBlock then proceed as if rent started paying using value.
|
||||
|
||||
This alternative is a good idea, if there is support I can include this part formally in the specification. The specification is a little complicated so I like the informal definition above until we have some consent around it.
|
||||
|
||||
Alternative2: do not have a separate rent account -- directly deduct rent from value
|
||||
* Every time the state is updated (including receiving value) you get a rent subsidity
|
||||
* Need to review invariants of existing contracts to see what problems and broken assumptions this will cause in real life
|
||||
|
||||
**Permanent removal**
|
||||
|
||||
All state about an account is destructed during eviction. The data cannot be recovered. That's the point.
|
||||
|
||||
Hint to implementers: make sure this works:
|
||||
|
||||
1. Send value to a new account (gets stipend)
|
||||
2. Pay rent to that account
|
||||
3. Wait until after the rent expires (account is gone)
|
||||
4. Send value to that account (gets stipend again)
|
||||
5. Deploy a contract (CREATE) to that account (stipend gets topped off)
|
||||
|
||||
# Rationale -- economics & constants
|
||||
|
||||
An `SSTORE` executed in 2015 cost 20,000 gas and has survived about 6 million blocks. The gas price has been around 1 ~ 50 Gwei. So basically 4,000 Wei per block per word so far. Maybe storing an account is 10 times more intensive than storing a word. But actually G_transaction is 21,000 and G_sstore is 20,000 so these are similar and they can both create new accounts / words.
|
||||
|
||||
How about:
|
||||
|
||||
* RENT_WORD_COST -- 4,000 Wei
|
||||
* RENT_ACCOUNT_COST -- 4,000 Wei
|
||||
* RENT_STIPEND -- 4,000 Wei * 360 days worth of blocks
|
||||
|
||||
The rent is priced in cold, hard Ether. It is not negotiated by clients, it is not dynamic. It is linear. Why is this a good idea? Because right now Ethereum is a system with multiple free variables -- Ether/gas price, gas/opcodes costs, Ether/block reward. [Add some note here about reducing a system of equations...] So the end result is that we can peg one of the values and it will be okay.
|
||||
|
||||
By setting the RENT price in Ether and by having the existing gas prices set based on the floating rate, there is an implicit price of ~4 gwei set into the Yellow Paper. In other words, if in the future the price of gas goes to 1 Ether then people will be upset because they will say "I paid 20,000 gas for an SSTORE" but I only got 360 days of stipend. If I paid for the rent directly I would have gotten enough rent to last until the Sun explodes." I acknowledge this complaint and do not think it is sufficient to warrant dismissing this proposal.
|
||||
|
||||
Q: There is a finite-ish amount of Ether and this proposal introduces a word-price in Ether, do math for me. A: The current size of Ethereum is about ~1 TB, maybe half of that is branch nodes. So that's like 15B words. There is about 100M Ether mined. The answer is that all the Ether can be spent on 400,000 terabyte-years of storage. I'm not sure if it is helpful to look at it that way.
|
||||
|
||||
# Backwards compatibility
|
||||
|
||||
There is a 360-day transition period (related to the RENT_STIPEND). This requires a hard fork. On the block of the fork, every account is immediately funded with enough rent to pay for ~ 360 days' worth of their current storage requirements. The formal implementation is that this new rule is applied if any existing account has σ[account]_rentLastPaid = 0. Therefore this can be implemented by clients lazily or eagerly.
|
||||
|
||||
Preexisting accounts which increase their storage needs will evict sooner than 360 days.
|
||||
|
||||
Users will need to be educated.
|
||||
|
||||
# Test Cases
|
||||
|
||||
TO BE ADDED
|
||||
|
||||
# Implementation
|
||||
|
||||
TO BE ADDED
|
||||
|
||||
# Copyright
|
||||
|
||||
Copyright and related rights waived via CC0.
|
|
@ -106,7 +106,7 @@ function textFor(bytes32 _code) external view returns (bool _wasFound, string _t
|
|||
|
||||
### String Format
|
||||
|
||||
All strings MUST be encoded as [UTF-8](http://www.ietf.org/rfc/rfc3629.txt).
|
||||
All strings MUST be encoded as [UTF-8](https://www.ietf.org/rfc/rfc3629.txt).
|
||||
|
||||
```solidity
|
||||
"Špeĉiäl chârãçtérs are permitted"
|
||||
|
@ -117,7 +117,7 @@ All strings MUST be encoded as [UTF-8](http://www.ietf.org/rfc/rfc3629.txt).
|
|||
|
||||
### Templates
|
||||
|
||||
Template strings are allowed, and MUST follow the [ANSI C `printf`](http://pubs.opengroup.org/onlinepubs/009696799/utilities/printf.html) conventions.
|
||||
Template strings are allowed, and MUST follow the [ANSI C `printf`](https://pubs.opengroup.org/onlinepubs/009696799/utilities/printf.html) conventions.
|
||||
|
||||
```solidity
|
||||
"Satoshi's true identity is %s"
|
||||
|
@ -155,7 +155,7 @@ A very viable alternative is to store text off chain, with a pointer to the tran
|
|||
|
||||
UTF-8 is the most widely used encoding at time of writing. It contains a direct embedding of ASCII, while providing characters for most natural languages, emoji, and special characters.
|
||||
|
||||
Please see the [UTF-8 Everywhere Manifesto](http://utf8everywhere.org/) for more information.
|
||||
Please see the [UTF-8 Everywhere Manifesto](https://utf8everywhere.org/) for more information.
|
||||
|
||||
### When No Text is Found
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ title: Bitwise shifting instructions in EVM
|
|||
author: Alex Beregszaszi (@axic), Paweł Bylica
|
||||
type: Standards Track
|
||||
category: Core
|
||||
status: Accepted
|
||||
status: Final
|
||||
created: 2017-02-13
|
||||
---
|
||||
|
||||
|
|
|
@ -68,24 +68,37 @@ Test cases include crafted as well as real-world samples of vulnerable smart con
|
|||
|
||||
1. Source code of a smart contract sample; e.g. Solidity, Vyper, etc.
|
||||
2. Compiled asset from an EVM compiler in machine readable format; e.g. JSON or ethPM.
|
||||
3. Test result configuration that describes which and how many instances of a weakness variant can be found in a given sample. The YAML schema for the proposed test result configuration is listed below.
|
||||
3. Test result configuration that describes which and how many instances of a weakness variant can be found in a given sample. The YAML schema for the proposed test case configuration is listed below.
|
||||
|
||||
```YAML
|
||||
description:
|
||||
type: string
|
||||
required: true
|
||||
issues:
|
||||
- id:
|
||||
title: SWC config
|
||||
type: object
|
||||
required:
|
||||
- description
|
||||
- issues
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
required: true
|
||||
count:
|
||||
type: number
|
||||
required: true
|
||||
locations:
|
||||
- bytecode_offsets:
|
||||
- type: number
|
||||
line_numbers:
|
||||
- type: number
|
||||
issues:
|
||||
title: Issues
|
||||
type: array
|
||||
items:
|
||||
title: Issue
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- count
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
count:
|
||||
type: number
|
||||
locations:
|
||||
items:
|
||||
bytecode_offsets:
|
||||
type: object
|
||||
line_numbers:
|
||||
type: object
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,7 @@ requires: 191
|
|||
A protocol for aggregating digital identity information that's broadly interoperable with existing, proposed, and hypothetical future digital identity standards.
|
||||
|
||||
## Abstract
|
||||
This EIP proposes an identity management and aggregation framework on the Ethereum blockchain. It allows entities to claim an `Identity` via a singular `Identity Registry` smart contract, associate it with Ethereum addresses in a variety of meaningful ways, and use it to interact with smart contracts. This enables arbitrarily complex identity-related functionality. Notably (among other features) ERC-1484 `Identities`: are self-sovereign, can natively support [ERC-725](https://github.com/hydrogen-dev/ERC-1484/tree/master/contracts/examples/Resolvers/ERC725) and [ERC-1056](https://github.com/hydrogen-dev/ERC-1484/tree/master/contracts/examples/Resolvers/ERC1056) identities, are [DID compliant](https://github.com/hydrogen-dev/ERC-1484/blob/master/best-practices/DID-Method.md), and can be fully powered by [meta-transactions](https://github.com/hydrogen-dev/ERC-1484/tree/master/contracts/examples/Providers/MetaTransactions).
|
||||
This EIP proposes an identity management and aggregation framework on the Ethereum blockchain. It allows entities to claim an `Identity` via a singular `Identity Registry` smart contract, associate it with Ethereum addresses in a variety of meaningful ways, and use it to interact with smart contracts. This enables arbitrarily complex identity-related functionality. Notably (among other features) ERC-1484 `Identities`: are self-sovereign, can natively support [ERC-725](https://github.com/NoahZinsmeister/ERC-1484/tree/master/contracts/examples/Resolvers/ERC725) and [ERC-1056](https://github.com/NoahZinsmeister/ERC-1484/tree/master/contracts/examples/Resolvers/ERC1056) identities, are [DID compliant](https://github.com/NoahZinsmeister/ERC-1484/blob/master/best-practices/DID-Method.md), and can be fully powered by [meta-transactions](https://github.com/NoahZinsmeister/ERC-1484/tree/master/contracts/examples/Providers/MetaTransactions).
|
||||
|
||||
## Motivation
|
||||
Emerging identity standards and related frameworks proposed by the Ethereum community (including ERCs/EIPs [725](https://github.com/ethereum/EIPs/issues/725), [735](https://github.com/ethereum/EIPs/issues/735), [780](https://github.com/ethereum/EIPs/issues/780), [1056](https://github.com/ethereum/EIPs/issues/1056), etc.) define and instrumentalize digital identity in a variety of ways. As existing approaches mature, new standards emerge, and isolated, non-standard approaches to identity develop, coordinating on identity will become increasingly burdensome for blockchain users and developers, and involve the unnecessary duplication of work.
|
||||
|
@ -51,7 +51,7 @@ A digital identity in this proposal can be viewed as an omnibus account, contain
|
|||
The protocol revolves around claiming an `Identity` and managing `Associated Addresses`, `Providers` and `Resolvers`. Identities can delegate much or all of this responsibility to one or more `Providers`, or perform it directly from an `Associated Address`. `Associated Addresses`/`Providers` may add and remove `Resolvers` and `Providers` indiscriminately. `Associated Addresses` may only be added or removed with the appropriate permission.
|
||||
|
||||
### Identity Registry
|
||||
The `Identity Registry` contains functionality to create new `Identities` and for existing `Identities` to manage their `Associated Addresses`, `Providers`, and `Resolvers`. It is important to note that this registry fundamentally requires transactions for every aspect of building out an `Identity`. However, recognizing the importance of accessibility to dApps and identity applications, we empower `Providers` to build out `Identities` on the behalf of users, without requiring users to pay gas costs. An example of this pattern, often referred to as a meta transactions, can be [seen in the reference implementation](https://github.com/hydrogen-dev/ERC-1484/tree/master/contracts/examples/Providers/MetaTransactions).
|
||||
The `Identity Registry` contains functionality to create new `Identities` and for existing `Identities` to manage their `Associated Addresses`, `Providers`, and `Resolvers`. It is important to note that this registry fundamentally requires transactions for every aspect of building out an `Identity`. However, recognizing the importance of accessibility to dApps and identity applications, we empower `Providers` to build out `Identities` on the behalf of users, without requiring users to pay gas costs. An example of this pattern, often referred to as a meta transactions, can be [seen in the reference implementation](https://github.com/NoahZinsmeister/ERC-1484/tree/master/contracts/examples/Providers/MetaTransactions).
|
||||
|
||||
Due to the fact that multiple addresses can be associated with a given identity (though not the reverse), `Identities` are denominated by `EIN`. This `uint` identifier can be encoded in QR format or mapped to more user-friendly formats, such as a `string`, in registries at the `Provider` or `Resolver` level.
|
||||
|
||||
|
@ -63,7 +63,7 @@ The address management function consists of trustlessly connecting multiple user
|
|||
|
||||
Trustlessness in the address management function is achieved through a robust permissioning scheme. To add an `Associated Address` to an `Identity`, implicit permission from a transaction sender or explicit permission from a signature is required from 1) an address already within the registry and 2) an address to be claimed. Importantly, the transaction need not come from any particular address, as long as permission is established, which allows not only users but third parties (companies, governments, etc.) to bear the overhead of managing identities. To prevent a compromised `Associated Address` from unilaterally removing other `Associated Addresses`, it's only possible to remove an `Associated Address` by transacting or producing a signature from it.
|
||||
|
||||
All signatures required in ERC-1484 are designed per the [ERC-191](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-191.md) v0 specification. To avoid replay attacks, all signatures must include a timestamp within a rolling lagged window of the current `block.timestamp`. For more information, see this [best practices document](https://github.com/hydrogen-dev/ERC-1484/blob/master/best-practices/VerifyingSignatures.md) in the reference implementation.
|
||||
All signatures required in ERC-1484 are designed per the [ERC-191](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-191.md) v0 specification. To avoid replay attacks, all signatures must include a timestamp within a rolling lagged window of the current `block.timestamp`. For more information, see this [best practices document](https://github.com/NoahZinsmeister/ERC-1484/blob/master/best-practices/VerifyingSignatures.md) in the reference implementation.
|
||||
|
||||
### Provider Management
|
||||
While the protocol allows users to directly call identity management functions, it also aims to be more robust and future-proof by allowing `Providers`, typically smart contracts, to perform identity management functions on a user's behalf. A `Provider` set by an `Identity` can perform address management and resolver management functions by passing a user's `EIN` in function calls.
|
||||
|
@ -104,7 +104,7 @@ We find that at a protocol layer, identities should not rely on specific claim o
|
|||
The main criticism of existing identity solutions is that they're overly restrictive. We aim to limit requirements, keep identities modular and future-proof, and remain un-opinionated regarding any functionality a particular identity component may have. This proposal gives users the option to interact on the blockchain using an robust `Identity` rather than just an address.
|
||||
|
||||
## Implementation
|
||||
**The reference implementation for ERC-1484 may be found in [hydrogen-dev/ERC-1484](https://github.com/hydrogen-dev/ERC-1484).**
|
||||
**The reference implementation for ERC-1484 may be found in [NoahZinsmeister/ERC-1484](https://github.com/NoahZinsmeister/ERC-1484).**
|
||||
|
||||
#### identityExists
|
||||
|
||||
|
@ -535,7 +535,7 @@ interface IdentityRegistryInterface {
|
|||
`Identities` established under this standard consist of existing Ethereum addresses; accordingly, there are no backwards compatibility issues. Deployed, non-upgradeable smart contracts that wish to become `Resolvers` for `Identities` will need to write wrapper contracts that resolve addresses to `EIN`-denominated `Identities`.
|
||||
|
||||
## Additional References
|
||||
- [ERC-1484 Reference Implementation](https://github.com/hydrogen-dev/ERC-1484)
|
||||
- [ERC-1484 Reference Implementation](https://github.com/NoahZinsmeister/ERC-1484)
|
||||
- [ERC-191 Signatures](https://github.com/ethereum/EIPs/issues/191)
|
||||
- [ERC-725 Identities](https://github.com/ethereum/EIPs/issues/725)
|
||||
- [ERC-1056 Identities](https://github.com/ethereum/EIPs/issues/1056)
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
---
|
||||
eip: 1485
|
||||
title: TEthashV1
|
||||
author: trustfarm (KT Ahn - 안씨아저씨) <trustfarm.info@gmail.com>, <cpplover@trustfarm.net>,
|
||||
discussions-to: https://ethereum-magicians.org/t/anti-eth-asic-mining-eip-1488-pr/1807
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2018-11-01
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
This EIP modifies ethash in order to break ASIC miners specialized for the current ethash mining algorithm.
|
||||
|
||||
## Abstract
|
||||
This EIP pursue "obsolete current ASIC miners" by modifying PoW algorithm in a very low risk manner and update to latest hash algorithm from deprecated FNV Hash algorithms.
|
||||
|
||||
Following TEthashV1 algorithm suggests safe transition of PoW algorithms and secure the FNV Algorithm in MIX Parts.
|
||||
|
||||
## Motivation
|
||||
Provide original Ethash proof of work verification with minimal set of changes by updating FNV0 algorithm
|
||||
|
||||
## Specification
|
||||
|
||||
#### 1. Reference materials on ETHASH FNV0
|
||||
|
||||
#### Where FNV Applied on ETHASH
|
||||
|
||||
- In [ETHASH](https://github.com/ethereum/wiki/wiki/Ethash) , FNV Hash is used on
|
||||
* 1) On data aggregation function, MIX parts.
|
||||
|
||||
* Ethash Algorithm
|
||||
|
||||
```
|
||||
Header + Nonce
|
||||
|
|
||||
Keccak
|
||||
|
|
||||
**[MIX 0]** --> **[DAG Page]**
|
||||
| |
|
||||
Mixing <--|
|
||||
...
|
||||
|
|
||||
**[Mix 63]**
|
||||
|
|
||||
|-----> Mix64 [Process] ---> Mix Digest [32B]
|
||||
```
|
||||
|
||||
* FNV used in DAG Generation
|
||||
and Mixing for random access or DAG Page.
|
||||
|
||||
#### 2. Current applied Ethash FNV hash implementation is deprecated now.
|
||||
|
||||
[FNV-0_hash (deprecated)](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-0_hash_(deprecated))
|
||||
|
||||
It is a simple way of hashing algorithm
|
||||
|
||||
```
|
||||
hash = 0
|
||||
for each byte_of_data to be hashed
|
||||
hash = hash × FNV_prime
|
||||
hash = hash XOR octet_of_data
|
||||
return hash
|
||||
```
|
||||
|
||||
When analysed FNV-0 , there's very weak [avalanche effect](https://simple.wikipedia.org/wiki/Avalanche_effect), when hash input changes on 1~2bits. refer [FNV-Analysis reference section](https://github.com/tao-foundation/FNV-Analysis#how-to-test-and-analysis-reference-test-code)
|
||||
|
||||
We need to research and apply newer FNV hash or short message hash algorithm.
|
||||
|
||||
#### 3. FNV1A hash algorithm description
|
||||
|
||||
Previous proposed algorithm based on FNV1 [EIP-1355](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1355.md)
|
||||
|
||||
There's a implementation that looks like "Missing Offset Bias" at **FNV1A**.
|
||||
|
||||
Quotation of [original algorithm FNV1A](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash)
|
||||
```
|
||||
use hash offset
|
||||
FNV-1a hash
|
||||
The FNV-1a hash differs from the FNV-1 hash by only the order in which the multiply and XOR is performed:[8][10]
|
||||
|
||||
hash = FNV_offset_basis
|
||||
for each byte_of_data to be hashed
|
||||
hash = hash XOR byte_of_data
|
||||
hash = hash × FNV_prime
|
||||
return hash
|
||||
```
|
||||
|
||||
FNV_offset_basis and computation order change of xor and multiplication Makes one more xor and multiply computation, but more secure hash effects than FNV0.
|
||||
and make dispersion boundary condition (0, even number, ..) by using of Prime Number.
|
||||
|
||||
#### 4. Real Implementation for FNV1A
|
||||
|
||||
Consider real computation resources, in TEthashV1 uses hash byte_of_data to 4bytes aligned data.
|
||||
|
||||
In TETHashV1, Adapts fully follow the FNV1A implementation.
|
||||
|
||||
- TETHASHV1 FNV1A implementation
|
||||
|
||||
Followings are reference implementation of FNV1A adapted in TETHashV1.
|
||||
|
||||
```cpp
|
||||
// Reference Pseudo c/cpp implementation
|
||||
|
||||
#define FNV_PRIME 0x01000193U
|
||||
#define FNV_OFFSET_BASIS 0x811c9dc5U
|
||||
|
||||
#define fnv1a(x, y) ((((FNV_OFFSET_BASIS^(x))*FNV_PRIME) ^ (y)) * FNV_PRIME)
|
||||
#define fnv1a_reduce(a,b,c,d) (fnv1a(fnv1a(fnv1a(a, b), c), d))
|
||||
```
|
||||
|
||||
Another Byte aligned implementation of FNV1A , call to FNV1c
|
||||
|
||||
```cpp
|
||||
#define FNV_PRIME 0x01000193U
|
||||
#define FNV_OFFSET_BASIS 0x811c9dc5U
|
||||
|
||||
#define fnv1i(x) ( (( (( (( \
|
||||
( ((FNV_OFFSET_BASIS)^( ((x)>>24)&0x000000ff )) * FNV_PRIME) \
|
||||
^ (((x)>>16 )&0x000000ff)) * FNV_PRIME) \
|
||||
^ (((x)>>8 )&0x000000ff)) * FNV_PRIME) \
|
||||
^ (((x) )&0x000000ff)) * FNV_PRIME) \
|
||||
)
|
||||
#define fnv1c(x, y) ((fnv1i(x) ^ (y)) * FNV_PRIME)
|
||||
```
|
||||
|
||||
#### 5. [FNV-Analysis](https://github.com/tao-foundation/FNV-Analysis)
|
||||
FNV Mix Algorithm Analysis for TEthashV1
|
||||
|
||||
#### How to test and analysis reference test code.
|
||||
|
||||
You can compile it with simple in terminal.
|
||||
No additional library needs,
|
||||
|
||||
```
|
||||
gcc -o fnvtest fnvcltest.c
|
||||
```
|
||||
|
||||
And You can execute it
|
||||
```
|
||||
fnvtest
|
||||
|
||||
F(00,00)::VEC(0, 0, ffffffff, 0):: FNV :00000000, DF=00000000(00) DS(00000000), FNV1 :00000000, DF=00000000(00) DS(00000000), FNV1a:117697cd, DF=117697cd(17) DS(117697cd), FNV1c:1210d00f, DF=127f8dbf(20) DS(11a1725f), F___RC=efe1b9c4, DF:efe1b9c4(19) , F1__RC=deb68dfe, DF:deb68dfe(22) , F1A_RC=99bad28b, DF:99bad28b(17) , F1C_RC=e29fa497, DF:e29fa497(18)
|
||||
F(00,01)::VEC(0, 1, ffffffff, 0):: FNV :00000001, DF=00000001(01) DS(00000001), FNV1 :01000193, DF=01000193(06) DS(01000193), FNV1a:1076963a, DF=010001f7(09) DS(01000193), FNV1c:1110ce7c, DF=03001e73(11) DS(01000193), F___RC=fefffe6d, DF:111e47a9(14) , F1__RC=d9fd8597, DF:074b0869(12) , F1A_RC=72c287e0, DF:eb78556b(19) , F1C_RC=6b6991ef, DF:89f63578(17)
|
||||
F(00,02)::VEC(0, 2, ffffffff, 0):: FNV :00000002, DF=00000003(02) DS(00000001), FNV1 :02000326, DF=030002b5(08) DS(01000193), FNV1a:0f7694a7, DF=1f00029d(11) DS(01000193), FNV1c:1410d335, DF=05001d49(09) DS(030004b9), F___RC=d8fd8404, DF:26027a69(13) , F1__RC=9b16d24c, DF:42eb57db(19) , F1A_RC=c17f0ecb, DF:b3bd892b(18) , F1C_RC=a5be8e78, DF:ced71f97(21)
|
||||
F(00,03)::VEC(0, 3, ffffffff, 0):: FNV :00000003, DF=00000001(01) DS(00000001), FNV1 :030004b9, DF=0100079f(10) DS(01000193), FNV1a:0e769314, DF=010007b3(09) DS(01000193), FNV1c:1310d1a2, DF=07000297(09) DS(01000193), F___RC=b2fb099b, DF:6a068d9f(16) , F1__RC=5c301f01, DF:c726cd4d(17) , F1A_RC=94cf402e, DF:55b04ee5(16) , F1C_RC=aea1a025, DF:0b1f2e5d(17)
|
||||
F(00,04)::VEC(0, 4, ffffffff, 0):: FNV :00000004, DF=00000007(03) DS(00000001), FNV1 :0400064c, DF=070002f5(10) DS(01000193), FNV1a:0d769181, DF=03000295(07) DS(01000193), FNV1c:0e10c9c3, DF=1d001861(09) DS(050007df), F___RC=8cf88f32, DF:3e0386a9(14) , F1__RC=1d496bb6, DF:417974b7(17) , F1A_RC=89401d59, DF:1d8f5d77(20) , F1C_RC=e4e96c7c, DF:4a48cc59(13)
|
||||
F(00,05)::VEC(0, 5, ffffffff, 0):: FNV :00000005, DF=00000001(01) DS(00000001), FNV1 :050007df, DF=01000193(06) DS(01000193), FNV1a:0c768fee, DF=01001e6f(11) DS(01000193), FNV1c:0d10c830, DF=030001f3(09) DS(01000193), F___RC=66f614c9, DF:ea0e9bfb(20) , F1__RC=de62b86b, DF:c32bd3dd(19) , F1A_RC=346e222c, DF:bd2e3f75(21) , F1C_RC=502e5f82, DF:b4c733fe(20)
|
||||
F(00,06)::VEC(0, 6, ffffffff, 0):: FNV :00000006, DF=00000003(02) DS(00000001), FNV1 :06000972, DF=03000ead(10) DS(01000193), FNV1a:0b768e5b, DF=070001b5(09) DS(01000193), FNV1c:1010cce9, DF=1d0004d9(10) DS(030004b9), F___RC=40f39a60, DF:26058ea9(13) , F1__RC=9f7c0520, DF:411ebd4b(16) , F1A_RC=b376a527, DF:8718870b(13) , F1C_RC=1241a9a4, DF:426ff626(17)
|
||||
F(00,07)::VEC(0, 7, ffffffff, 0):: FNV :00000007, DF=00000001(01) DS(00000001), FNV1 :07000b05, DF=01000277(08) DS(01000193), FNV1a:0a768cc8, DF=01000293(06) DS(01000193), FNV1c:0f10cb56, DF=1f0007bf(15) DS(01000193), F___RC=1af11ff7, DF:5a028597(13) , F1__RC=609551d5, DF:ffe954f5(22) , F1A_RC=14293bea, DF:a75f9ecd(21) , F1C_RC=49d34bba, DF:5b92e21e(16)
|
||||
F(00,08)::VEC(0, 8, ffffffff, 0):: FNV :00000008, DF=0000000f(04) DS(00000001), FNV1 :08000c98, DF=0f00079d(12) DS(01000193), FNV1a:09768b35, DF=030007fd(12) DS(01000193), FNV1c:1a10dca7, DF=150017f1(12) DS(0b001151), F___RC=f4eea58e, DF:ee1fba79(21) , F1__RC=21ae9e8a, DF:413bcf5f(19) , F1A_RC=eeebb7a5, DF:fac28c4f(17) , F1C_RC=7da04f47, DF:347304fd(16)
|
||||
F(00,09)::VEC(0, 9, ffffffff, 0):: FNV :00000009, DF=00000001(01) DS(00000001), FNV1 :09000e2b, DF=010002b3(07) DS(01000193), FNV1a:087689a2, DF=01000297(07) DS(01000193), FNV1c:1910db14, DF=030007b3(10) DS(01000193), F___RC=ceec2b25, DF:3a028eab(14) , F1__RC=e2c7eb3f, DF:c36975b5(18) , F1A_RC=54e1aef8, DF:ba0a195d(15) , F1C_RC=d425e1af, DF:a985aee8(16)
|
||||
F(00,0a)::VEC(0, a, ffffffff, 0):: FNV :0000000a, DF=00000003(02) DS(00000001), FNV1 :0a000fbe, DF=03000195(07) DS(01000193), FNV1a:0776880f, DF=0f0001ad(10) DS(01000193), FNV1c:1c10dfcd, DF=050004d9(08) DS(030004b9), F___RC=a8e9b0bc, DF:66059b99(15) , F1__RC=a3e137f4, DF:4126dccb(15) , F1A_RC=213fcd63, DF:75de639b(20) , F1C_RC=7e1d2751, DF:aa38c6fe(18)
|
||||
F(00,0b)::VEC(0, b, ffffffff, 0):: FNV :0000000b, DF=00000001(01) DS(00000001), FNV1 :0b001151, DF=01001eef(12) DS(01000193), FNV1a:0676867c, DF=01000e73(09) DS(01000193), FNV1c:1b10de3a, DF=070001f7(11) DS(01000193), F___RC=82e73653, DF:2a0e86ef(16) , F1__RC=64fa84a9, DF:c71bb35d(19) , F1A_RC=5598ce46, DF:74a70325(14) , F1C_RC=6400c630, DF:1a1de161(14)
|
||||
F(00,0c)::VEC(0, c, ffffffff, 0):: FNV :0000000c, DF=00000007(03) DS(00000001), FNV1 :0c0012e4, DF=070003b5(10) DS(01000193), FNV1a:057684e9, DF=03000295(07) DS(01000193), FNV1c:1610d65b, DF=0d000861(07) DS(050007df), F___RC=5ce4bbea, DF:de038db9(17) , F1__RC=2613d15e, DF:42e955f7(18) , F1A_RC=6a220ff1, DF:3fbac1b7(20) , F1C_RC=6e781da4, DF:0a78db94(15)
|
||||
F(00,0d)::VEC(0, d, ffffffff, 0):: FNV :0000000d, DF=00000001(01) DS(00000001), FNV1 :0d001477, DF=01000693(07) DS(01000193), FNV1a:04768356, DF=010007bf(11) DS(01000193), FNV1c:1510d4c8, DF=03000293(07) DS(01000193), F___RC=36e24181, DF:6a06fa6b(17) , F1__RC=e72d1e13, DF:c13ecf4d(18) , F1A_RC=168d4944, DF:7caf46b5(19) , F1C_RC=65bbcfa1, DF:0bc3d205(13)
|
||||
F(00,0e)::VEC(0, e, ffffffff, 0):: FNV :0000000e, DF=00000003(02) DS(00000001), FNV1 :0e00160a, DF=0300027d(09) DS(01000193), FNV1a:037681c3, DF=07000295(08) DS(01000193), FNV1c:1810d981, DF=0d000d49(09) DS(030004b9), F___RC=10dfc718, DF:263d8699(15) , F1__RC=a8466ac8, DF:4f6b74db(20) , F1A_RC=93e667bf, DF:856b2efb(19) , F1C_RC=76f80ee3, DF:1343c142(11)
|
||||
F(00,0f)::VEC(0, f, ffffffff, 0):: FNV :0000000f, DF=00000001(01) DS(00000001), FNV1 :0f00179d, DF=01000197(07) DS(01000193), FNV1a:02768030, DF=010001f3(08) DS(01000193), FNV1c:1710d7ee, DF=0f000e6f(13) DS(01000193), F___RC=eadd4caf, DF:fa028bb7(17) , F1__RC=695fb77d, DF:c119ddb5(17) , F1A_RC=0f485682, DF:9cae313d(17) , F1C_RC=3667e8dc, DF:409fe63f(18)
|
||||
F(00,10)::VEC(0, 10, ffffffff, 0):: FNV :00000010, DF=0000001f(05) DS(00000001), FNV1 :10001930, DF=1f000ead(13) DS(01000193), FNV1a:01767e9d, DF=0300fead(14) DS(01000193), FNV1c:0210b6df, DF=15006131(09) DS(1500210f), F___RC=c4dad246, DF:2e079ee9(17) , F1__RC=2a790432, DF:4326b34f(16) , F1A_RC=d10adebd, DF:de42883f(16) , F1C_RC=1ce48e12, DF:2a8366ce(15)
|
||||
```
|
||||
|
||||
`F(00,01)` : is input x,y
|
||||
|
||||
`VEC(0, 1, ffffffff, 0)` : is `fnv_reduce` input vector (a,b,c,d)
|
||||
|
||||
`FNV :00000001, DF=00000001(01) DS(00000001)` :
|
||||
* `FNV(00,01)` result is 00000001 ,
|
||||
* `DF` : is changed bitcounts, compared with previous outputs, in this case prev[00,00] current[00,01] input is 1bit changed, and output result 1bit changed.
|
||||
* `DS` : is distances of previous result and current result , ABS(prev_fnvresult,current_fnvresult).
|
||||
|
||||
** Basically, `DF` is higher is best on hash algorithm.
|
||||
|
||||
`F___RC=fefffe6d, DF:111e47a9(14)` : `fnv_reduce = fnv(fnv(fnv(a,b),c),d) ` result is fefffe6d , and Different Bits counts are `14` bits.
|
||||
|
||||
|
||||
## Rationale
|
||||
|
||||
In case of ethash algorithm, it can't prevent ASIC forever.
|
||||
|
||||
And, current ethash algorithm's FNV function is depricated.
|
||||
|
||||
So, It needs to be upgraded and it will make current ethash based ASICs obsolete.
|
||||
|
||||
And current TETHASHV1 FNV1A implementation is based on most of ethash , which is verified for a long time.
|
||||
|
||||
Another propose of big differencing the Ethash algorithm need to crypto analysis for a long times and need to GPU code optimization times.
|
||||
|
||||
**Verification and Optimization timeline Examples**
|
||||
|
||||
orignal ethminer (2015) -> claymore optimized miner (2016) [1year]
|
||||
|
||||
genoil ethminer (2015) -> ethereum-mining/ethminer (2017) [2year]
|
||||
|
||||
## Test Results::
|
||||
|
||||
Tethash miner has 2~3% of hashrate degrade on GPU, due to more core computation time.
|
||||
|
||||
## Copyright
|
||||
|
||||
This work is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-nc-sa/4.0/).
|
|
@ -0,0 +1,474 @@
|
|||
---
|
||||
eip: 1538
|
||||
title: Transparent Contract Standard
|
||||
author: Nick Mudge <nick@mokens.io>
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/1538
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
created: 2018-10-31
|
||||
---
|
||||
|
||||
|
||||
## Simple Summary
|
||||
<!--"If you can't explain it simply, you don't understand it well enough." Provide a simplified and layman-accessible explanation of the EIP.-->
|
||||
This standard provides a contract architecture that makes upgradeable contracts flexible, unlimited in size, and transparent.
|
||||
|
||||
A transparent contract publicly documents the full history of all changes made to it.
|
||||
|
||||
All changes to a transparent contract are reported in a standard format.
|
||||
|
||||
## Abstract
|
||||
<!--A short (~200 word) description of the technical issue being addressed.-->
|
||||
A transparent contract is a proxy contract design pattern that provides the following:
|
||||
|
||||
1. A way to add, replace and remove multiple functions of a contract atomically (at the same time).
|
||||
1. Standard events to show what functions are added, replaced and removed from a contract, and why the changes are made.
|
||||
2. A standard way to query a contract to discover and retrieve information about all functions exposed by it.
|
||||
3. Solves the 24KB maximum contract size limitation, making the maximum contract size of a transparent contract practically unlimited. This standard makes the worry about contract size a thing of the past.
|
||||
4. Enables an upgradeable contract to become immutable in the future if desired.
|
||||
|
||||
## Motivation
|
||||
<!--The motivation is critical for EIPs that want to change the Ethereum protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the EIP solves. EIP submissions without sufficient motivation may be rejected outright.-->
|
||||
A fundamental benefit of Ethereum contracts is that their code is immutable, thereby acquiring trust by trustlessness. People do not have to trust others if it is not possible for a contract to be changed.
|
||||
|
||||
However, a fundamental problem with trustless contracts that cannot be changed is that they cannot be changed.
|
||||
|
||||
#### Bugs
|
||||
|
||||
Bugs and security vulnerabilities are unwittingly written into immutable contracts that ruin them.
|
||||
|
||||
#### Improvements
|
||||
|
||||
Immutable, trustless contracts cannot be improved, resulting in increasingly inferior contracts over time.
|
||||
|
||||
Contract standards evolve, new ones come out. People, groups and organizations learn over time what people want and what is better and what should be built next. Contracts that cannot be improved not only hold back the authors that create them, but everybody who uses them.
|
||||
|
||||
#### Upgradeable Contracts vs. Centralized Private Database
|
||||
Why have an upgradeable contract instead of a centralized, private, mutable database?
|
||||
Here are some reasons:
|
||||
1. Because of the openness of storage data and verified code, it is possible to show a provable history of trustworthiness.
|
||||
2. Because of the openness, bad behavior can be spotted and reported when it happens.
|
||||
3. Independent security and domain experts can review the change history of contracts and vouch for their history of trustworthiness.
|
||||
4. It is possible for an upgradeable contract to become immutable and trustless.
|
||||
5. An upgradeable contract can have parts of it that are not upgradeable and so are partially immutable and trustless.
|
||||
|
||||
#### Immutability
|
||||
|
||||
In some cases immutable, trustless contracts are the right fit. This is the case when a contract is only needed for a short time or it is known ahead of time that there will never be any reason to change or improve it.
|
||||
|
||||
### Middle Ground
|
||||
|
||||
Transparent contracts provide a middle ground between immutable trustless contracts that can't be improved and upgradeable contracts that can't be trusted.
|
||||
|
||||
### Purposes
|
||||
|
||||
1. Create upgradeable contracts that earn trust by showing a provable history of trustworthiness.
|
||||
2. Document the development of contracts so their development and change is provably public and can be understood.
|
||||
3. Create upgradeable contracts that can become immutable in the future if desired.
|
||||
4. Create contracts that are not limited by a max size.
|
||||
|
||||
### Benefits & Use Cases
|
||||
This standard is for use cases that benefit from the following:
|
||||
1. The ability to add, replace or remove multiple functions of a contract atomically (at the same time).
|
||||
2. Each time a function is added, replaced or removed, it is documented with events.
|
||||
3. Build trust over time by showing all changes made to a contract.
|
||||
4. Unlimited contract size.
|
||||
5. The ability to query information about functions currently supported by the contract.
|
||||
6. One contract address that provides all needed functionality and never needs to be replaced by another contract address.
|
||||
7. The ability for a contract to be upgradeable for a time, and then become immutable.
|
||||
8. Add trustless guarantees to a contract with "unchangeable functions".
|
||||
|
||||
### New Software Possibilities
|
||||
|
||||
This standard enables a form of contract version control software to be written.
|
||||
|
||||
Software and user interfaces can be written to filter the `FunctionUpdate` and `CommitMessage` events of a contract address. Such software can show the full history of changes of any contract that implements this standard.
|
||||
|
||||
User interfaces and software can also use this standard to assist or automate changes of contracts.
|
||||
|
||||
## Specification
|
||||
<!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (go-ethereum, parity, cpp-ethereum, ethereumj, ethereumjs, and [others](https://github.com/ethereum/wiki/wiki/Clients)).-->
|
||||
|
||||
> **Note:**
|
||||
The solidity `delegatecall` opcode enables a contract to execute a function from another contract, but it is executed as if the function was from the calling contract. Essentially `delegatecall` enables a contract to "borrow" another contract's function. Functions executed with `delegatecall` affect the storage variables of the calling contract, not the contract where the functions are defined.
|
||||
|
||||
### General Summary
|
||||
|
||||
A transparent contract delegates or forwards function calls to it to other contracts using `delegatecode`.
|
||||
|
||||
A transparent contract has an `updateContract` function that enables multiple functions to be added, replaced or removed.
|
||||
|
||||
An event is emitted for every function that is added, replaced or removed so that all changes to a contract can be tracked in a standard way.
|
||||
|
||||
A transparent contract is a contract that implements and complies with the design points below.
|
||||
|
||||
### Terms
|
||||
|
||||
1. In this standard a **delegate contract** is a contract that a transparent contract fallback function forwards function calls to using `delegatecall`.
|
||||
2. In this standard an **unchangeable function** is a function that is defined directly in a transparent contract and so cannot be replaced or removed.
|
||||
|
||||
### Design Points
|
||||
|
||||
A contract is a transparent contract if it implements the following design points:
|
||||
|
||||
1. A transparent contract is a contract that contains a fallback function, a constructor, and zero or more unchangeable functions that are defined directly within it.
|
||||
2. The constructor of a transparent contract associates the `updateContract` function with a contract that implements the ERC1538 interface. The `updateContract` function can be an "unchangeable function" that is defined directly in the transparent contract or it can be defined in a delegate contract. Other functions can also be associated with contracts in the constructor.
|
||||
3. After a transparent contract is deployed functions are added, replaced and removed by calling the `updateContract` function.
|
||||
4. The `updateContract` function associates functions with contracts that implement those functions, and emits the `CommitMessage` and `FunctionUpdate` events that document function changes.
|
||||
5. The `FunctionUpdate` event is emitted for each function that is added, replaced or removed. The `CommitMessage` event is emitted one time for each time the `updateContract` function is called and is emitted after any `FunctionUpdate` events are emitted.
|
||||
6. The `updateContract` function can take a list of multiple function signatures in its `_functionSignatures` parameter and so add/replace/remove multiple functions at the same time.
|
||||
7. When a function is called on a transparent contract it executes immediately if it is an "unchangeable function". Otherwise the fallback function is executed. The fallback function finds the delegate contract associated with the function and executes the function using `delegatecall`. If there is no delegate contract for the function then execution reverts.
|
||||
8. The source code of a transparent contract and all delegate contracts used by it are publicly viewable and verified.
|
||||
|
||||
The transparent contract address is the address that users interact with. The transparent contract address never changes. Only delegate addresses can change by using the `updateContracts` function.
|
||||
|
||||
Typically some kind of authentication is needed for adding/replacing/removing functions from a transparent contract, **however the scheme for authentication or ownership is not part of this standard**.
|
||||
|
||||
### Example
|
||||
|
||||
Here is an example of an implementation of a transparent contract. Please note that the example below is an **example only. It is not the standard**. A contract is a transparent contract when it implements and complies with the design points listed above.
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.5.7;
|
||||
|
||||
contract ExampleTransparentContract {
|
||||
// owner of the contract
|
||||
address internal contractOwner;
|
||||
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
||||
|
||||
// maps functions to the delegate contracts that execute the functions
|
||||
// funcId => delegate contract
|
||||
mapping(bytes4 => address) internal delegates;
|
||||
|
||||
// maps each function signature to its position in the funcSignatures array.
|
||||
// signature => index+1
|
||||
mapping(bytes => uint256) internal funcSignatureToIndex;
|
||||
|
||||
event CommitMessage(string message);
|
||||
event FunctionUpdate(bytes4 indexed functionId, address indexed oldDelegate, address indexed newDelegate, string functionSignature);
|
||||
|
||||
// this is an example of an "unchangeable function".
|
||||
// return the delegate contract address for the supplied function signature
|
||||
function delegateAddress(string calldata _functionSignature) external view returns(address) {
|
||||
require(funcSignatureToIndex[bytes(_functionSignature)] != 0, "Function signature not found.");
|
||||
return delegates[bytes4(keccak256(bytes(_functionSignature)))];
|
||||
}
|
||||
|
||||
// add a function using the updateContract function
|
||||
// this is an internal helper function
|
||||
function addFunction(address _erc1538Delegate, address contractAddress, string memory _functionSignatures, string memory _commitMessage) internal {
|
||||
// 0x03A9BCCF == bytes4(keccak256("updateContract(address,string,string)"))
|
||||
bytes memory funcdata = abi.encodeWithSelector(0x03A9BCCF, contractAddress, _functionSignatures, _commitMessage);
|
||||
bool success;
|
||||
assembly {
|
||||
success := delegatecall(gas, _erc1538Delegate, add(funcdata, 0x20), mload(funcdata), funcdata, 0)
|
||||
}
|
||||
require(success, "Adding a function failed");
|
||||
}
|
||||
|
||||
constructor(address _erc1538Delegate) public {
|
||||
contractOwner = msg.sender;
|
||||
emit OwnershipTransferred(address(0), msg.sender);
|
||||
|
||||
// adding ERC1538 updateContract function
|
||||
bytes memory signature = "updateContract(address,string,string)";
|
||||
bytes4 funcId = bytes4(keccak256(signature));
|
||||
delegates[funcId] = _erc1538Delegate;
|
||||
emit FunctionUpdate(funcId, address(0), _erc1538Delegate, string(signature));
|
||||
emit CommitMessage("Added ERC1538 updateContract function at contract creation");
|
||||
|
||||
// associate "unchangeable functions" with this transparent contract address
|
||||
// prevents function selector clashes with delegate contract functions
|
||||
// uses the updateContract function
|
||||
string memory functions = "delegateAddress(string)";
|
||||
addFunction(_erc1538Delegate, address(this), functions, "Associating unchangeable functions");
|
||||
|
||||
// adding ERC1538Query interface functions
|
||||
functions = "functionByIndex(uint256)functionExists(string)delegateAddresses()delegateFunctionSignatures(address)functionById(bytes4)functionBySignature(string)functionSignatures()totalFunctions()";
|
||||
// "0x01234567891011121314" is an example address of an ERC1538Query delegate contract
|
||||
addFunction(_erc1538Delegate, 0x01234567891011121314, functions, "Adding ERC1538Query functions");
|
||||
|
||||
// additional functions could be added at this point
|
||||
}
|
||||
|
||||
// Making the fallback function payable makes it work for delegate contract functions
|
||||
// that are payable and not payable.
|
||||
function() external payable {
|
||||
// Delegate every function call to a delegate contract
|
||||
address delegate = delegates[msg.sig];
|
||||
require(delegate != address(0), "Function does not exist.");
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
calldatacopy(ptr, 0, calldatasize)
|
||||
let result := delegatecall(gas, delegate, ptr, calldatasize, 0, 0)
|
||||
let size := returndatasize
|
||||
returndatacopy(ptr, 0, size)
|
||||
switch result
|
||||
case 0 {revert(ptr, size)}
|
||||
default {return (ptr, size)}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
As can be seen in the above example, every function call is delegated to a delegate contract, unless the function is defined directly in the transparent contract (making it an unchangeable function).
|
||||
|
||||
The constructor function adds the `updateContract` function to the transparent contract, which is then used to add other functions to the transparent contract.
|
||||
|
||||
Each time a function is added to a transparent contract the events `CommitMessage` and `FunctionUpdate` are emitted to document exactly what functions where added or replaced and why.
|
||||
|
||||
The delegate contract that implements the `updateContract` function implements the following interface:
|
||||
### ERC1538 Interface
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.5.7;
|
||||
|
||||
/// @title ERC1538 Transparent Contract Standard
|
||||
/// @dev Required interface
|
||||
/// Note: the ERC-165 identifier for this interface is 0x61455567
|
||||
interface ERC1538 {
|
||||
/// @dev This emits when one or a set of functions are updated in a transparent contract.
|
||||
/// The message string should give a short description of the change and why
|
||||
/// the change was made.
|
||||
event CommitMessage(string message);
|
||||
|
||||
/// @dev This emits for each function that is updated in a transparent contract.
|
||||
/// functionId is the bytes4 of the keccak256 of the function signature.
|
||||
/// oldDelegate is the delegate contract address of the old delegate contract if
|
||||
/// the function is being replaced or removed.
|
||||
/// oldDelegate is the zero value address(0) if a function is being added for the
|
||||
/// first time.
|
||||
/// newDelegate is the delegate contract address of the new delegate contract if
|
||||
/// the function is being added for the first time or if the function is being
|
||||
/// replaced.
|
||||
/// newDelegate is the zero value address(0) if the function is being removed.
|
||||
event FunctionUpdate(
|
||||
bytes4 indexed functionId,
|
||||
address indexed oldDelegate,
|
||||
address indexed newDelegate,
|
||||
string functionSignature
|
||||
);
|
||||
|
||||
/// @notice Updates functions in a transparent contract.
|
||||
/// @dev If the value of _delegate is zero then the functions specified
|
||||
/// in _functionSignatures are removed.
|
||||
/// If the value of _delegate is a delegate contract address then the functions
|
||||
/// specified in _functionSignatures will be delegated to that address.
|
||||
/// @param _delegate The address of a delegate contract to delegate to or zero
|
||||
/// to remove functions.
|
||||
/// @param _functionSignatures A list of function signatures listed one after the other
|
||||
/// @param _commitMessage A short description of the change and why it is made
|
||||
/// This message is passed to the CommitMessage event.
|
||||
function updateContract(address _delegate, string calldata _functionSignatures, string calldata _commitMessage) external;
|
||||
}
|
||||
```
|
||||
### Function Signatures String Format
|
||||
|
||||
The text format for the `_functionSignatures` parameter is simply a string of function signatures. For example: `"myFirstFunction()mySecondFunction(string)"` This format is easy to parse and is concise.
|
||||
|
||||
Here is an example of calling the `updateContract` function that adds the ERC721 standard functions to a transparent contract:
|
||||
```javascript
|
||||
functionSignatures = "approve(address,uint256)balanceOf(address)getApproved(uint256)isApprovedForAll(address,address)ownerOf(uint256)safeTransferFrom(address,address,uint256)safeTransferFrom(address,address,uint256,bytes)setApprovalForAll(address,bool)transferFrom(address,address,uint256)"
|
||||
tx = await transparentContract.updateContract(erc721Delegate.address, functionSignatures, "Adding ERC721 functions");
|
||||
```
|
||||
|
||||
### Removing Functions
|
||||
|
||||
Functions are removed by passing `address(0)` as the first argument to the `updateContract` function. The list of functions that are passed in are removed.
|
||||
|
||||
### Source Code Verification
|
||||
|
||||
The transparent contract source code and the source code for the delegate contracts should be verified in a provable way by a third party source such as etherscan.io.
|
||||
<!--
|
||||
A transparent contract must implement the [ERC-165 Standard Interface Detection standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md) via a delegate contract by adding the `supportsInterface` function using the `updateContract` function. The interfaceID for the ERC1538 standard is `0x61455567`.
|
||||
-->
|
||||
|
||||
### Function Selector Clash
|
||||
A function selector clash occurs when a function is added to a contract that hashes to the same four-byte hash as an existing function. This is unlikely to occur but should be prevented in the implementation of the `updateContract` function. See the [reference implementation of ERC1538](https://github.com/mudgen/transparent-contracts-erc1538) to see an example of how function clashes can be prevented.
|
||||
|
||||
### ERC1538Query
|
||||
|
||||
Optionally, the function signatures of a transparent contract can be stored in an array in the transparent contract and queried to get what functions the transparent contract supports and what their delegate contract addresses are.
|
||||
|
||||
The following is an optional interface for querying function information from a transparent contract:
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.5.7;
|
||||
|
||||
interface ERC1538Query {
|
||||
|
||||
/// @notice Gets the total number of functions the transparent contract has.
|
||||
/// @return The number of functions the transparent contract has,
|
||||
/// not including the fallback function.
|
||||
function totalFunctions() external view returns(uint256);
|
||||
|
||||
/// @notice Gets information about a specific function
|
||||
/// @dev Throws if `_index` >= `totalFunctions()`
|
||||
/// @param _index The index position of a function signature that is stored in an array
|
||||
/// @return The function signature, the function selector and the delegate contract address
|
||||
function functionByIndex(uint256 _index)
|
||||
external
|
||||
view
|
||||
returns(
|
||||
string memory functionSignature,
|
||||
bytes4 functionId,
|
||||
address delegate
|
||||
);
|
||||
|
||||
/// @notice Checks to see if a function exists
|
||||
/// @param The function signature to check
|
||||
/// @return True if the function exists, false otherwise
|
||||
function functionExists(string calldata _functionSignature) external view returns(bool);
|
||||
|
||||
/// @notice Gets all the function signatures of functions supported by the transparent contract
|
||||
/// @return A string containing a list of function signatures
|
||||
function functionSignatures() external view returns(string memory);
|
||||
|
||||
/// @notice Gets all the function signatures supported by a specific delegate contract
|
||||
/// @param _delegate The delegate contract address
|
||||
/// @return A string containing a list of function signatures
|
||||
function delegateFunctionSignatures(address _delegate) external view returns(string memory);
|
||||
|
||||
/// @notice Gets the delegate contract address that supports the given function signature
|
||||
/// @param The function signature
|
||||
/// @return The delegate contract address
|
||||
function delegateAddress(string calldata _functionSignature) external view returns(address);
|
||||
|
||||
/// @notice Gets information about a function
|
||||
/// @dev Throws if no function is found
|
||||
/// @param _functionId The id of the function to get information about
|
||||
/// @return The function signature and the contract address
|
||||
function functionById(bytes4 _functionId)
|
||||
external
|
||||
view
|
||||
returns(
|
||||
string memory signature,
|
||||
address delegate
|
||||
);
|
||||
|
||||
/// @notice Get all the delegate contract addresses used by the transparent contract
|
||||
/// @return An array of all delegate contract addresses
|
||||
function delegateAddresses() external view returns(address[] memory);
|
||||
}
|
||||
```
|
||||
|
||||
See the [reference implementation of ERC1538](https://github.com/mudgen/transparent-contracts-erc1538) to see how this is implemented.
|
||||
|
||||
The text format for the list of function signatures returned from the `delegateFunctionSignatures` and `functionSignatures` functions is simply a string of function signatures. Here is an example of such a string: `"approve(address,uint256)balanceOf(address)getApproved(uint256)isApprovedForAll(address,address)ownerOf(uint256)safeTransferFrom(address,address,uint256)safeTransferFrom(address,address,uint256,bytes)setApprovalForAll(address,bool)transferFrom(address,address,uint256)"`
|
||||
|
||||
### How To Deploy A Transparent Contract
|
||||
1. Create and deploy to a blockchain a contract that implements the ERC1538 interface. You can skip this step if there is already such a contract deployed to the blockchain.
|
||||
2. Create your transparent contract with a fallback function as given above. Your transparent contract also needs a constructor that adds the `updateContract` function.
|
||||
3. Deploy your transparent contract to a blockchain. Pass in the address of the ERC1538 delegate contract to your constructor if it requires it.
|
||||
|
||||
See the [reference implementation](https://github.com/mudgen/transparent-contracts-erc1538) for examples of these contracts.
|
||||
|
||||
### Wrapper Contract for Delegate Contracts that Depend on Other Delegate Contracts
|
||||
In some cases some delegate contracts may need to call external/public functions that reside in other delegate contracts. A convenient way to solve this problem is to create a contract that contains empty implementations of functions that are needed and import and extend this contract in delegate contracts that call functions from other delegate contracts. This enables delegate contracts to compile without having to provide implementations of the functions that are already given in other delegate contracts. This is a way to save gas, prevent reaching the max contract size limit, and prevent duplication of code. This strategy was given by @amiromayer. [See his comment for more information.](https://github.com/ethereum/EIPs/issues/1538#issuecomment-451985155) Another way to solve this problem is to use assembly to call functions provided by other delegate contracts.
|
||||
|
||||
### Decentralized Authority
|
||||
It is possible to extend this standard to add consensus functionality such as an approval function that multiple different people call to approve changes before they are submitted with the `updateContract` function. Changes only go into effect when the changes are fully approved. The `CommitMessage` and ` FunctionUpdate` events should only be emitted when changes go into effect.
|
||||
|
||||
## Security
|
||||
> This standard refers to **owner(s)** as one or more individuals that have the power to add/replace/remove functions of an upgradeable contract.
|
||||
|
||||
### General
|
||||
|
||||
The owners(s) of an upgradeable contract have the ability to alter, add or remove data from the contract's data storage. Owner(s) of a contract can also execute any arbitrary code in the contract on behalf of any address. Owners(s) can do these things by adding a function to the contract that they call to execute arbitrary code. This is an issue for upgradeable contracts in general and is not specific to transparent contracts.
|
||||
|
||||
>**Note:** The design and implementation of contract ownership is **not** part of this standard. The examples given in this standard and in the reference implementation are just **examples** of how it could be done.
|
||||
|
||||
### Unchangeable Functions
|
||||
|
||||
"Unchangeable functions" are functions defined in a transparent contract itself and not in a delegate contract. The owner(s) of a transparent contract are not able to replace these functions. The use of unchangeable functions is limited because in some cases they can still be manipulated if they read or write data to the storage of the transparent contract. Data read from the transparent contract's storage could have been altered by the owner(s) of the contract. Data written to the transparent contract's storage can be undone or altered by the owner(s) of the contract.
|
||||
|
||||
In some cases unchangeble functions add trustless guarantees to a transparent contract.
|
||||
|
||||
### Transparency
|
||||
|
||||
Contracts that implement this standard emit an event every time a function is added, replaced or removed. This enables people and software to monitor the changes to a contract. If any bad acting function is added to a contract then it can be seen. To comply with this standard all source code of a transparent contract and delegate contracts must be publicly available and verified.
|
||||
|
||||
Security and domain experts can review the history of change of any transparent contract to detect any history of foul play.
|
||||
|
||||
## Rationale
|
||||
<!--The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The rationale may also provide evidence of consensus within the community, and should discuss important objections or concerns raised during discussion.-->
|
||||
|
||||
### String of Function Signatures Instead of bytes4[] Array of Function Selectors
|
||||
|
||||
The `updateContract` function takes a `string` list of functions signatures as an argument instead of a `bytes4[]` array of function selectors for three reasons:
|
||||
|
||||
1. Passing in function signatures enables the implementation of `updateContract` to prevent selector clashes.
|
||||
2. A major part of this standard is to make upgradeable contracts more transparent by making it easier to see what has changed over time and why. When a function is added, replaced or removed its function signature is included in the FunctionUpdate event that is emitted. This makes it relatively easy to write software that filters the events of a contract to display to people what functions have been added/removed and changed over time without needing access to the source code or ABI of the contract. If only four-byte function selectors were provided this would not be possible.
|
||||
3. By looking at the source code of a transparent contract it is not possible to see all the functions that it supports. This is why the ERC1538Query interface exists, so that people and software have a way to look up and examine or show all functions currently supported by a transparent contract. Function signatures are used so that ERC1538Query functions can show them.
|
||||
|
||||
### Gas Considerations
|
||||
|
||||
Delegating function calls does have some gas overhead. This is mitigated in two ways:
|
||||
1. Delegate contracts can be small, reducing gas costs. Because it costs more gas to call a function in a contract with many functions than a contract with few functions.
|
||||
2. Because transparent contracts do not have a max size limitation it is possible to add gas optimizing functions for use cases. For example someone could use a transparent contract to implement the ERC721 standard and implement batch transfer functions from the [ERC1412 standard](https://github.com/ethereum/EIPs/issues/1412) to help reduce gas (and make batch transfers more convenient).
|
||||
|
||||
### Storage
|
||||
|
||||
The standard does not specify how data is stored or organized by a transparent contract. But here are some suggestions:
|
||||
|
||||
**Inherited Storage**
|
||||
|
||||
1. The storage variables of a transparent contract consist of the storage variables defined in the transparent contract source code and the source code of delegate contracts that have been added.
|
||||
|
||||
2. A delegate contract can use any storage variable that exists in a transparent contract as long as it defines within it all the storage variables that exist, in the order that they exist, up to and including the ones being used.
|
||||
|
||||
3. A delegate contract can create new storage variables as long as it has defined, in the same order, all storage variables that exist in the transparent contract.
|
||||
|
||||
Here is a simple way inherited storage could be implemented:
|
||||
|
||||
1. Create a storage contract that contains the storage variables that your transparent contract and delegate contracts will use.
|
||||
2. Make your delegate contracts inherit the storage contract.
|
||||
3. If you want to add a new delegate contract that adds new storage variables then create a new storage contract that adds the new storage variables and inherits from the old storage contract. Use your new storage contract with your new delegate contract.
|
||||
4. Repeat steps 2 or 3 for every new delegate contract.
|
||||
|
||||
|
||||
**Unstructured Storage**
|
||||
|
||||
Assembly is used to store and read data at specific storage locations. An advantage to this approach is that previously used storage locations don't have to be defined or mentioned in a delegate contract if they aren't used by it.
|
||||
|
||||
**Eternal Storage**
|
||||
|
||||
Data can be stored using a generic API based on the type of data. [See ERC930 for more information.](https://github.com/ethereum/EIPs/issues/930)
|
||||
|
||||
### Becoming Immutable
|
||||
It is possible to make a transparent contract become immutable. This is done by calling the `updateContract` function to remove the `updateContract` function. With this gone it is no longer possible to add, replace and remove functions.
|
||||
|
||||
### Versions of Functions
|
||||
|
||||
Software or a user can verify what version of a function is called by getting the delegate contract address of the function. This can be done by calling the `delegateAddress` function from the ERC1538Query interface if it is implemented. This function takes a function signature as an argument and returns the delegate contract address where it is implemented.
|
||||
|
||||
### Best Practices, Tools and More Information
|
||||
|
||||
> More information, tools, tutorials and best practices concerning transparent contracts need to be developed and published.
|
||||
|
||||
Below is a growing list of articles concerning transparent contracts and their use. If you have an article about transparent contracts you would like to share then please submit a comment to this issue about it to get it added.
|
||||
|
||||
[ERC1538: Future Proofing Smart Contracts and Tokens](https://coinjournal.net/erc1538-future-proofing-smart-contacts-and-tokens/)
|
||||
|
||||
[The ERC1538 improving towards the “transparent contract” standard](https://www.crypto-economy.net/en/ethereum-eth-erc1538-transparent-contract-standard/)
|
||||
|
||||
### Inspiration
|
||||
|
||||
This standard was inspired by ZeppelinOS's implementation of [Upgradeability with vtables](https://github.com/zeppelinos/labs/tree/master/upgradeability_with_vtable).
|
||||
|
||||
This standard was also inspired by the design and implementation of the [Mokens contract](https://etherscan.io/address/0xc1eab49cf9d2e23e43bcf23b36b2be14fc2f8838#code) from the [Mokens project](https://github.com/Mokens/MIPs/blob/master/MIPS/mip-2-Goals-and-Objectives.md). The Mokens contract has been [upgraded to implement this standard](https://etherscan.io/address/0x0ac5637fe62ec14fd9e237a81a9679d4adef701f#code).
|
||||
|
||||
|
||||
## Backwards Compatibility
|
||||
<!--All EIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The EIP must explain how the author proposes to deal with these incompatibilities. EIP submissions without a sufficient backwards compatibility treatise may be rejected outright.-->
|
||||
This standard makes a contract compatible with future standards and functionality because new functions can be added and existing functions can be replaced or removed.
|
||||
|
||||
This standard future proofs a contract.
|
||||
|
||||
## Implementation
|
||||
<!--The implementations must be completed before any EIP is given status "Final", but it need not be completed before the EIP is accepted. While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of "rough consensus and running code" is still useful when it comes to resolving many discussions of API details.-->
|
||||
A reference implementation of this standard is given in the [transparent-contracts-erc1538](https://github.com/mudgen/transparent-contracts-erc1538) repository.
|
||||
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -14,9 +14,11 @@ created: 2016-10-14
|
|||
### Parameters
|
||||
- `FORK_BLKNUM`: 2,675,000
|
||||
- `CHAIN_ID`: 1 (main net)
|
||||
|
||||
### Specification
|
||||
|
||||
If `block.number >= FORK_BLKNUM` and `v = CHAIN_ID * 2 + 35` or `v = CHAIN_ID * 2 + 36`, then when computing the hash of a transaction for purposes of signing or recovering, instead of hashing only the first six elements (i.e. nonce, gasprice, startgas, to, value, data), hash nine elements, with `v` replaced by `CHAIN_ID`, `r = 0` and `s = 0`. The currently existing signature scheme using `v = 27` and `v = 28` remains valid and continues to operate under the same rules as it does now.
|
||||
|
||||
### Example
|
||||
|
||||
Consider a transaction with `nonce = 9`, `gasprice = 20 * 10**9`, `startgas = 21000`, `to = 0x3535353535353535353535353535353535353535`, `value = 10**18`, `data=''` (empty).
|
||||
|
@ -44,6 +46,7 @@ Notice the use of 37 instead of 27. The signed tx would become:
|
|||
```
|
||||
0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83
|
||||
```
|
||||
|
||||
### Rationale
|
||||
|
||||
This would provide a way to send transactions that work on Ethereum without working on ETC or the Morden testnet. ETC is encouraged to adopt this EIP but replacing `CHAIN_ID` with a different value, and all future testnets, consortium chains and alt-etherea are encouraged to adopt this EIP replacing `CHAIN_ID` with a unique value.
|
||||
|
@ -57,14 +60,9 @@ This would provide a way to send transactions that work on Ethereum without work
|
|||
| 2 | Morden (disused), Expanse mainnet |
|
||||
| 3 | Ropsten |
|
||||
| 4 | Rinkeby |
|
||||
| 8 | Ubiq mainnet |
|
||||
| 9 | Ubiq testnet |
|
||||
| 30 | Rootstock mainnet |
|
||||
| 31 | Rootstock testnet |
|
||||
| 5 | Goerli |
|
||||
| 42 | Kovan |
|
||||
| 61 | Ethereum Classic mainnet |
|
||||
| 62 | Ethereum Classic testnet |
|
||||
| 66 | ewasm testnet |
|
||||
| 1337 | Geth private chains (default) |
|
||||
| 6284 | Görli |
|
||||
| 314158 | Stureby |
|
||||
|
||||
|
||||
Find more chain ID's on [chainid.network](https://chainid.network) and contribute to [ethereum-lists/chains](https://github.com/ethereum-lists/chains).
|
|
@ -32,7 +32,7 @@ The value returned by `contenthash` MUST be represented as a machine-readable [m
|
|||
|
||||
protoCodes and their meanings are specified in the [multiformats/multicodec](https://github.com/multiformats/multicodec) repository.
|
||||
|
||||
The encoding of the value depends on the content type specified by the protoCode. Values with protocodes of 0xee and 0xef represent IPFS and Swarm content; these values are encoded as v1 [CIDs](https://github.com/multiformats/cid) without a base prefix, meaning their value is formatted as follows:
|
||||
The encoding of the value depends on the content type specified by the protoCode. Values with protocodes of 0xe3 and 0xe4 represent IPFS and Swarm content; these values are encoded as v1 [CIDs](https://github.com/multiformats/cid) without a base prefix, meaning their value is formatted as follows:
|
||||
|
||||
```
|
||||
<protoCode uvarint><cid-version><multicodec-content-type><multihash-content-address>
|
||||
|
@ -45,7 +45,7 @@ When resolving a `contenthash`, applications MUST use the protocol code to deter
|
|||
Input data:
|
||||
|
||||
```
|
||||
storage system: IPFS (0xee)
|
||||
storage system: IPFS (0xe3)
|
||||
CID version: 1 (0x01)
|
||||
content type: dag-pb (0x70)
|
||||
hash function: sha2-256 (0x12)
|
||||
|
@ -56,7 +56,7 @@ hash: 29f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f
|
|||
Binary format:
|
||||
|
||||
```
|
||||
0xee010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f
|
||||
0xe3010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f
|
||||
```
|
||||
|
||||
Text format:
|
||||
|
@ -67,7 +67,7 @@ ipfs://QmRAQB6YaCyidP37UdDnjFY5vQuiBrcqdyoW1CuDgwxkD4
|
|||
|
||||
### Fallback
|
||||
|
||||
In order to support names that have an IPFS or Swarm hash in their `content` field, a grace period MUST be implemented offering those name holders time to update their names. If a resolver does not support the `multihash` interface, it MUST be checked whether they support the `content` interface. If they do, the value of that field SHOULD be treated in a context dependent fashion and resolved. This condition MUST be enforced until December 31st, 2018.
|
||||
In order to support names that have an IPFS or Swarm hash in their `content` field, a grace period MUST be implemented offering those name holders time to update their names. If a resolver does not support the `multihash` interface, it MUST be checked whether they support the `content` interface. If they do, the value of that field SHOULD be treated in a context dependent fashion and resolved. This condition MUST be enforced until at least March 31st, 2019.
|
||||
|
||||
### Implementation
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ Applications interacting with the blockchain often make use of additional, non-b
|
|||
## Specification
|
||||
|
||||
### Path levels
|
||||
We define the following 5 levels in BIP32 path:
|
||||
We define the following levels in BIP32 path:
|
||||
|
||||
```m / purpose' / coin_type' / subpurpose' / key_type' / key_index```
|
||||
|
||||
|
@ -35,15 +35,15 @@ This part is constant and set to ```m / 43' / 60' / 1581'```, meaning BIP 43 ->
|
|||
All subtrees under this prefix are the scope of this EIP.
|
||||
|
||||
### Key type
|
||||
Describes the purpose for which the key is being used. Key types should be generic. "Instant messaging" is a good example whereas "Whisper" is not. The reason is that you want to be able to use the same identity across different services. Key types are defined at: <to be defined>
|
||||
Describes the purpose for which the key is being used. Key types should be generic. "Instant messaging" is a good example whereas "Whisper" is not. The reason is that you want to be able to use the same identity across different services. Key types are defined at: TBD
|
||||
|
||||
Hardened derivation is used at this level.
|
||||
|
||||
### Key index
|
||||
Keys are numbered from index 0 in sequentially increasing manner.
|
||||
This number is used as child index in BIP32 derivation.
|
||||
The key index is a field of variable length identifying a specific key. In its simplest case, it is a number from 0 to 2^31-1. If a larger identifier is desired (for example representing a hash or a GUID), the value must be split
|
||||
across several BIP32 nesting levels, most significant bit first and left aligned, bit-padded with 0s if needed. All levels, except the last one must used hardened key derivation. The last level must use public derivation. This means that every level can carry 31-bit of the identifier to represent.
|
||||
|
||||
Public derivation is used at this level.
|
||||
As an example, let's assume we have a key with key type 4' and a key_index representing a 62-bit ID represented as hexadecimal 0x2BCDEFFEDCBAABCD the complete keypath would be ```m / 43' / 60' / 1581' / 4' / 1469833213' / 1555737549 ```. If you are using random identifiers, it might be convenient to generate a conventional GUID, for example 128-bit just fix the value of the most significant bit of each 32-bit word to 1 for all of them, except the last one which will be 0.
|
||||
|
||||
## Rationale
|
||||
The structure proposed above follows the BIP43 generic structure and is similar to the widely adopted BIP44 specification.
|
||||
|
|
|
@ -17,7 +17,7 @@ This meta-EIP specifies the changes included in the alternative Ethereum hardfor
|
|||
- Codename: Ethereum ProgPoW
|
||||
- Aliases: N/A
|
||||
- Activation:
|
||||
- `Block >= 7080000` on the Ethereum mainnet
|
||||
- `Block >= 7280000` on the Ethereum mainnet
|
||||
- Included EIPs:
|
||||
- [EIP 1057](./eip-1057.md): ProgPoW, a Programmatic Proof-of-Work
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
eip: 1613
|
||||
title: Gas stations network
|
||||
author: Yoav Weiss <yoav@tabookey.com>, Dror Tirosh <dror@tabookey.com>
|
||||
author: Yoav Weiss <yoav@tabookey.com>, Dror Tirosh <dror@tabookey.com>, Alex Forshtat <alex@tabookey.com>
|
||||
discussions-to: https://github.com/yoav-tabookey/EIPs/issues/1
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
|
@ -58,7 +58,6 @@ Roles of a `Relay` node:
|
|||
* Maintain a hot wallet with a small amount of ETH, to pay for gas.
|
||||
* Provide a public interface for user apps to send gasless transactions via channels such as https or whisper.
|
||||
* Publish it's public interfaces and its price (as a multiplier of the actual transaction gas cost) in `RelayHub`.
|
||||
* Help `RelayHub` maintain the list of relays in a trustless way. Relays are incentivized to remove other verifiably-stale relays.
|
||||
* Optionally monitor reverted transactions of other relays through RelayHub, catching offending relays and claiming their stakes. This can be done by anyone, not just a relay.
|
||||
|
||||
Implementing a `RelayRecipient` contract:
|
||||
|
@ -88,7 +87,7 @@ Glossary of terms used in the processes below:
|
|||
* `Sender` - an external address with a valid keypair but no ETH to pay for gas.
|
||||
* `Relay` - a node holding ETH in an external address, listed in RelayHub and relaying transactions from Senders to RelayHub for a fee.
|
||||
|
||||
![Sequence Diagram](http://bit.ly/2EWWVN8)
|
||||
![Sequence Diagram](https://bit.ly/2EWWVN8)
|
||||
|
||||
The process of registering/refreshing a `Relay`:
|
||||
|
||||
|
@ -96,19 +95,14 @@ The process of registering/refreshing a `Relay`:
|
|||
* If starting for the first time (no key yet), generate a key pair for Relay's address.
|
||||
* If Relay's address doesn't hold sufficient funds for gas (e.g. because it was just generated), Relay stays inactive until its owner funds it.
|
||||
* Relay's owner funds it.
|
||||
* Relay sends the required stake to `RelayHub`.
|
||||
* Relay calls `RelayHub.register_relay(address owner, uint transaction_fee, string[] url, address optional_stale_relay_for_removal)`, with its `owner` (the address that funded it),
|
||||
the relay's `transaction fee` (as a multiplier on transaction gas cost), and one or more URL for incoming transactions.
|
||||
The `optional_stale_relay_for_removal` arg is the address of a stale relay found in the list.
|
||||
* `RelayHub` checks Relay.balance and emits `NeedsFunding(Relay)` to alert the owner if it runs low.
|
||||
* Relay's owner sends the required stake to `RelayHub` by calling `RelayHub.stake(address relay, uint unstake_delay)`.
|
||||
* `RelayHub` puts the `owner` and `unstake delay` in the relays map, indexed by `relay` address.
|
||||
* Relay calls `RelayHub.register_relay(uint transaction_fee, string memory url)` with the relay's `transaction fee` (as a multiplier on transaction gas cost), and a URL for incoming transactions.
|
||||
* `RelayHub` ensures that Relay has a sufficient stake.
|
||||
* `RelayHub` puts the `owner`, current `timestamp`, `transaction fee`, and `urls`, in the relays map, indexed by `relay` address.
|
||||
* `RelayHub` emits an event, `RelayAdded(Relay, transaction_fee, relay_stake, urls)`.
|
||||
* If `optional_stale_relay_for_removal` is in the relays map and is stale (hasn't communicated in a few days), `RelayHub` removes it.
|
||||
Relay benefits by receiving a gas refund for the freed storage, so it's incentivized to always include a stale relay if there is one.
|
||||
* Relay starts a timer to perform a `keepalive` transaction after a certain amount of time if no real transactions are relayed through it.
|
||||
`Relay` is considered stale if it hasn't sent anything to `RelayHub` in a while, e.g. 4 days.
|
||||
* `Relay` goes to sleep and waits signing requests.
|
||||
* `RelayHub` puts the `transaction fee` in the relays map.
|
||||
* `RelayHub` emits an event, `RelayAdded(Relay, owner, transaction_fee, relay_stake, unstake_delay, url)`.
|
||||
* Relay starts a timer to perform a `keepalive` transaction every 6000 blocks.
|
||||
* `Relay` goes to sleep and waits for signing requests.
|
||||
|
||||
The process of sending a relayed transaction:
|
||||
|
||||
|
@ -120,7 +114,8 @@ The process of sending a relayed transaction:
|
|||
* Sender prepares the transaction with Sender's address, the recipient address, the actual transaction data, Relay's transaction fee, gas price, gas limit, its current nonce from `RelayHub.nonces`, RelayHub's address, and Relay's address, and then signs it.
|
||||
* Sender verifies that `RelayHub.balances[recipient]` holds enough ETH to pay Relay's fee.
|
||||
* Sender verifies that `Relay.balance` has enough eth to send the transaction
|
||||
* Sender sends the signed transaction to Relay's web interface.
|
||||
* Sender reads the Relay's current `nonce` value and decides on the `max_nonce` parameter.
|
||||
* Sender sends the signed transaction amd metadata to Relay's web interface.
|
||||
* `Relay` wraps the transaction with a transaction to `RelayHub`, with zero ETH value.
|
||||
* `Relay` signs the wrapper transaction with its key in order to pay for gas.
|
||||
* `Relay` verifies that:
|
||||
|
@ -130,12 +125,14 @@ The process of sending a relayed transaction:
|
|||
* The relay address in the transaction matches Relay's address.
|
||||
* The transaction's recipient has enough ETH deposited in `RelayHub` to pay the transaction fee.
|
||||
* Relay has enough ETH to pay for the gas required by the transaction.
|
||||
* Value of `max_nonce` is higher than current Relay's `nonce`
|
||||
* If any of Relay's checks fail, it returns an error to sender, and doesn't proceed.
|
||||
* Relay submits the signed wrapped transaction to the blockchain.
|
||||
* Relay immediately returns the signed wrapped transaction to the sender. This step is discussed below, in attacks/mitigations.
|
||||
* `Sender` receives the wrapped transaction and verifies that:
|
||||
* It's a valid relay call to `RelayHub`. from Relay's address.
|
||||
* The transaction's ethereum nonce matches Relay's current nonce.
|
||||
* The transaction's ethereum nonce is lower than or equal to `max_nonce`.
|
||||
* `Relay` is sufficiently funded to pay for it.
|
||||
* The wrapped transaction is valid and signed by `sender`.
|
||||
* Recipient contract has sufficient funds in `RelayHub.balances` to pay for Relay's fee as stated in the transaction.
|
||||
|
@ -153,7 +150,6 @@ The process of sending a relayed transaction:
|
|||
* Verifies that the signature of the internal transaction matches its stated origin (sender's key).
|
||||
* Verifies that the relay address written in the transaction matches msg.sender.
|
||||
* Verifies that the transaction's `nonce` matches the stated origin's nonce in `RelayHub.nonces`.
|
||||
* Checks `Relay.balance` and emits `NeedsFunding(Relay)` to alert the owner if it runs low.
|
||||
* Calls recipient's `accept_relayed_call` function, asking whether it's going to accept the transaction. If not, `RelayHub` reverts.
|
||||
In this case, Relay doesn't get paid, as it was its responsibility to check `RelayHub.can_relay` before releasing the transaction.
|
||||
* Sends the transaction to the recipient. The call is made using `call()`, so reverts won't kill the transaction, just return false.
|
||||
|
@ -181,15 +177,6 @@ The process of winding a `Relay` down:
|
|||
* `Relay` shuts down.
|
||||
* Once the owner's unstake delay is over, owner calls `RelayHub.unstake()`, and withdraws the stake.
|
||||
|
||||
Removal of stale/invalid relays:
|
||||
|
||||
* During registration/refresh, `Relay` helps purging stale relays.
|
||||
* `Relay` scans the relays in `RelayHub`, e.g. by going through old `RelayAdded` events.
|
||||
* `Relay` looks for stale relays (where the latest recorded `timestamp` is a few days ago).
|
||||
* If `Relay` finds such relay, it passes the stale relay as `optional_relay_removal` during registration.
|
||||
* `RelayHub` verifies that the reported stale relay is indeed stale or invalid, removes it from the relays map and emits `RelayRemoved(r)`.
|
||||
The storage refund offsets Relay's registration cost, so `Relay` is incentivized to remove a stale relay whenever if can find one.
|
||||
|
||||
## Rationale
|
||||
The rationale for the gas stations network design is a combination of two sets of requirements: Easy adoption, and robustness.
|
||||
|
||||
|
@ -236,6 +223,13 @@ The sender then proceeds to select a new relay and send the original transaction
|
|||
The result of such attack is a delay of a few blocks in sending the transaction (until the attack is detected) but the relay gets removed and loses its entire stake.
|
||||
Scaling such attack would be prohibitively expensive, and actually quite profitable for senders and honest relays.
|
||||
|
||||
##### Attack: Relay attempts to censor a transaction by signing it, but using a nonce higher than it's current nonce.
|
||||
In this attack, the Relay did create and return a perfectly valid transaction, but it will not be mined until this Relay fills the gap in the nonce with 'missing' transactions.
|
||||
This may delay the relaying of some transactions indefinately. In order to mitigate that, the sender includes a `max_nonce` parameter with it's signing request.
|
||||
It is suggested to be higher by 2-3 from current nonce, to allow the relay process several transactions.
|
||||
|
||||
When the sender receives a transaction signed by a Relay he validates that the nonce used is valid, and if it is not, the client will ignore the given relay and use other relays to relay given transaction. Therefore, there will be no actual delay introduced by such attack.
|
||||
|
||||
##### Attack: Dapp attempts to burn relays funds by implementing an inconsistent accept_relayed_call() and using multiple sender addresses to generate expensive transactions, thus performing a DoS attack on relays and reducing their profitability.
|
||||
In this attack, a contract sets an inconsistent accept_relayed_call (e.g. return zero for even blocks, nonzero for odd blocks), and uses it to exhaust relay resources through unpaid transactions.
|
||||
Relays can easily detect it after the fact.
|
||||
|
@ -275,9 +269,6 @@ After it caused this minor delay and got blacklisted, the attacker must wait a m
|
|||
Simultaneously bringing up a number of unreliable relays, large enough to cause a noticeable network delay, would be prohibitively expensive due to the required stake,
|
||||
and even then, all those relays will get blacklisted within a short time.
|
||||
|
||||
##### Attack: Relay attempts to unregister other relays.
|
||||
Removal of stale relays is trustless. RelayHub verifies whether the removed relay has performed any action recently, and would revert any transaction that tries to remove an active relay.
|
||||
|
||||
##### Attack: Attacker attempts to replay a relayed transaction.
|
||||
Transactions include a nonce. RelayHub maintains a nonce (counter) for each sender. Transactions with bad nonces get reverted by RelayHub. Each transaction can only be relayed once.
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ A slower release allows for extra time to identify, and address any issues which
|
|||
|
||||
Choosing a single TLD helps to maximize network effects by focusing on one namespace.
|
||||
|
||||
A three letter TLD is a pattern made familiar by it's common usage in internet domain names. This familiarity significantly increases the potential of the ENS to be integrated into pre-existing DNS systems, and reserved as a [special-use domain name](http://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml#special-use-domain). A recent precedent for this is the [reservation of the `.onion` domain](https://tools.ietf.org/html/rfc7686).
|
||||
A three letter TLD is a pattern made familiar by it's common usage in internet domain names. This familiarity significantly increases the potential of the ENS to be integrated into pre-existing DNS systems, and reserved as a [special-use domain name](https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml#special-use-domain). A recent precedent for this is the [reservation of the `.onion` domain](https://tools.ietf.org/html/rfc7686).
|
||||
|
||||
### Holding ether as collateral
|
||||
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
---
|
||||
eip: 1620
|
||||
title: ERC-1620 Money Streaming
|
||||
author: Paul Berg (@PaulRBerg) <hello@paulrberg.com>
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/1620
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
created: 2018-11-24
|
||||
---
|
||||
|
||||
<!--You can leave these HTML comments in your merged EIP and delete the visible duplicate text guides, they will not appear and may be helpful to refer to if you edit it again. This is the suggested template for new EIPs. Note that an EIP number will be assigned by an editor. When opening a pull request to submit your EIP, please use an abbreviated title in the filename, `eip-draft_title_abbrev.md`. The title should be 44 characters or less.-->
|
||||
|
||||
## Simple Summary
|
||||
<!--"If you can't explain it simply, you don't understand it well enough." Provide a simplified and layman-accessible explanation of the EIP.-->
|
||||
Money streaming represents the idea of continuous payments over a finite period of time. Block numbers are used as a proxy of time to continuously update balances.
|
||||
|
||||
## Abstract
|
||||
<!--A short (~200 word) description of the technical issue being addressed.-->
|
||||
The following describes a standard whereby time is measured using block numbers and streams are mappings in a master contract.
|
||||
|
||||
1. A provider sets up a money streaming contract.
|
||||
2. A prospective payer can interact with the contract and start the stream right away by depositing the funds required for the chosen period.
|
||||
3. The payee is able to withdraw money from the contract based on its ongoing solvency. That is: `payment rate * (current block height - starting block height)`
|
||||
4. The stream terms (payment rate, length, metadata) can be updated at any time if both parties pledge their signatures.
|
||||
5. The stream can be stopped at any point in time by any party without on-chain consensus.
|
||||
6. If the stream period ended and it was not previously stopped by any party, the payee is entitled to withdraw all the deposited funds.
|
||||
|
||||
## Motivation
|
||||
<!--The motivation is critical for EIPs that want to change the Ethereum protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the EIP solves. EIP submissions without sufficient motivation may be rejected outright.-->
|
||||
This standardised interface aims to change the way we think about long-term financial commitments. Thanks to blockchains, payments need not be sent in chunks (e.g. monthly salaries), as there is much less overhead in paying-as-you-go. Money as a function of time would better align incentives in a host of scenarios.
|
||||
|
||||
### Use Cases
|
||||
|
||||
This is just a preliminary list of use cases. There are other spooky ideas interesting to explore, such as time-dependent disincetivisation, but, for brevity, we have not included them here.
|
||||
|
||||
- Salaries
|
||||
- Subscriptions
|
||||
- Consultancies
|
||||
- CDPs
|
||||
- Rent
|
||||
- Parking
|
||||
|
||||
### Crowdsales
|
||||
[RICOs](https://github.com/lukso-network/rico), or Reversible ICOs, were introduced at Devcon4 by @frozeman. The idea is to endow investors with more power and safety guarantees by allowing them to "reverse" the investment based on the evolution of the project. We previously discussed a similar concept called SICOs, or Streamable ICOs, in this research [thread](https://ethresear.ch/t/chronos-a-quirky-application-proposal-for-plasma/2928/14?u=paulrberg).
|
||||
|
||||
Instead of investing a lump sum and giving the money away to the project developers, funds are held in a smart contract which allocates money based on the passage of time. Project developers can withdraw funds as the stream stays active, while investors have the power to get back a significant percentage of their initial commitment if the project halts.
|
||||
|
||||
## Specification
|
||||
<!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (go-ethereum, parity, cpp-ethereum, ethereumj, ethereumjs, and [others](https://github.com/ethereum/wiki/wiki/Clients)).-->
|
||||
|
||||
<details><summary>Expand</summary>
|
||||
|
||||
### Structs
|
||||
|
||||
The structure of a `stream` should be as follows:
|
||||
|
||||
- `stream`
|
||||
- `sender`: the `address` of the entity funding the stream
|
||||
- `recipient`: the `address` where the money is being delivered to
|
||||
- `tokenAddress`: the `address` of the ERC20 token used as payment asset
|
||||
- `balance`: the total funds left in the stream
|
||||
- `timeframe`: as defined below
|
||||
- `rate`: as defined below
|
||||
|
||||
```solidity
|
||||
struct Stream {
|
||||
address sender;
|
||||
address recipient;
|
||||
address tokenAddress;
|
||||
uint256 balance;
|
||||
Timeframe timeframe;
|
||||
Rate rate;
|
||||
}
|
||||
```
|
||||
|
||||
- `timeframe`
|
||||
- `start`: the starting block number of the stream
|
||||
- `stop`: the stopping block number of the stream
|
||||
|
||||
```solidity
|
||||
struct Timeframe {
|
||||
uint256 start;
|
||||
uint256 stop;
|
||||
}
|
||||
```
|
||||
|
||||
- `rate`
|
||||
- `payment`: how much money moves from `sender` to `recipient`
|
||||
- `interval`: how often `payment` moves from `sender` to `recipient`
|
||||
|
||||
```solidity
|
||||
struct Rate {
|
||||
uint256 payment;
|
||||
uint256 interval;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Methods
|
||||
|
||||
#### balanceOf
|
||||
|
||||
Returns available funds for the given stream id and address.
|
||||
|
||||
```solidity
|
||||
function balanceOf(uint256 _streamId, address _addr)
|
||||
```
|
||||
|
||||
#### getStream
|
||||
|
||||
Returns the full stream data, if the id points to a valid stream.
|
||||
|
||||
```solidity
|
||||
function getStream(uint256 _streamId) returns (address sender, address recipient, address tokenAddress, uint256 balance, uint256 startBlock, uint256 stopBlock, uint256 payment, uint256 interval)
|
||||
```
|
||||
|
||||
#### create
|
||||
|
||||
Creates a new stream between `msg.sender` and `_recipient`.
|
||||
|
||||
MUST allow senders to create multiple streams in parallel. SHOULD not accept Ether and only use ERC20-compatible tokens.
|
||||
|
||||
**Triggers Event**: [LogCreate](#log-create)
|
||||
|
||||
```solidity
|
||||
function create(address _recipient, address _tokenAddress, uint256 _startBlock, uint256 _stopBlock, uint256 _payment, uint256 _interval)
|
||||
```
|
||||
|
||||
#### withdraw
|
||||
|
||||
Withdraws all or a fraction of the available funds.
|
||||
|
||||
MUST allow only the recipient to perform this action.
|
||||
|
||||
**Triggers Event**: [LogWithdraw](#log-withdraw)
|
||||
|
||||
```solidity
|
||||
function withdraw(uint256 _streamId, uint256 _funds)
|
||||
```
|
||||
|
||||
#### redeem
|
||||
|
||||
Redeems the stream by distributing the funds to the sender and the recipient.
|
||||
|
||||
SHOULD allow any party to redeem the stream.
|
||||
|
||||
**Triggers Event**: [LogRedeem](#log-redeem)
|
||||
|
||||
```solidity
|
||||
function redeem(uint256 _streamId)
|
||||
```
|
||||
|
||||
#### confirmUpdate
|
||||
|
||||
Signals one party's willingness to update the stream
|
||||
|
||||
SHOULD allow any party to do this but MUST NOT be executed without consent from all involved parties.
|
||||
|
||||
**Triggers Event**: [LogConfirmUpdate](#log-confirm-update)
|
||||
|
||||
**Triggers Event**: [LogExecuteUpdate](#log-execute-update) when the last involved party calls this function
|
||||
|
||||
```solidity
|
||||
function update(uint256 _streamId, address _tokenAddress, uint256 _stopBlock, uint256 _payment, uint256 _interval)
|
||||
```
|
||||
|
||||
#### revokeUpdate
|
||||
|
||||
Revokes an update proposed by one of the involved parties.
|
||||
|
||||
MUST allow any party to do this.
|
||||
|
||||
**Triggers Event**: [LogRevokeUpdate](#log-revoke-update)
|
||||
|
||||
```solidity
|
||||
function confirmUpdate(uint256 _streamId, address _tokenAddress, uint256 _stopBlock, uint256 _payment, uint256 _interval)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Events
|
||||
|
||||
#### LogCreate
|
||||
|
||||
MUST be triggered when `create` is successfully called.
|
||||
|
||||
```solidity
|
||||
event LogCreate(uint256 indexed _streamId, address indexed _sender, address indexed _recipient, address _tokenAddress, uint256 _startBlock, uint256 _stopBlock, uint256 _payment, uint256 _interval)
|
||||
```
|
||||
|
||||
#### LogWithdraw
|
||||
|
||||
MUST be triggered when `withdraw` is successfully called.
|
||||
|
||||
```solidity
|
||||
event LogWithdraw(uint256 indexed _streamId, address indexed _recipient, uint256 _funds)
|
||||
```
|
||||
|
||||
#### LogRedeem
|
||||
|
||||
MUST be triggered when `redeem` is successfully called.
|
||||
|
||||
```solidity
|
||||
event LogRedeem(uint256 indexed _streamId, address indexed _sender, address indexed _recipient, uint256 _senderBalance, uint256 _recipientBalance)
|
||||
```
|
||||
|
||||
#### LogConfirmUpdate
|
||||
|
||||
MUST be triggered when `confirmUpdate` is successfully called.
|
||||
|
||||
```solidity
|
||||
event LogConfirmUpdate(uint256 indexed _streamId, address indexed _confirmer, address _newTokenAddress, uint256 _newStopBlock, uint256 _newPayment, uint256 _newInterval);
|
||||
```
|
||||
|
||||
#### LogRevokeUpdate
|
||||
|
||||
MUST be triggered when `revokeUpdate` is successfully called.
|
||||
|
||||
```solidity
|
||||
event LogRevokeUpdate(uint256 indexed _streamId, address indexed revoker, address _newTokenAddress, uint256 _newStopBlock, uint256 _newPayment, uint256 _newInterval)
|
||||
```
|
||||
|
||||
#### LogExecuteUpdate
|
||||
|
||||
MUST be triggered when an update is approved by all involved parties.
|
||||
|
||||
```solidity
|
||||
event LogExecuteUpdate(uint256 indexed _newStreamId, address indexed _sender, address indexed _recipient, address _newTokenAddress, uint256 _newStopBlock, uint256 _newPayment, uint256 _newInterval)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Rationale
|
||||
<!--The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The rationale may also provide evidence of consensus within the community, and should discuss important objections or concerns raised during discussion.-->
|
||||
|
||||
This specification was designed to serve as an entry point to the quirky concept of money as a function of time and it is definitely not set in stone. Several other designs, including payment channels and Plasma chains were also considered, but they were eventually deemed dense in assumptions unnecessary for an initial version.
|
||||
|
||||
<!--
|
||||
- Block times and oracles for time calculation
|
||||
- GCD
|
||||
- Miners
|
||||
- Sidechain-compatible (and preferable)
|
||||
- The `update` function
|
||||
- Multi-hop streams
|
||||
-->
|
||||
|
||||
Block times are a reasonable, trustless proxy for time on the blockchain. Between 2016 and 2018, the Ethereum block time average value [hovered](https://etherscan.io/chart/blocktime) around 14 seconds, excluding the last two quarters of 2017. Mathematically speaking, it would be ideal to have a standard deviation as close to 0 as possible, but that is not how things work in the real world. This has huge implications on the feasibility of this ERC which we shall investigate below.
|
||||
|
||||
### GCD
|
||||
When setting up a stream, a payer and a payee may want to make the total streaming duration a multiple of the "greatest common denominator" (GCD) of the chain they operate on; that is, the average block time. This is not imperative in the smart contracts per se, but there needs to be an off-chain process to map streams to real world time units in order to create a sound and fair payment mechanism.
|
||||
|
||||
### Block Times
|
||||
Because there is uncertainty regarding block times, streams may not be settled on the blockchain as initially planned. Let `$d` be the total streaming duration measured in seconds, `$t` the average block time before the stream started and `$t'` the actual average block time over `$d` after the stream started. We distinguish two undesirable scenarios:
|
||||
|
||||
1. `$t` < `$t'`: the payee will get their funds *later* than expected
|
||||
|
||||
2. `$t` > `$t'`: the payee will get their funds *sooner* than expected
|
||||
|
||||
If the combined error delta is smaller than the payment rate (fifth parameter of the `create` method, measured in wei), there is no problem at all. Conversely, we stumble upon trust issues because real-world time frames do not correspond to the stream terms. For instance, if an employee is normally entitled to withdraw all the funds from the stream at the end of the month, but block times cause case 1 from above to occur, the employee is in a financial disadvantage because their continuous effort is not compensated as promised.
|
||||
|
||||
Limiting the problem scope only to Ethereum, we propose two remedies:
|
||||
|
||||
1. Consensus on calling the `update` function to correct the stream terms. This might sound preposterous, but in most cases the stakes are low and stream participants are involved in long-term financial commitments. There is a high disincentive to refuse to cooperate.
|
||||
|
||||
2. Autonomously fix significant error deltas. In theory, we could achieve this using previous blocks' timestamps, "checkpointing" the stream once in a predefined number of blocks. This is still an area of active research because of potentially high overheads in gas costs.
|
||||
|
||||
Nonetheless, it is important to note that this is still a major improvement on the traditional model where absolute trust is required.
|
||||
|
||||
### Sidechains
|
||||
|
||||
It could be more efficient to implement this standard on independent sidechains like [POA Network](https://poa.network) or [xDai](https://medium.com/poa-network/poa-network-partners-with-makerdao-on-xdai-chain-the-first-ever-usd-stable-blockchain-65a078c41e6a) - thanks to their rather predictable nature. Admittedly, security is traded for scalability, but proper cryptoeconomic stakes could alleviate potential problems.
|
||||
|
||||
Furthermore, it is intriguing to explore the prospect of stream-specific sidechains.
|
||||
|
||||
### Oracles
|
||||
|
||||
The proposed specification uses block numbers to proxy time, but this need not be the only method. Albeit it would imply different trust assumptions, oracles could be used to provide a feed of timestamps. Coupled with the aforementioned idea of stream-specific sidechains, oracles could efficiently solve the problems outlined in [Block Times](#block-times).
|
||||
|
||||
### Multi-Hop Streams
|
||||
|
||||
Future or upgraded versions of this standard may describe "multi-hop" streams. If:
|
||||
|
||||
1. There is a stream between A and B
|
||||
2. There is another stream between B and C
|
||||
|
||||
There could be a way to avoid running two different streams in parallel. That is, a fraction or all of the funds being streamed from A to B could be automatically wired to C. An interesting use case for this is taxes. Instead of manually moving money around, proactively calculating how much you owe and then transfer it, a stream could atomically perform those operations for you.
|
||||
|
||||
## Implementation
|
||||
<!--The implementations must be completed before any EIP is given status "Final", but it need not be completed before the EIP is accepted. While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of "rough consensus and running code" is still useful when it comes to resolving many discussions of API details.-->
|
||||
|
||||
- [ChronosProtocol WIP implementation](https://github.com/ChronosProtocol/monorepo)
|
||||
|
||||
## Additional References
|
||||
- [Chronos Protocol Ethresear.ch Plasma Proposal](https://ethresear.ch/t/chronos-a-quirky-application-proposal-for-plasma/2928?u=paulrberg)
|
||||
- [Chronos Protocol White Paper](http://chronosprotocol.org/chronos-white-paper.pdf)
|
||||
- [Flipper: Streaming Salaries @ CryptoLife Hackathon](https://devpost.com/software/flipper-3gvl4b)
|
||||
- [SICOs or Streamed ICOs](https://ethresear.ch/t/chronos-a-quirky-application-proposal-for-plasma/2928/14?u=paulrberg)
|
||||
- [RICOs or Reversible ICOs](https://twitter.com/feindura/status/1058057076306518017)
|
||||
- [Andreas Antonopoulos' Keynote on Bitcoin, Lightning and Money Streaming](https://www.youtube.com/watch?v=gF_ZQ_eijPs)
|
||||
|
||||
## Final Notes
|
||||
|
||||
Many thanks to @mmilton41 for countless brainstorming sessions. We have been doing research on the topic of money streaming for quite a while within the context of @ChronosProtocol. In August this year, we published the first version of our white paper describing a Plasma approach. However, in the meantime, we realised that it would be much more [fun](https://twitter.com/PaulRBerg/status/1056595919116910592) and easier to start small on Ethereum itself and sidechains like [xDai](https://blockscout.com/poa/dai).
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -6,6 +6,7 @@ type: Standards Track
|
|||
category: ERC
|
||||
status: Final
|
||||
created: 2018-01-23
|
||||
requires: 214
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
|
@ -29,7 +30,7 @@ For some "standard interfaces" like [the ERC-20 token interface](https://github.
|
|||
|
||||
### How Interfaces are Identified
|
||||
|
||||
For this standard, an *interface* is a set of [function selectors as defined by the Ethereum ABI](http://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector). This a subset of [Solidity's concept of interfaces](http://solidity.readthedocs.io/en/develop/abi-spec.html) and the `interface` keyword definition which also defines return types, mutability and events.
|
||||
For this standard, an *interface* is a set of [function selectors as defined by the Ethereum ABI](https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector). This a subset of [Solidity's concept of interfaces](https://solidity.readthedocs.io/en/develop/abi-spec.html) and the `interface` keyword definition which also defines return types, mutability and events.
|
||||
|
||||
We define the interface identifier as the XOR of all function selectors in the interface. This code example shows how to calculate an interface identifier:
|
||||
|
||||
|
@ -84,7 +85,7 @@ Implementation note, there are several logical ways to implement this function.
|
|||
|
||||
### How to Detect if a Contract Implements ERC-165
|
||||
|
||||
1. The source contact makes a `STATICCALL` to the destination address with input data: `0x01ffc9a701ffc9a700000000000000000000000000000000000000000000000000000000` and gas 30,000. This corresponds to `contract.supportsInterface(0x01ffc9a7)`.
|
||||
1. The source contract makes a `STATICCALL` to the destination address with input data: `0x01ffc9a701ffc9a700000000000000000000000000000000000000000000000000000000` and gas 30,000. This corresponds to `contract.supportsInterface(0x01ffc9a7)`.
|
||||
2. If the call fails or return false, the destination contract does not implement ERC-165.
|
||||
3. If the call returns true, a second call is made with input data `0x01ffc9a7ffffffff00000000000000000000000000000000000000000000000000000000`.
|
||||
4. If the second call fails or returns true, the destination contract does not implement ERC-165.
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
eip: 1679
|
||||
title: "Hardfork Meta: Istanbul"
|
||||
author: Alex Beregszaszi (@axic), Afri Schoedon (@5chdn)
|
||||
type: Meta
|
||||
status: Draft
|
||||
created: 2019-01-04
|
||||
requires: 1716
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
||||
This meta-EIP specifies the changes included in the Ethereum hardfork named Istanbul.
|
||||
|
||||
## Specification
|
||||
|
||||
- Codename: Istanbul
|
||||
- Activation: TBD
|
||||
- Included EIPs: TBD
|
||||
|
||||
## References
|
||||
|
||||
TBA
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
eip: 1681
|
||||
title: Temporal Replay Protection
|
||||
author: Martin Holst Swende (@holiman)
|
||||
discussions-to: https://ethereum-magicians.org/t/temporal-replay-protection/2355
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2019-01-08
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
|
||||
This EIP proposes adding a 'temporal' replay protection to transactions, in the form of a `valid-until` timestamp.
|
||||
This EIP is very similar to https://github.com/ethereum/EIPs/pull/599 by Nick Johnson and Konrad Feldmeier, the main difference
|
||||
being that this EIP is based on clock-time / walltime instead of block numbers.
|
||||
|
||||
|
||||
## Motivation
|
||||
|
||||
There are a couple of different motivators for introducing a timebased transaction validity.
|
||||
|
||||
- If any form of dust-account clearing is introduced, e.g. (https://github.com/ethereum/EIPs/issues/168), it will be necessary
|
||||
to introduce a replay protection, such as https://github.com/ethereum/EIPs/issues/169 . Having temporal replay protection removes the need
|
||||
to change nonce-behaviour in the state, since transactions would not be replayable at a later date than explicitly set by the user.
|
||||
- In many cases, such as during ICOs, a lot of people want their transactions to either become included soon (within a couple of hours) or not at all. Currently,
|
||||
transactions are queued and may not execute for several days, at a cost for both the user (who ends up paying gas for a failing purchase) and the network, dealing with the large transaction queues.
|
||||
- Node implementations have no commonly agreed metric for which transactions to keep, discard or propagate. Having a TTL on transactions would make it easier to remove stale transactions from the system.
|
||||
|
||||
## Specification
|
||||
|
||||
The roll-out would be performed in two phases, `X` (hardfork), and `Y` (softfork).
|
||||
|
||||
At block `X`,
|
||||
|
||||
- Add an optional field `valid-until` to the RLP-encoded transaction, defined as a `uint64` (same as `nonce`).
|
||||
- If the field is present in transaction `t`, then
|
||||
- `t` is only eligible for inclusion in a block if `block.timestamp` < `t.valid-until`.
|
||||
|
||||
At block `Y`,
|
||||
- Make `valid-until` mandatory, and consider any transaction without `valid-until` to be invalid.
|
||||
|
||||
## Rationale
|
||||
|
||||
### Rationale for this EIP
|
||||
|
||||
For the dust-account clearing usecase,
|
||||
- This change is much less invasive in the consensus engine.
|
||||
- No need to maintain a consensus-field of 'highest-known-nonce' or cap the number of transactions from a sender in a block.
|
||||
- Only touches the transaction validation part of the consensus engine
|
||||
- Other schemas which uses the `nonce` can have unintended side-effects,
|
||||
- such as inability to create contracts at certain addresses.
|
||||
- more difficult to integrate with offline signers, since more elaborate nonce-schemes requires state access to determine.
|
||||
- More intricate schemes like `highest-nonce` are a lot more difficult, since highest-known-nonce will be a consensus-struct that is incremented and possibly reverted during transaction execution, requireing one more journalled field.
|
||||
|
||||
|
||||
### Rationale for walltime
|
||||
|
||||
Why use walltime instead of block numbers, as proposed in https://github.com/ethereum/EIPs/pull/599 ?
|
||||
|
||||
- The UTC time is generally available in most settings, even on a computer which is offline. This means that even a setup where blockchain information is unavailable, the party signing a transaction can generate a transaction with the desired properties.
|
||||
- The correlation between time and block number is not fixed; even though a 14s blocktime is 'desired', this varies due to both network hashrate and difficulty bomb progression.
|
||||
- The block number is even more unreliable as a timestamp for testnets and private networks.
|
||||
- UTC time is more user-friendly, a user can more easily decide on reasonable end-date for a transaction, rather than a suitalbe number of valid blocks.
|
||||
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
This EIP means that all software/hardware that creates transactions need to add timestamps to the transactions, or will otherwise be incapable of signing transactions after block `Y`. Note: this EIP does not introduce any maximum `valid-until` date, so it would still be possible to create
|
||||
transactions with near infinite validity.
|
||||
|
||||
## Test Cases
|
||||
|
||||
todo
|
||||
|
||||
## Implementation
|
||||
|
||||
None yet
|
||||
|
||||
## Security considerations
|
||||
|
||||
The most notable security impact is that pre-signed transactions stored on paper backups, will become invalid as of block `Y`. There are a couple of cases where this might be used
|
||||
- Pregenerated onetime 'bootstrap' transactions, e.g. to onboard a user into Ethereum. Instead of giving a user a giftcard with actual ether on it, someone may instead give the person a one-time pregenerated transaction that will only send those ether to the card once the
|
||||
user actively wants to start using it.
|
||||
- If a user has an offline paper-wallet, he may have pregenerated transactions to send value to e.g. an exchange. This is sometimes done to be able to send ether to an exchange without having to go through all the hoops of bringing the paper wallet back to 'life'.
|
||||
|
||||
Secondary security impacts are that the addition of a timestamp would make the transactions a little bit larger.
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
eip: 1706
|
||||
title: Disable SSTORE with gasleft lower than call stipend
|
||||
author: Alex Forshtat <alex@tabookey.com>, Yoav Weiss <yoav@tabookey.com>
|
||||
discussions-to: https://github.com/alex-forshtat-tbk/EIPs/issues/1
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2019-01-15
|
||||
requires: 1283
|
||||
---
|
||||
|
||||
<!--You can leave these HTML comments in your merged EIP and delete the visible duplicate text guides, they will not appear and may be helpful to refer to if you edit it again. This is the suggested template for new EIPs. Note that an EIP number will be assigned by an editor. When opening a pull request to submit your EIP, please use an abbreviated title in the filename, `eip-draft_title_abbrev.md`. The title should be 44 characters or less.-->
|
||||
|
||||
## Simple Summary
|
||||
<!--"If you can't explain it simply, you don't understand it well enough." Provide a simplified and layman-accessible explanation of the EIP.-->
|
||||
The proposal that had been accepted changes security properties of a large portion of an existing contract code base that may be infeasible to update and validate. This proposal will make the old assumptions hold even after a network upgrade.
|
||||
|
||||
## Abstract
|
||||
<!--A short (~200 word) description of the technical issue being addressed.-->
|
||||
[EIP-1283](https://eips.ethereum.org/EIPS/eip-1283) significantly lowers the gas costs of writing to contract's storage. This created a danger of a new kind of reentrancy attacks on existing contracts as Solidity by default grants a 'stipend' of 2300 gas to simple transfer calls.
|
||||
This danger is easily mitigated if SSTORE is not allowed in low gasleft state, without breaking the backward compatibility and the original intention of this EIP.
|
||||
|
||||
## Motivation
|
||||
<!--The motivation is critical for EIPs that want to change the Ethereum protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the EIP solves. EIP submissions without sufficient motivation may be rejected outright.-->
|
||||
|
||||
An attack that is described in [this article](https://medium.com/chainsecurity/constantinople-enables-new-reentrancy-attack-ace4088297d9).
|
||||
Explicitly specifying the call stipend as an invariant will have a positive effect on Ethereum protocol security:
|
||||
https://www.reddit.com/r/ethereum/comments/agdqsm/security_alert_ethereum_constantinople/ee5uvjt
|
||||
|
||||
## Specification
|
||||
<!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (go-ethereum, parity, cpp-ethereum, ethereumj, ethereumjs, and [others](https://github.com/ethereum/wiki/wiki/Clients)).-->
|
||||
|
||||
Add the following condition to to the SSTORE opcode gas cost calculation:
|
||||
|
||||
* If *gasleft* is less than or equal to 2300, fail the current call frame
|
||||
with 'out of gas' exception.
|
||||
|
||||
## Rationale
|
||||
<!--The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The rationale may also provide evidence of consensus within the community, and should discuss important objections or concerns raised during discussion.-->
|
||||
In order to keep in place the implicit reentrancy protection of existing contracts, transactions should not be allowed to modify state if the remaining gas is lower then the 2300 stipend given to 'transfer'/'send' in Solidity.
|
||||
These are other proposed remediations and objections to implementing them:
|
||||
|
||||
* Drop EIP-1283 and abstain from modifying SSTORE cost
|
||||
* EIP-1283 is an important update
|
||||
* It was accepted and implemented on test networks and in clients.
|
||||
* Add a new call context that permits LOG opcodes but not changes to state.
|
||||
* Adds another call type beyond existing regular/staticcall
|
||||
* Raise the cost of SSTORE to dirty slots to >=2300 gas
|
||||
* Makes net gas metering much less useful.
|
||||
* Reduce the gas stipend
|
||||
* Makes the stipend almost useless.
|
||||
* Increase the cost of writes to dirty slots back to 5000 gas, but add 4800 gas to the refund counter
|
||||
* Still doesn’t make the invariant explicit.
|
||||
* Requires callers to supply more gas, just to have it refunded
|
||||
* Add contract metadata specifying per-contract EVM version, and only apply SSTORE changes to contracts deployed with the new version.
|
||||
|
||||
|
||||
## Backwards Compatibility
|
||||
<!--All EIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The EIP must explain how the author proposes to deal with these incompatibilities. EIP submissions without a sufficient backwards compatibility treatise may be rejected outright.-->
|
||||
Performing SSTORE has never been possible with less than 5000 gas, so it does not introduce incompatibility to the Ethereum mainnet. Gas estimation should account for this requirement.
|
||||
|
||||
## Test Cases
|
||||
<!--Test cases for an implementation are mandatory for EIPs that are affecting consensus changes. Other EIPs can choose to include links to test cases if applicable.-->
|
||||
Test cases for an implementation are mandatory for EIPs that are affecting consensus changes. Other EIPs can choose to include links to test cases if applicable.
|
||||
TODO
|
||||
## Implementation
|
||||
<!--The implementations must be completed before any EIP is given status "Final", but it need not be completed before the EIP is accepted. While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of "rough consensus and running code" is still useful when it comes to resolving many discussions of API details.-->
|
||||
TODO
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
eip: 1716
|
||||
title: "Hardfork Meta: Petersburg"
|
||||
author: Afri Schoedon (@5chdn), Marius van der Wijden (@MariusVanDerWijden)
|
||||
type: Meta
|
||||
status: Final
|
||||
created: 2019-01-21
|
||||
requires: 1013, 1283
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
||||
This meta-EIP specifies the changes included in the Ethereum hardfork that removes [EIP-1283](./eip-1283.md) from [Constantinople](./eip-1013.md).
|
||||
|
||||
## Specification
|
||||
|
||||
- Codename: Petersburg
|
||||
- Aliases: St. Petersfork, Peter's Fork, Constantinople Fix
|
||||
- Activation:
|
||||
- `Block >= 7_280_000` on the Ethereum mainnet
|
||||
- `Block >= 4_939_394` on the Ropsten testnet
|
||||
- `Block >= 10_255_201` on the Kovan testnet
|
||||
- `Block >= 9_999_999` on the Rinkeby testnet
|
||||
- `Block >= 0` on the Görli testnet
|
||||
- Removed EIPs:
|
||||
- [EIP 1283](./eip-1283.md): Net gas metering for SSTORE without dirty maps
|
||||
|
||||
If `Petersburg` and `Constantinople` are applied at the same block, `Petersburg` takes precedence: with the net effect of EIP-1283 being _disabled_.
|
||||
|
||||
If `Petersburg` is defined with an earlier block number than `Constantinople`, then there is _no immediate effect_ from the `Petersburg` fork. However, when `Constantinople` is later activated, EIP-1283 should be _disabled_.
|
||||
|
||||
## References
|
||||
|
||||
1. The list above includes the EIPs that had to be removed from Constantinople due to a [potential reentrancy attack vector](https://medium.com/chainsecurity/constantinople-enables-new-reentrancy-attack-ace4088297d9). Removing this was agreed upon at the [All-Core-Devs call #53 in January 2019](https://github.com/ethereum/pm/issues/70).
|
||||
2. https://blog.ethereum.org/2019/02/22/ethereum-constantinople-st-petersburg-upgrade-announcement/
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -0,0 +1,175 @@
|
|||
---
|
||||
eip: 1761
|
||||
title: ERC-1761 Scoped Approval Interface
|
||||
author: Witek Radomski <witek@enjin.com>, Andrew Cooke <andrew@enjin.com>, James Therien <james@enjin.com>, Eric Binet <eric@enjin.com>
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
status: Draft
|
||||
created: 2019-02-18
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/1761
|
||||
requires: 165
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
|
||||
A standard interface to permit restricted approval in token contracts by defining "scopes" of one or more Token IDs.
|
||||
|
||||
## Abstract
|
||||
|
||||
This interface is designed for use with token contracts that have an "ID" domain, such as ERC-1155 or ERC-721. This enables restricted approval of one or more Token IDs to a specific "scope". When considering a smart contract managing tokens from multiple different domains, it makes sense to limit approvals to those domains. Scoped approval is a generalization of this idea. Implementors can define scopes as needed.
|
||||
|
||||
Sample use cases for scopes:
|
||||
|
||||
* A company may represent its fleet of vehicles on the blockchain and it could create a scope for each regional office.
|
||||
* Game developers could share an [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) contract where each developer manages tokens under a specified scope.
|
||||
* Tokens of different value could be split into separate scopes. High-value tokens could be kept in smaller separate scopes while low-value tokens might be kept in a shared scope. Users would approve the entire low-value token scope to a third-party smart contract, exchange, or other application without concern about losing their high-value tokens in the event of a problem.
|
||||
|
||||
## Motivation
|
||||
|
||||
It may be desired to restrict approval in some applications. Restricted approval can prevent losses in cases where users do not audit the contracts they're approving. No standard API is supplied to manage scopes as this is implementation specific. Some implementations may opt to offer a fixed number of scopes, or assign a specific set of scopes to certain types. Other implementations may open up scope configuration to its users and offer methods to create scopes and assign IDs to them.
|
||||
|
||||
# Specification
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.5.2;
|
||||
|
||||
/**
|
||||
Note: The ERC-165 identifier for this interface is 0x30168307.
|
||||
*/
|
||||
interface ScopedApproval {
|
||||
/**
|
||||
@dev MUST emit when approval changes for scope.
|
||||
*/
|
||||
event ApprovalForScope(address indexed _owner, address indexed _operator, bytes32 indexed _scope, bool _approved);
|
||||
|
||||
/**
|
||||
@dev MUST emit when the token IDs are added to the scope.
|
||||
By default, IDs are in no scope.
|
||||
The range is inclusive: _idStart, _idEnd, and all IDs in between have been added to the scope.
|
||||
_idStart must be lower than or equal to _idEnd.
|
||||
*/
|
||||
event AddIdsToScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope);
|
||||
|
||||
/**
|
||||
@dev MUST emit when the token IDs are removed from the scope.
|
||||
The range is inclusive: _idStart, _idEnd, and all IDs in between have been removed from the scope.
|
||||
_idStart must be lower than or equal to _idEnd.
|
||||
*/
|
||||
event RemoveIdsFromScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope);
|
||||
|
||||
/** @dev MUST emit when a scope URI is set or changes.
|
||||
URIs are defined in RFC 3986.
|
||||
The URI MUST point a JSON file that conforms to the "Scope Metadata JSON Schema".
|
||||
*/
|
||||
event ScopeURI(string _value, bytes32 indexed _scope);
|
||||
|
||||
/**
|
||||
@notice Returns the number of scopes that contain _id.
|
||||
@param _id The token ID
|
||||
@return The number of scopes containing the ID
|
||||
*/
|
||||
function scopeCountForId(uint256 _id) public view returns (uint32);
|
||||
|
||||
/**
|
||||
@notice Returns a scope that contains _id.
|
||||
@param _id The token ID
|
||||
@param _scopeIndex The scope index to query (valid values are 0 to scopeCountForId(_id)-1)
|
||||
@return The Nth scope containing the ID
|
||||
*/
|
||||
function scopeForId(uint256 _id, uint32 _scopeIndex) public view returns (bytes32);
|
||||
|
||||
/**
|
||||
@notice Returns a URI that can be queried to get scope metadata. This URI should return a JSON document containing, at least the scope name and description. Although supplying a URI for every scope is recommended, returning an empty string "" is accepted for scopes without a URI.
|
||||
@param _scope The queried scope
|
||||
@return The URI describing this scope.
|
||||
*/
|
||||
function scopeUri(bytes32 _scope) public view returns (string memory);
|
||||
|
||||
/**
|
||||
@notice Enable or disable approval for a third party ("operator") to manage the caller's tokens in the specified scope.
|
||||
@dev MUST emit the ApprovalForScope event on success.
|
||||
@param _operator Address to add to the set of authorized operators
|
||||
@param _scope Approval scope (can be identified by calling scopeForId)
|
||||
@param _approved True if the operator is approved, false to revoke approval
|
||||
*/
|
||||
function setApprovalForScope(address _operator, bytes32 _scope, bool _approved) external;
|
||||
|
||||
/**
|
||||
@notice Queries the approval status of an operator for a given owner, within the specified scope.
|
||||
@param _owner The owner of the Tokens
|
||||
@param _operator Address of authorized operator
|
||||
@param _scope Scope to test for approval (can be identified by calling scopeForId)
|
||||
@return True if the operator is approved, false otherwise
|
||||
*/
|
||||
function isApprovedForScope(address _owner, address _operator, bytes32 _scope) public view returns (bool);
|
||||
}
|
||||
```
|
||||
|
||||
## Scope Metadata JSON Schema
|
||||
|
||||
This schema allows for localization. `{id}` and `{locale}` should be replaced with the appropriate values by clients.
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Scope Metadata",
|
||||
"type": "object",
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Identifies the scope in a human-readable way.",
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Describes the scope to allow users to make informed approval decisions.",
|
||||
},
|
||||
"localization": {
|
||||
"type": "object",
|
||||
"required": ["uri", "default", "locales"],
|
||||
"properties": {
|
||||
"uri": {
|
||||
"type": "string",
|
||||
"description": "The URI pattern to fetch localized data from. This URI should contain the substring `{locale}` which will be replaced with the appropriate locale value before sending the request."
|
||||
},
|
||||
"default": {
|
||||
"type": "string",
|
||||
"description": "The locale of the default data within the base JSON"
|
||||
},
|
||||
"locales": {
|
||||
"type": "array",
|
||||
"description": "The list of locales for which data is available. These locales should conform to those defined in the Unicode Common Locale Data Repository (http://cldr.unicode.org/)."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Localization
|
||||
|
||||
Metadata localization should be standardized to increase presentation uniformity across all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content may be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software.
|
||||
|
||||
## Rationale
|
||||
|
||||
The initial design was proposed as an extension to ERC-1155: [Discussion Thread - Comment 1](https://github.com/ethereum/EIPs/issues/1155#issuecomment-459505728). After some discussion: [Comment 2](https://github.com/ethereum/EIPs/issues/1155#issuecomment-460603439) and suggestions by the community to implement this approval mechanism in an external contract [Comment 3](https://github.com/ethereum/EIPs/issues/1155#issuecomment-461758755), it was decided that as an interface standard, this design would allow many different token standards such as ERC-721 and ERC-1155 to implement scoped approvals without forcing the system into all implementations of the tokens.
|
||||
|
||||
### Metadata JSON
|
||||
|
||||
The Scope Metadata JSON Schema was added in order to support human-readable scope names and descriptions in more than one language.
|
||||
|
||||
## References
|
||||
|
||||
**Standards**
|
||||
- [ERC-1155 Multi Token Standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md)
|
||||
- [ERC-165 Standard Interface Detection](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md)
|
||||
- [JSON Schema](http://json-schema.org/)
|
||||
|
||||
**Implementations**
|
||||
- [Enjin Coin](https://enjincoin.io) ([github](https://github.com/enjin))
|
||||
|
||||
**Articles & Discussions**
|
||||
- [Github - Original Discussion Thread](https://github.com/ethereum/EIPs/issues/1761)
|
||||
- [Github - ERC-1155 Discussion Thread](https://github.com/ethereum/EIPs/issues/1155)
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -0,0 +1,414 @@
|
|||
---
|
||||
eip: 1767
|
||||
title: GraphQL interface to Ethereum node data
|
||||
author: Nick Johnson (@arachnid), Raúl Kripalani (@raulk), Kris Shinn (@kshinn)
|
||||
discussions-to: https://ethereum-magicians.org/t/graphql-interface-to-ethereum-node-data/2710
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Interface
|
||||
created: 2019-02-14
|
||||
---
|
||||
|
||||
## Abstract
|
||||
This EIP specifies a GraphQL schema for accessing data stored on an Ethereum node. It aims to provide a complete replacement to the read-only information exposed via the present JSON-RPC interface, while improving on usability, consistency, efficiency, and future-proofing.
|
||||
|
||||
## Motivation
|
||||
The current JSON-RPC interface for Ethereum nodes has a number of shortcomings. It's informally and incompletely specified in areas, which has led to incompatibilities around issues such as representation of empty byte strings ("" vs "0x" vs "0x0"), and it has to make educated guesses about the data a user will request, which often leads to unnecessary work.
|
||||
|
||||
For example, the `totalDifficulty` field is stored separately from the block header in common Ethereum node implementations, and many callers do not require this field. However, every call to `eth_getBlock` still retrieves this field, requiring a separate disk read, because the RPC server has no way of knowing if the user requires this field or not.
|
||||
|
||||
Similarly, transaction receipts in go-ethereum are stored on disk as a single binary blob for each block. Fetching a receipt for a single transaction requires fetching and deserializing this blob, then finding the relevant entry and returning it; this is accomplished by the `eth_getTransactionReceipt` API call. A common task for API consumers is to fetch all the receipts in a block; as a result, node implementations end up fetching and deserializing the same data repeatedly, leading to `O(n^2)` effort to fetch all transaction receipts from a block instead of `O(n)`.
|
||||
|
||||
Some of these issues could be fixed with changes to the existing JSON-RPC interface, at the cost of complicating the interface somewhat. Instead, we propose adopting a standard query language, GraphQL, which facilitates more efficient API implementations, while also increasing flexibility.
|
||||
|
||||
## Prior Art
|
||||
|
||||
Nick Johnson and [EthQL](https://github.com/ConsenSys/ethql) independently developed a GraphQL schema for node data. Once the parties were made aware of the shared effort, they made efforts to bring their schemas into alignment. The current schema proposed in this EIP is derived primarily from the EthQL schema.
|
||||
|
||||
## Specification
|
||||
|
||||
### Node API
|
||||
|
||||
Compatible nodes MUST provide a GraphQL endpoint available over HTTP. This SHOULD be offered on port 8547 by default. The path to the GraphQL endpoint SHOULD be '/graphql'.
|
||||
|
||||
Compatible nodes MAY offer a GraphiQL interactive query explorer on the root path ('/').
|
||||
|
||||
### Schema
|
||||
|
||||
The GraphQL schema for this service is defined as follows:
|
||||
```
|
||||
# Bytes32 is a 32 byte binary string, represented as 0x-prefixed hexadecimal.
|
||||
scalar Bytes32
|
||||
# Address is a 20 byte Ethereum address, represented as 0x-prefixed hexadecimal.
|
||||
scalar Address
|
||||
# Bytes is an arbitrary length binary string, represented as 0x-prefixed hexadecimal.
|
||||
# An empty byte string is represented as '0x'. Byte strings must have an even number of hexadecimal nybbles.
|
||||
scalar Bytes
|
||||
# BigInt is a large integer. Input is accepted as either a JSON number or as a string.
|
||||
# Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all
|
||||
# 0x-prefixed hexadecimal.
|
||||
scalar BigInt
|
||||
# Long is a 64 bit unsigned integer.
|
||||
scalar Long
|
||||
|
||||
schema {
|
||||
query: Query
|
||||
mutation: Mutation
|
||||
}
|
||||
|
||||
# Account is an Ethereum account at a particular block.
|
||||
type Account {
|
||||
# Address is the address owning the account.
|
||||
address: Address!
|
||||
# Balance is the balance of the account, in wei.
|
||||
balance: BigInt!
|
||||
# TransactionCount is the number of transactions sent from this account,
|
||||
# or in the case of a contract, the number of contracts created. Otherwise
|
||||
# known as the nonce.
|
||||
transactionCount: Long!
|
||||
# Code contains the smart contract code for this account, if the account
|
||||
# is a (non-self-destructed) contract.
|
||||
code: Bytes!
|
||||
# Storage provides access to the storage of a contract account, indexed
|
||||
# by its 32 byte slot identifier.
|
||||
storage(slot: Bytes32!): Bytes32!
|
||||
}
|
||||
|
||||
# Log is an Ethereum event log.
|
||||
type Log {
|
||||
# Index is the index of this log in the block.
|
||||
index: Int!
|
||||
# Account is the account which generated this log - this will always
|
||||
# be a contract account.
|
||||
account(block: Long): Account!
|
||||
# Topics is a list of 0-4 indexed topics for the log.
|
||||
topics: [Bytes32!]!
|
||||
# Data is unindexed data for this log.
|
||||
data: Bytes!
|
||||
# Transaction is the transaction that generated this log entry.
|
||||
transaction: Transaction!
|
||||
}
|
||||
|
||||
# Transaction is an Ethereum transaction.
|
||||
type Transaction {
|
||||
# Hash is the hash of this transaction.
|
||||
hash: Bytes32!
|
||||
# Nonce is the nonce of the account this transaction was generated with.
|
||||
nonce: Long!
|
||||
# Index is the index of this transaction in the parent block. This will
|
||||
# be null if the transaction has not yet been mined.
|
||||
index: Int
|
||||
# From is the account that sent this transaction - this will always be
|
||||
# an externally owned account.
|
||||
from(block: Long): Account!
|
||||
# To is the account the transaction was sent to. This is null for
|
||||
# contract-creating transactions.
|
||||
to(block: Long): Account
|
||||
# Value is the value, in wei, sent along with this transaction.
|
||||
value: BigInt!
|
||||
# GasPrice is the price offered to miners for gas, in wei per unit.
|
||||
gasPrice: BigInt!
|
||||
# Gas is the maximum amount of gas this transaction can consume.
|
||||
gas: Long!
|
||||
# InputData is the data supplied to the target of the transaction.
|
||||
inputData: Bytes!
|
||||
# Block is the block this transaction was mined in. This will be null if
|
||||
# the transaction has not yet been mined.
|
||||
block: Block
|
||||
|
||||
# Status is the return status of the transaction. This will be 1 if the
|
||||
# transaction succeeded, or 0 if it failed (due to a revert, or due to
|
||||
# running out of gas). If the transaction has not yet been mined, this
|
||||
# field will be null.
|
||||
status: Long
|
||||
# GasUsed is the amount of gas that was used processing this transaction.
|
||||
# If the transaction has not yet been mined, this field will be null.
|
||||
gasUsed: Long
|
||||
# CumulativeGasUsed is the total gas used in the block up to and including
|
||||
# this transaction. If the transaction has not yet been mined, this field
|
||||
# will be null.
|
||||
cumulativeGasUsed: Long
|
||||
# CreatedContract is the account that was created by a contract creation
|
||||
# transaction. If the transaction was not a contract creation transaction,
|
||||
# or it has not yet been mined, this field will be null.
|
||||
createdContract(block: Long): Account
|
||||
# Logs is a list of log entries emitted by this transaction. If the
|
||||
# transaction has not yet been mined, this field will be null.
|
||||
logs: [Log!]
|
||||
}
|
||||
|
||||
# BlockFilterCriteria encapsulates log filter criteria for a filter applied
|
||||
# to a single block.
|
||||
input BlockFilterCriteria {
|
||||
# Addresses is list of addresses that are of interest. If this list is
|
||||
# empty, results will not be filtered by address.
|
||||
addresses: [Address!]
|
||||
# Topics list restricts matches to particular event topics. Each event has a list
|
||||
# of topics. Topics matches a prefix of that list. An empty element array matches any
|
||||
# topic. Non-empty elements represent an alternative that matches any of the
|
||||
# contained topics.
|
||||
#
|
||||
# Examples:
|
||||
# - [] or nil matches any topic list
|
||||
# - [[A]] matches topic A in first position
|
||||
# - [[], [B]] matches any topic in first position, B in second position
|
||||
# - [[A], [B]] matches topic A in first position, B in second position
|
||||
# - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position
|
||||
topics: [[Bytes32!]!]
|
||||
}
|
||||
|
||||
# Block is an Ethereum block.
|
||||
type Block {
|
||||
# Number is the number of this block, starting at 0 for the genesis block.
|
||||
number: Long!
|
||||
# Hash is the block hash of this block.
|
||||
hash: Bytes32!
|
||||
# Parent is the parent block of this block.
|
||||
parent: Block
|
||||
# Nonce is the block nonce, an 8 byte sequence determined by the miner.
|
||||
nonce: Bytes!
|
||||
# TransactionsRoot is the keccak256 hash of the root of the trie of transactions in this block.
|
||||
transactionsRoot: Bytes32!
|
||||
# TransactionCount is the number of transactions in this block. if
|
||||
# transactions are not available for this block, this field will be null.
|
||||
transactionCount: Int
|
||||
# StateRoot is the keccak256 hash of the state trie after this block was processed.
|
||||
stateRoot: Bytes32!
|
||||
# ReceiptsRoot is the keccak256 hash of the trie of transaction receipts in this block.
|
||||
receiptsRoot: Bytes32!
|
||||
# Miner is the account that mined this block.
|
||||
miner(block: Long): Account!
|
||||
# ExtraData is an arbitrary data field supplied by the miner.
|
||||
extraData: Bytes!
|
||||
# GasLimit is the maximum amount of gas that was available to transactions in this block.
|
||||
gasLimit: Long!
|
||||
# GasUsed is the amount of gas that was used executing transactions in this block.
|
||||
gasUsed: Long!
|
||||
# Timestamp is the unix timestamp at which this block was mined.
|
||||
timestamp: BigInt!
|
||||
# LogsBloom is a bloom filter that can be used to check if a block may
|
||||
# contain log entries matching a filter.
|
||||
logsBloom: Bytes!
|
||||
# MixHash is the hash that was used as an input to the PoW process.
|
||||
mixHash: Bytes32!
|
||||
# Difficulty is a measure of the difficulty of mining this block.
|
||||
difficulty: BigInt!
|
||||
# TotalDifficulty is the sum of all difficulty values up to and including
|
||||
# this block.
|
||||
totalDifficulty: BigInt!
|
||||
# OmmerCount is the number of ommers (AKA uncles) associated with this
|
||||
# block. If ommers are unavailable, this field will be null.
|
||||
ommerCount: Int
|
||||
# Ommers is a list of ommer (AKA uncle) blocks associated with this block.
|
||||
# If ommers are unavailable, this field will be null. Depending on your
|
||||
# node, the transactions, transactionAt, transactionCount, ommers,
|
||||
# ommerCount and ommerAt fields may not be available on any ommer blocks.
|
||||
ommers: [Block]
|
||||
# OmmerAt returns the ommer (AKA uncle) at the specified index. If ommers
|
||||
# are unavailable, or the index is out of bounds, this field will be null.
|
||||
ommerAt(index: Int!): Block
|
||||
# OmmerHash is the keccak256 hash of all the ommers (AKA uncles)
|
||||
# associated with this block.
|
||||
ommerHash: Bytes32!
|
||||
# Transactions is a list of transactions associated with this block. If
|
||||
# transactions are unavailable for this block, this field will be null.
|
||||
transactions: [Transaction!]
|
||||
# TransactionAt returns the transaction at the specified index. If
|
||||
# transactions are unavailable for this block, or if the index is out of
|
||||
# bounds, this field will be null.
|
||||
transactionAt(index: Int!): Transaction
|
||||
# Logs returns a filtered set of logs from this block.
|
||||
logs(filter: BlockFilterCriteria!): [Log!]!
|
||||
# Account fetches an Ethereum account at the current block's state.
|
||||
account(address: Address!): Account!
|
||||
# Call executes a local call operation at the current block's state.
|
||||
call(data: CallData!): CallResult
|
||||
# EstimateGas estimates the amount of gas that will be required for
|
||||
# successful execution of a transaction at the current block's state.
|
||||
estimateGas(data: CallData!): Long!
|
||||
}
|
||||
|
||||
# CallData represents the data associated with a local contract call.
|
||||
# All fields are optional.
|
||||
input CallData {
|
||||
# From is the address making the call.
|
||||
from: Address
|
||||
# To is the address the call is sent to.
|
||||
to: Address
|
||||
# Gas is the amount of gas sent with the call.
|
||||
gas: Long
|
||||
# GasPrice is the price, in wei, offered for each unit of gas.
|
||||
gasPrice: BigInt
|
||||
# Value is the value, in wei, sent along with the call.
|
||||
value: BigInt
|
||||
# Data is the data sent to the callee.
|
||||
data: Bytes
|
||||
}
|
||||
|
||||
# CallResult is the result of a local call operation.
|
||||
type CallResult {
|
||||
# Data is the return data of the called contract.
|
||||
data: Bytes!
|
||||
# GasUsed is the amount of gas used by the call, after any refunds.
|
||||
gasUsed: Long!
|
||||
# Status is the result of the call - 1 for success or 0 for failure.
|
||||
status: Long!
|
||||
}
|
||||
|
||||
# FilterCriteria encapsulates log filter criteria for searching log entries.
|
||||
input FilterCriteria {
|
||||
# FromBlock is the block at which to start searching, inclusive. Defaults
|
||||
# to the latest block if not supplied.
|
||||
fromBlock: Long
|
||||
# ToBlock is the block at which to stop searching, inclusive. Defaults
|
||||
# to the latest block if not supplied.
|
||||
toBlock: Long
|
||||
# Addresses is a list of addresses that are of interest. If this list is
|
||||
# empty, results will not be filtered by address.
|
||||
addresses: [Address!]
|
||||
# Topics list restricts matches to particular event topics. Each event has a list
|
||||
# of topics. Topics matches a prefix of that list. An empty element array matches any
|
||||
# topic. Non-empty elements represent an alternative that matches any of the
|
||||
# contained topics.
|
||||
#
|
||||
# Examples:
|
||||
# - [] or nil matches any topic list
|
||||
# - [[A]] matches topic A in first position
|
||||
# - [[], [B]] matches any topic in first position, B in second position
|
||||
# - [[A], [B]] matches topic A in first position, B in second position
|
||||
# - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position
|
||||
topics: [[Bytes32!]!]
|
||||
}
|
||||
|
||||
# SyncState contains the current synchronisation state of the client.
|
||||
type SyncState{
|
||||
# StartingBlock is the block number at which synchronisation started.
|
||||
startingBlock: Long!
|
||||
# CurrentBlock is the point at which synchronisation has presently reached.
|
||||
currentBlock: Long!
|
||||
# HighestBlock is the latest known block number.
|
||||
highestBlock: Long!
|
||||
# PulledStates is the number of state entries fetched so far, or null
|
||||
# if this is not known or not relevant.
|
||||
pulledStates: Long
|
||||
# KnownStates is the number of states the node knows of so far, or null
|
||||
# if this is not known or not relevant.
|
||||
knownStates: Long
|
||||
}
|
||||
|
||||
# Pending represents the current pending state.
|
||||
type Pending {
|
||||
# TransactionCount is the number of transactions in the pending state.
|
||||
transactionCount: Int!
|
||||
# Transactions is a list of transactions in the current pending state.
|
||||
transactions: [Transaction!]
|
||||
# Account fetches an Ethereum account for the pending state.
|
||||
account(address: Address!): Account!
|
||||
# Call executes a local call operation for the pending state.
|
||||
call(data: CallData!): CallResult
|
||||
# EstimateGas estimates the amount of gas that will be required for
|
||||
# successful execution of a transaction for the pending state.
|
||||
estimateGas(data: CallData!): Long!
|
||||
}
|
||||
|
||||
type Query {
|
||||
# Block fetches an Ethereum block by number or by hash. If neither is
|
||||
# supplied, the most recent known block is returned.
|
||||
block(number: Long, hash: Bytes32): Block
|
||||
# Blocks returns all the blocks between two numbers, inclusive. If
|
||||
# to is not supplied, it defaults to the most recent known block.
|
||||
blocks(from: Long!, to: Long): [Block!]!
|
||||
# Pending returns the current pending state.
|
||||
pending: Pending!
|
||||
# Transaction returns a transaction specified by its hash.
|
||||
transaction(hash: Bytes32!): Transaction
|
||||
# Logs returns log entries matching the provided filter.
|
||||
logs(filter: FilterCriteria!): [Log!]!
|
||||
# GasPrice returns the node's estimate of a gas price sufficient to
|
||||
# ensure a transaction is mined in a timely fashion.
|
||||
gasPrice: BigInt!
|
||||
# ProtocolVersion returns the current wire protocol version number.
|
||||
protocolVersion: Int!
|
||||
# Syncing returns information on the current synchronisation state.
|
||||
syncing: SyncState
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
# SendRawTransaction sends an RLP-encoded transaction to the network.
|
||||
sendRawTransaction(data: Bytes!): Bytes32!
|
||||
}
|
||||
```
|
||||
|
||||
Nodes MAY offer a superset of this schema, by adding new fields or types. Experimental or client-specific fields MUST be prefixed with '_client_' (eg, '_geth_' or '_parity_'). Unprefixed fields MUST be specified in a new EIP that extends this one.
|
||||
|
||||
## Rationale
|
||||
Ethereum nodes have been moving away from providing read-write functionality such as transaction and message signing, and from other services such as code compilation, in favor of a more 'unix-like' approach where each task is performed by a dedicated process. We have thus specified a core set of types and fields that reflects this trend, leaving out functionality that is presently, or intended to be, deprecated:
|
||||
|
||||
- `eth_compile*` calls are deprecated, and hence not provided here.
|
||||
- `eth_accounts`, `eth_sign`, and `eth_sendTransaction` are considered by many to be deprecated, and are not provided here; callers should use local accounts or a separate signing daemon instead.
|
||||
|
||||
Further, two areas of the current API interface have been omitted for simplicity in this initial standard, with the intention that they will be defined in a later EIP:
|
||||
|
||||
- Filters will require use of GraphQL subscriptions, and require careful consideration around the desire for nodes without local per-caller state.
|
||||
- Mining functionality is less-used and benefits less from reimplementation in GraphQL, and should be specified in a separate EIP.
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
This schema implements the bulk of the current read-only functionality provided by the JSON-RPC node interface. Existing RPC calls can be mapped to GraphQL queries as follows:
|
||||
|
||||
| RPC | Status | Description |
|
||||
| --- | ------ | ----------- |
|
||||
| eth_blockNumber | IMPLEMENTED | `{ block { number } }` |
|
||||
| eth_call | IMPLEMENTED | `{ call(data: { to: "0x...", data: "0x..." }) { data status gasUsed } }` |
|
||||
| eth_estimateGas | IMPLEMENTED | `{ estimateGas(data: { to: "0x...", data: "0x..." }) }` |
|
||||
| eth_gasPrice | IMPLEMENTED | `{ gasPrice }` |
|
||||
| eth_getBalance | IMPLEMENTED | `{ account(address: "0x...") { balance } }` |
|
||||
| eth_getBlockByHash | IMPLEMENTED | `{ block(hash: "0x...") { ... } }` |
|
||||
| eth_getBlockByNumber | IMPLEMENTED | `{ block(number: 123) { ... } }` |
|
||||
| eth_getBlockTransactionCountByHash | IMPLEMENTED | `{ block(hash: "0x...") { transactionCount } }` |
|
||||
| eth_getBlockTransactionCountByNumber | IMPLEMENTED | `{ block(number: x) { transactionCounnt } }` |
|
||||
| eth_getCode | IMPLEMENTED | `{ account(address: "0x...") { code } }` |
|
||||
| eth_getLogs | IMPLEMENTED | `{ logs(filter: { ... }) { ... } }` or `{ block(...) { logs(filter: { ... }) { ... } } }` |
|
||||
| eth_getStorageAt | IMPLEMENTED | `{ account(address: "0x...") { storage(slot: "0x...") } }` |
|
||||
| eth_getTransactionByBlockHashAndIndex | IMPLEMENTED | `{ block(hash: "0x...") { transactionAt(index: x) { ... } } }` |
|
||||
| eth_getTransactionByBlockNumberAndIndex | IMPLEMENTED | `{ block(number: n) { transactionAt(index: x) { ... } } }` |
|
||||
| eth_getTransactionByHash | IMPLEMENTED | `{ transaction(hash: "0x...") { ... } }` |
|
||||
| eth_getTransactionCount | IMPLEMENTED | `{ account(address: "0x...") { transactionCount } }` |
|
||||
| eth_getTransactionReceipt | IMPLEMENTED | `{ transaction(hash: "0x...") { ... } }` |
|
||||
| eth_getUncleByBlockHashAndIndex | IMPLEMENTED | `{ block(hash: "0x...") { ommerAt(index: x) { ... } } }` |
|
||||
| eth_getUncleByBlockNumberAndIndex | IMPLEMENTED | `{ block(number: n) { ommerAt(index: x) { ... } } }` |
|
||||
| eth_getUncleCountByBlockHash | IMPLEMENTED | `{ block(hash: "0x...") { ommerCount } }` |
|
||||
| eth_getUncleCountByBlockNumber | IMPLEMENTED | `{ block(number: x) { ommerCount } }` |
|
||||
| eth_protocolVersion | IMPLEMENTED | `{ protocolVersion }` |
|
||||
| eth_sendRawTransaction | IMPLEMENTED | `mutation { sendRawTransaction(data: data) }` |
|
||||
| eth_syncing | IMPLEMENTED | `{ syncing { ... } }` |
|
||||
| eth_getCompilers | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. |
|
||||
| eth_compileLLL | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. |
|
||||
| eth_compileSolidity | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. |
|
||||
| eth_compileSerpent | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. |
|
||||
| eth_newFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
|
||||
| eth_newBlockFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
|
||||
| eth_newPendingTransactionFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
|
||||
| eth_uninstallFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
|
||||
| eth_getFilterChanges | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
|
||||
| eth_getFilterLogs | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
|
||||
| eth_accounts | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. |
|
||||
| eth_sign | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. |
|
||||
| eth_sendTransaction | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. |
|
||||
| eth_coinbase | NOT IMPLEMENTED | Mining functionality to be defined separately. |
|
||||
| eth_getWork | NOT IMPLEMENTED | Mining functionality to be defined separately. |
|
||||
| eth_hashRate | NOT IMPLEMENTED | Mining functionality to be defined separately. |
|
||||
| eth_mining | NOT IMPLEMENTED | Mining functionality to be defined separately. |
|
||||
| eth_submitHashrate | NOT IMPLEMENTED | Mining functionality to be defined separately. |
|
||||
| eth_submitWork | NOT IMPLEMENTED | Mining functionality to be defined separately. |
|
||||
|
||||
For specific reasoning behind omitted functionality, see the Rationale section.
|
||||
|
||||
## Test Cases
|
||||
TBD.
|
||||
|
||||
## Implementation
|
||||
A go-ethereum implementation was completed in [PR 18445](https://github.com/ethereum/go-ethereum/pull/18445) and will be available in a forthcoming geth release.
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -0,0 +1,442 @@
|
|||
---
|
||||
eip: 1812
|
||||
title: Ethereum Verifiable Claims
|
||||
author: Pelle Braendgaard <@pelle>
|
||||
discussions-to: https://ethereum-magicians.org/t/erc-1812-ethereum-verifiable-claims/2814
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
created: 2019-03-03
|
||||
requires: 712
|
||||
---
|
||||
|
||||
# Ethereum Verifiable Claims
|
||||
|
||||
## Simple Summary
|
||||
|
||||
Reusable Verifiable Claims using [EIP 712 Signed Typed Data](https://github.com/ethereum/EIPs/issues/712).
|
||||
|
||||
## Abstract
|
||||
A new method for Off-Chain Verifiable Claims built on [EIP 712](https://github.com/ethereum/EIPs/issues/712). These Claims can be issued by any user with a EIP 712 compatible web3 provider. Claims can be stored off chain and verified on-chain by Solidity Smart Contracts, State Channel Implementations or off-chain libraries.
|
||||
|
||||
## Motivation
|
||||
Reusable Off-Chain Verifiable Claims provide an important piece of integrating smart contracts with real world organizational requirements such as meeting regulatory requirements such as KYC, GDPR, Accredited Investor rules etc.
|
||||
|
||||
[ERC 735](https://github.com/ethereum/EIPs/issues/735) and [ERC 780](https://github.com/ethereum/EIPs/issues/780) provide methods of making claims that live on chain. This is useful for some particular use cases, where some claim about an address must be verified on chain.
|
||||
|
||||
In most cases though it is both dangerous and in some cases illegal (according to EU GDPR rules for example) to record Identity Claims containing Personal Identifying Information (PII) on an immutable public database such as the Ethereum blockchain.
|
||||
|
||||
The W3C [Verifiable Claims Data Model and Representations](https://www.w3.org/TR/verifiable-claims-data-model/) as well as uPorts [Verification Message Spec](https://developer.uport.me/messages/verification) are proposed off-chain solutions.
|
||||
|
||||
While built on industry standards such as [JSON-LD](https://json-ld.org) and [JWT](https://jwt.io) neither of them are easy to integrate with the Ethereum ecosystem.
|
||||
|
||||
[EIP 712](https://eips.ethereum.org/EIPS/eip-712) introduces a new method of signing off chain Identity data. This provides both a data format based on Solidity ABI encoding that can easily be parsed on-chain an a new JSON-RPC call that is easily supported by existing Ethereum wallets and Web3 clients.
|
||||
|
||||
This format allows reusable off-chain Verifiable Claims to be cheaply issued to users, who can present them when needed.
|
||||
|
||||
## Prior Art
|
||||
Verified Identity Claims such as those proposed by [uPort](https://developer.uport.me/messages/verification) and [W3C Verifiable Claims Working Group](https://www.w3.org/2017/vc/WG/) form an important part of building up reusable identity claims.
|
||||
|
||||
[ERC 735](https://github.com/ethereum/EIPs/issues/735) and [ERC 780](https://github.com/ethereum/EIPs/issues/780) provide on-chain storage and lookups of Verifiable Claims.
|
||||
|
||||
## Specification
|
||||
### Claims
|
||||
Claims can be generalized like this:
|
||||
|
||||
> Issuer makes the claim that Subject is something or has some attribute and value.
|
||||
|
||||
Claims should be deterministic, in that the same claim signed multiple times by the same signer.
|
||||
|
||||
### Claims data structure
|
||||
Each claim should be typed based on its specific use case, which EIP 712 lets us do effortlessly. But there are 3 minimal attributes required of the claims structure.
|
||||
|
||||
* `subject` the subject of the claim as an `address` (who the claim is about)
|
||||
* `validFrom` the time in seconds encoded as a `uint256` of start of validity of claim. In most cases this would be the time of issuance, but some claims may be valid in the future or past.
|
||||
* `validTo` the time in seconds encoded as a `uint256` of when the validity of the claim expires. If you intend for the claim not to expire use `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`.
|
||||
|
||||
The basic minimal claim data structure as a Solidity struct:
|
||||
|
||||
```solidity
|
||||
struct [CLAIM TYPE] {
|
||||
address subject;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
The CLAIM TYPE is the actual name of the claim. While not required, in most cases use the taxonomy developed by [schema.org](https://schema.org/docs/full.html) which is also commonly used in other Verifiable Claims formats.
|
||||
|
||||
Example claim that issuer knows a subject:
|
||||
|
||||
```solidity
|
||||
struct Know {
|
||||
address subject;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
### Presenting a Verifiable Claim
|
||||
#### Verifying Contract
|
||||
When defining Verifiable Claims formats a Verifying Contract should be created with a public `verify()` view function. This makes it very easy for other smart contracts to verify a claim correctly.
|
||||
|
||||
It also provides a convenient interface for web3 and state channel apps to verify claims securely.
|
||||
|
||||
```solidity
|
||||
function verifyIssuer(Know memory claim, uint8 v, bytes32 r, bytes32 s) public returns (address) {
|
||||
bytes32 digest = keccak256(
|
||||
abi.encodePacked(
|
||||
"\x19\x01",
|
||||
DOMAIN_SEPARATOR,
|
||||
hash(claim)
|
||||
)
|
||||
);
|
||||
require(
|
||||
(claim.validFrom >= block.timestamp) && (block.timestamp < claim.validTo)
|
||||
, "invalid issuance timestamps");
|
||||
return ecrecover(digest, v, r, s);
|
||||
}
|
||||
```
|
||||
|
||||
#### Calling a SmartContract function
|
||||
Verifiable Claims can be presented to a solidity function call as it’s struct together with the `v`, `r` and `s` signature components.
|
||||
|
||||
```solidity
|
||||
function vouch(Know memory claim, uint8 v, bytes32 r, bytes32 s) public returns (bool) {
|
||||
address issuer = verifier.verifyIssuer(claim, v, r, s);
|
||||
require(issuer !== '0x0');
|
||||
knows[issuer][claim.subject] = block.number;
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
#### Embedding a Verifiable Claim in another Signed Typed Data structure
|
||||
The Claim struct should be embedded in another struct together with the `v`, `r` and `s` signature parameters.
|
||||
|
||||
```solidity
|
||||
struct Know {
|
||||
address subject;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
|
||||
struct VerifiableReference {
|
||||
Know delegate;
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
}
|
||||
|
||||
struct Introduction {
|
||||
address recipient;
|
||||
VerifiableReference issuer;
|
||||
}
|
||||
```
|
||||
|
||||
Each Verifiable Claim should be individually verified together with the parent Signed Typed Data structure.
|
||||
|
||||
Verifiable Claims issued to different EIP 712 Domains can be embedded within each other.
|
||||
|
||||
#### State Channels
|
||||
This proposal will not show how to use Eth Verifiable Claims as part of a specific State Channel method.
|
||||
|
||||
Any State Channel based on EIP712 should be able to include the embeddable Verifiable Claims as part of its protocol. This could be useful for exchanging private Identity Claims between the parties for regulatory reasons, while ultimately not posting them to the blockchain on conclusion of a channel.
|
||||
|
||||
### Key Delegation
|
||||
In most simple cases the issuer of a Claim is the signer of the data. There are cases however where signing should be delegated to an intermediary key.
|
||||
|
||||
KeyDelegation can be used to implement off chain signing for smart contract based addresses, server side key rotation as well as employee permissions in complex business use cases.
|
||||
|
||||
#### ERC1056 Signing Delegation
|
||||
|
||||
[ERC-1056](https://github.com/ethereum/EIPs/issues/1056) provides a method for addresses to assign delegate signers. One of the primary use cases for this is that a smart contract can allow a key pair to sign on its behalf for a certain period. It also allows server based issuance tools to institute key rotation.
|
||||
|
||||
To support this an additional `issuer` attribute can be added to the Claim Type struct. In this case the verification code should lookup the EthereumDIDRegistry to see if the signer of the data is an allowed signing delegate for the `issuer`
|
||||
|
||||
The following is the minimal struct for a Claim containing an issuer:
|
||||
|
||||
```solidity
|
||||
struct [CLAIM TYPE] {
|
||||
address subject;
|
||||
address issuer;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
If the `issuer` is specified in the struct In addition to performing the standard ERC712 verification the verification code MUST also verify that the signing address is a valid `veriKey` delegate for the address specified in the issuer.
|
||||
|
||||
```solidity
|
||||
registry.validDelegate(issuer, 'veriKey', recoveredAddress)
|
||||
```
|
||||
|
||||
|
||||
#### Embedded Delegation Proof
|
||||
There may be applications, in particularly where organizations want to allow delegates to issue claims about specific domains and types.
|
||||
|
||||
For this purpose instead of the `issuer` we allow a special claim to be embedded following this same format:
|
||||
|
||||
```solidity
|
||||
struct Delegate {
|
||||
address issuer;
|
||||
address subject;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
|
||||
struct VerifiableDelegate {
|
||||
Delegate delegate;
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
}
|
||||
|
||||
|
||||
struct [CLAIM TYPE] {
|
||||
address subject;
|
||||
VerifiedDelegate issuer;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
Delegates should be created for specific EIP 712 Domains and not be reused across Domains.
|
||||
|
||||
Implementers of new EIP 712 Domains can add further data to the `Delegate` struct to allow finer grained application specific rules to it.
|
||||
|
||||
### Claim Types
|
||||
#### Binary Claims
|
||||
A Binary claim is something that doesn’t have a particular value. It either is issued or not.
|
||||
|
||||
Examples:
|
||||
* subject is a Person
|
||||
* subject is my owner (eg. Linking an ethereum account to an owner identity)
|
||||
|
||||
Example:
|
||||
|
||||
```solidity
|
||||
struct Person {
|
||||
address issuer;
|
||||
address subject;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
This is exactly the same as the minimal claim above with the CLAIM TYPE set to [Person](https://schema.org/Person).
|
||||
|
||||
### Value Claims
|
||||
Value claims can be used to make a claim about the subject containing a specific readable value.
|
||||
|
||||
**WARNING**: Be very careful about using Value Claims as part of Smart Contract transactions. Identity Claims containing values could be a GDPR violation for the business or developer encouraging a user to post it to a public blockchain.
|
||||
|
||||
Examples:
|
||||
* subject’s name is Alice
|
||||
* subjects average account balance is 1234555
|
||||
|
||||
Each value should use the `value` field to indicate the value.
|
||||
|
||||
A Name Claim
|
||||
|
||||
```solidity
|
||||
struct Name {
|
||||
address issuer;
|
||||
address subject;
|
||||
string name;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
Average Balance
|
||||
|
||||
```solidity
|
||||
struct AverageBalance {
|
||||
address issuer;
|
||||
address subject;
|
||||
uint256 value;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
### Hashed Claims
|
||||
Hashed claims can be used to make a claim about the subject containing the hash of a claim value. Hashes should use ethereum standard `keccak256` hashing function.
|
||||
|
||||
**WARNING**: Be very careful about using Hashed Claims as part of Smart Contract transactions. Identity Claims containing hashes of known values could be a GDPR violation for the business or developer encouraging a user to post it to a public blockchain.
|
||||
|
||||
Examples:
|
||||
- [ ] hash of subject’s name is `keccak256(“Alice Torres”)`
|
||||
- [ ] hash of subject’s email is `keccak256(“alice@example.com”)`
|
||||
|
||||
Each value should use the `keccak256 ` field to indicate the hashed value. Question. The choice of using this name is that we can easily add support for future algorithms as well as maybe zkSnark proofs.
|
||||
|
||||
A Name Claim
|
||||
|
||||
```solidity
|
||||
struct Name {
|
||||
address issuer;
|
||||
address subject;
|
||||
bytes32 keccak256;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
Email Claim
|
||||
|
||||
```solidity
|
||||
struct Email {
|
||||
address issuer;
|
||||
address subject;
|
||||
bytes32 keccak256;
|
||||
uint256 validFrom;
|
||||
uint256 validTo;
|
||||
}
|
||||
```
|
||||
|
||||
### EIP 712 Domain
|
||||
The EIP 712 Domain specifies what kind of message that is to be signed and is used to differentiate between signed data types. The content MUST contain the following:
|
||||
|
||||
```solidity
|
||||
{
|
||||
name: "EIP1???Claim",
|
||||
version: 1,
|
||||
chainId: 1, // for mainnet
|
||||
verifyingContract: 0x // TBD
|
||||
salt: ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Full Combined format for EIP 712 signing:
|
||||
|
||||
Following the EIP 712 standard we can combine the Claim Type with the EIP 712 Domain and the claim itself (in the `message`) attribute.
|
||||
|
||||
Eg:
|
||||
```solidity
|
||||
{
|
||||
"types": {
|
||||
"EIP712Domain": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "chainId",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "verifyingContract",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"Email": [
|
||||
{
|
||||
"name": "subject",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "keccak256",
|
||||
"type": "bytes32"
|
||||
},
|
||||
{
|
||||
"name": "validFrom",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "validTo",
|
||||
"type": "uint256"
|
||||
}
|
||||
]
|
||||
},
|
||||
"primaryType": "Email",
|
||||
"domain": {
|
||||
"name": "EIP1??? Claim",
|
||||
"version": "1",
|
||||
"chainId": 1,
|
||||
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
|
||||
},
|
||||
"message": {
|
||||
"subject": "0x5792e817336f41de1d8f54feab4bc200624a1d9d",
|
||||
"value": "9c8465d9ae0b0bc167dee7f62880034f59313100a638dcc86a901956ea52e280",
|
||||
"validFrom": "0x0000000000000000000000000000000000000000000000000001644b74c2a0",
|
||||
"validTo": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Revocation
|
||||
Both Issuers and Subjects should be allowed to revoke Verifiable Claims. Revocations can be handled through a simple on-chain registry.
|
||||
|
||||
The ultimate rules of who should be able to revoke a claim is determined by the Verifying contract.
|
||||
|
||||
The `digest` used for revocation is the EIP712 Signed Typed Data digest.
|
||||
|
||||
```solidity
|
||||
contract RevocationRegistry {
|
||||
mapping (bytes32 => mapping (address => uint)) public revocations;
|
||||
|
||||
function revoke(bytes32 digest) public returns (bool) {
|
||||
revocations[digest][msg.sender] = block.number;
|
||||
return true;
|
||||
}
|
||||
|
||||
function revoked(address party, bytes32 digest) public view returns (bool) {
|
||||
return revocations[digest][party] > 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A verifying contract can query the Revocation Registry as such:
|
||||
|
||||
```solidity
|
||||
bytes32 digest = keccak256(
|
||||
abi.encodePacked(
|
||||
"\x19\x01",
|
||||
DOMAIN_SEPARATOR,
|
||||
hash(claim)
|
||||
)
|
||||
);
|
||||
require(valid(claim.validFrom, claim.validTo), "invalid issuance timestamps");
|
||||
address issuer = ecrecover(digest, v, r, s);
|
||||
require(!revocations.revoked(issuer, digest), "claim was revoked by issuer");
|
||||
require(!revocations.revoked(claim.subject, digest), "claim was revoked by subject");
|
||||
```
|
||||
|
||||
### Creation of Verifiable Claims Domains
|
||||
|
||||
Creating specific is Verifiable Claims Domains is out of the scope of this EIP. The Example Code has a few examples.
|
||||
|
||||
EIP’s or another process could be used to standardize specific important Domains that are universally useful across the Ethereum world.
|
||||
|
||||
## Rationale
|
||||
Signed Typed Data provides a strong foundation for Verifiable Claims that can be used in many different kinds of applications built on both Layer 1 and Layer 2 of Ethereum.
|
||||
|
||||
### Rationale for using not using a single EIP 712 Domain
|
||||
EIP712 supports complex types and domains in itself, that we believe are perfect building blocks for building Verifiable Claims for specific purposes.
|
||||
|
||||
The Type and Domain of a Claim is itself an important part of a claim and ensures that Verifiable Claims are used for the specific purposes required and not misused.
|
||||
|
||||
EIP712 Domains also allow rapid experimentation, allowing taxonomies to be built up by the community.
|
||||
|
||||
## Test Cases
|
||||
There is a repo with a few example verifiers and consuming smart contracts written in Solidity:
|
||||
|
||||
**Example Verifiers**
|
||||
* [Verifier for very simple IdVerification Verifiable Claims containing minimal Personal Data](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/IdentityClaimsVerifier.sol)
|
||||
* [Verifier for OwnershipProofs signed by a users wallet](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/OwnershipProofVerifier.sol)
|
||||
|
||||
**Example Smart Contracts**
|
||||
* [KYCCoin.sol](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/KYCCoin.sol) - Example Token allows reusable IdVerification claims issued by trusted verifiers and users to whitelist their own addresses using OwnershipProofs
|
||||
* [ConsortiumAgreement.sol](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/ConsortiumAgreements.sol) - Example Consortium Agreement smart contract. Consortium Members can issue Delegated Claims to employees or servers to interact on their behalf.
|
||||
|
||||
**Shared Registries**
|
||||
* [RevocationRegistry.sol](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/RevocationRegistry.sol)
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/_).
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,349 @@
|
|||
---
|
||||
eip: 1822
|
||||
title: Universal Upgradeable Proxy Standard (UUPS)
|
||||
author: Gabriel Barros <gabriel@terminal.co>, Patrick Gallagher <patrick@terminal.co>
|
||||
discussions-to: https://ethereum-magicians.org/t/eip-1822-universal-upgradeable-proxy-standard-uups
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
created: 2019-03-04
|
||||
---
|
||||
|
||||
## Table of contents
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [Simple Summary](#simple-summary)
|
||||
- [Abstract](#abstract)
|
||||
- [Motivation](#motivation)
|
||||
- [Terminology](#terminology)
|
||||
- [Specification](#specification)
|
||||
- [Proxy Contract](#proxy-contract)
|
||||
- [Functions](#functions)
|
||||
- [`fallback`](#fallback)
|
||||
- [`constructor`](#constructor)
|
||||
- [Proxiable Contract](#proxiable-contract)
|
||||
- [Functions](#functions-1)
|
||||
- [`proxiable`](#proxiable)
|
||||
- [`updateCodeAddress`](#updatecodeaddress)
|
||||
- [Pitfalls when using a proxy](#pitfalls-when-using-a-proxy)
|
||||
- [Separating Variables from Logic](#separating-variables-from-logic)
|
||||
- [Restricting dangerous functions](#restricting-dangerous-functions)
|
||||
- [Examples](#examples)
|
||||
- [Owned](#owned)
|
||||
- [ERC-20 Token](#erc-20-token)
|
||||
- [Proxy Contract](#proxy-contract-1)
|
||||
- [Token Logic Contract](#token-logic-contract)
|
||||
- [References](#references)
|
||||
- [Copyright](#copyright)
|
||||
<!-- /TOC -->
|
||||
|
||||
## Simple Summary
|
||||
|
||||
Standard upgradeable proxy contract.
|
||||
|
||||
## Abstract
|
||||
|
||||
The following describes a standard for proxy contracts which is universally compatible with all contracts, and does not create incompatibility between the proxy and business-logic contracts. This is achieved by utilizing a unique storage position in the proxy contract to store the Logic Contract's address. A compatibility check ensures successful upgrades. Upgrading can be performed unlimited times, or as determined by custom logic. In addition, a method for selecting from multiple constructors is provided, which does not inhibit the ability to verify bytecode.
|
||||
|
||||
## Motivation
|
||||
|
||||
- Improve upon existing proxy implementations to improve developer experience for deploying and maintaining Proxy and Logic Contracts.
|
||||
|
||||
- Standardize and improve the methods for verifying the bytecode used by the Proxy Contract.
|
||||
|
||||
## Terminology
|
||||
|
||||
- `delegatecall()` - Function in contract **A** which allows an external contract **B** (delegating) to modify **A**'s storage (see diagram below, [Solidity docs](https://solidity.readthedocs.io/en/v0.5.3/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries))
|
||||
- **Proxy Contract** - The contract **A** which stores data, but uses the logic of external contract **B** by way of `delegatecall()`.
|
||||
- **Logic Contract** - The contract **B** which contains the logic used by Proxy Contract **A**
|
||||
- **Proxiable Contract** - Inherited in Logic Contract **B** to provide the upgrade functionality
|
||||
|
||||
<p align="center"><img src="../assets/eip-1822/proxy-diagram.png" alt="diagram" width="600"/></p>
|
||||
|
||||
## Specification
|
||||
|
||||
The Proxy Contract proposed here should be deployed _as is_, and used as a drop-in replacement for any existing methods of lifecycle management of contracts. In addition to the Proxy Contract, we propose the Proxiable Contract interface/base which establishes a pattern for the upgrade which does not interfere with existing business rules. The logic for allowing upgrades can be implemented as needed.
|
||||
|
||||
### Proxy Contract
|
||||
|
||||
#### Functions
|
||||
|
||||
##### `fallback`
|
||||
|
||||
The proposed fallback function follows the common pattern seen in other Proxy Contract implementations such as [Zeppelin][1] or [Gnosis][2].
|
||||
|
||||
However, rather than forcing use of a variable, the address of the Logic Contract is stored at the defined storage position `keccak256("PROXIABLE")`. This eliminates the possibility of collision between variables in the Proxy and Logic Contracts, thus providing "universal" compatibility with any Logic Contract.
|
||||
|
||||
```javascript
|
||||
function() external payable {
|
||||
assembly { // solium-disable-line
|
||||
let contractLogic := sload(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7)
|
||||
calldatacopy(0x0, 0x0, calldatasize)
|
||||
let success := delegatecall(sub(gas, 10000), contractLogic, 0x0, calldatasize, 0, 0)
|
||||
let retSz := returndatasize
|
||||
returndatacopy(0, 0, retSz)
|
||||
switch success
|
||||
case 0 {
|
||||
revert(0, retSz)
|
||||
}
|
||||
default {
|
||||
return(0, retSz)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `constructor`
|
||||
|
||||
The proposed constructor accepts any number of arguments of any type, and thus is compatible with any Logic Contract constructor function.
|
||||
|
||||
In addition, the arbitrary nature of the Proxy Contract's constructor provides the ability to select from one or more constructor functions available in the Logic Contract source code (e.g., `constructor1`, `constructor2`, ... etc. ). Note that if multiple constructors are included in the Logic Contract, a check should be included to prohibit calling a constructor again post-initialization.
|
||||
|
||||
It's worth noting that the added functionality of supporting multiple constructors does not inhibit verification of the Proxy Contract's bytecode, since the initialization tx call data (input) can be decoded by first using the Proxy Contract ABI, and then using the Logic Contract ABI.
|
||||
|
||||
The contract below shows the proposed implementation of the Proxy Contract.
|
||||
|
||||
```javascript
|
||||
contract Proxy {
|
||||
// Code position in storage is keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7"
|
||||
constructor(bytes memory constructData, address contractLogic) public {
|
||||
// save the code address
|
||||
assembly { // solium-disable-line
|
||||
sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, contractLogic)
|
||||
}
|
||||
(bool success, bytes memory _ ) = contractLogic.delegatecall(constructData); // solium-disable-line
|
||||
require(success, "Construction failed");
|
||||
}
|
||||
|
||||
function() external payable {
|
||||
assembly { // solium-disable-line
|
||||
let contractLogic := sload(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7)
|
||||
calldatacopy(0x0, 0x0, calldatasize)
|
||||
let success := delegatecall(sub(gas, 10000), contractLogic, 0x0, calldatasize, 0, 0)
|
||||
let retSz := returndatasize
|
||||
returndatacopy(0, 0, retSz)
|
||||
switch success
|
||||
case 0 {
|
||||
revert(0, retSz)
|
||||
}
|
||||
default {
|
||||
return(0, retSz)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Proxiable Contract
|
||||
|
||||
The Proxiable Contract is included in the Logic Contract, and provides the functions needed to perform an upgrade. The compatibility check `proxiable` prevents irreparable updates during an upgrade.
|
||||
|
||||
> :warning: Warning: `updateCodeAddress` and `proxiable` must be present in the Logic Contract. Failure to include these may prevent upgrades, and could allow the Proxy Contract to become entirely unusable. See below [Restricting dangerous functions](#restricting-dangerous-functions)
|
||||
|
||||
#### Functions
|
||||
|
||||
##### `proxiable`
|
||||
|
||||
Compatibility check to ensure the new Logic Contract implements the Universal Upgradeable Proxy Standard. Note that in order to support future implementations, the `bytes32` comparison could be changed e.g., `keccak256("PROXIABLE-ERC1822-v1")`.
|
||||
|
||||
##### `updateCodeAddress`
|
||||
|
||||
Stores the Logic Contract's address at storage `keccak256("PROXIABLE")` in the Proxy Contract.
|
||||
|
||||
The contract below shows the proposed implementation of the Proxiable Contract.
|
||||
|
||||
```javascript
|
||||
contract Proxiable {
|
||||
// Code position in storage is keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7"
|
||||
|
||||
function updateCodeAddress(address newAddress) internal {
|
||||
require(
|
||||
bytes32(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7) == Proxiable(newAddress).proxiableUUID(),
|
||||
"Not compatible"
|
||||
);
|
||||
assembly { // solium-disable-line
|
||||
sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, newAddress)
|
||||
}
|
||||
}
|
||||
function proxiableUUID() public pure returns (bytes32) {
|
||||
return 0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Pitfalls when using a proxy
|
||||
|
||||
The following common best practices should be employed for all Logic Contracts when using a proxy contract.
|
||||
|
||||
### Separating Variables from Logic
|
||||
|
||||
Careful consideration should be made when designing a new Logic Contract to prevent incompatibility with the existing storage of the Proxy Contract after an upgrade. Specifically, the order in which variables are instantiated in the new contract should not be modified, and any new variables should be added after all existing variables from the previous Logic Contract
|
||||
|
||||
To facilitate this practice, we recommend utilizing a single "base" contract which holds all variables, and which is inherited in subsequent logic contract(s). This practice greatly reduces the chances of accidentally reordering variables or overwriting them in storage.
|
||||
|
||||
### Restricting dangerous functions
|
||||
|
||||
The compatibility check in the Proxiable Contract is a safety mechanism to prevent upgrading to a Logic Contract which does not implement the Universal Upgradeable Proxy Standard. However, as occurred in the parity wallet hack, it is still possible to perform irreparable damage to the Logic Contract itself.
|
||||
|
||||
In order to prevent damage to the Logic Contract, we recommend restricting permissions for any potentially damaging functions to `onlyOwner`, and giving away ownership of the Logic Contract immediately upon deployment to a null address (e.g., address(1)). Potentially damaging functions include native functions such as `SELFDESTRUCT`, as well functions whose code may originate externally such as `CALLCODE`, and `delegatecall()`. In the [ERC-20 Token](#erc-20-token) example below, a `LibraryLock` contract is used to prevent destruction of the logic contract.
|
||||
|
||||
## Examples
|
||||
|
||||
### Owned
|
||||
|
||||
In this example, we show the standard ownership example, and restrict the `updateCodeAddress` to only the owner.
|
||||
|
||||
```javascript
|
||||
contract Owned is Proxiable {
|
||||
// ensures no one can manipulate this contract once it is deployed
|
||||
address public owner = address(1);
|
||||
|
||||
function constructor1() public{
|
||||
// ensures this can be called only once per *proxy* contract deployed
|
||||
require(owner == address(0));
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function updateCode(address newCode) onlyOwner public {
|
||||
updateCodeAddress(newCode);
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(msg.sender == owner, "Only owner is allowed to perform this action");
|
||||
_;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ERC-20 Token
|
||||
|
||||
#### Proxy Contract
|
||||
|
||||
```javascript
|
||||
pragma solidity ^0.5.1;
|
||||
|
||||
contract Proxy {
|
||||
// Code position in storage is keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7"
|
||||
constructor(bytes memory constructData, address contractLogic) public {
|
||||
// save the code address
|
||||
assembly { // solium-disable-line
|
||||
sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, contractLogic)
|
||||
}
|
||||
(bool success, bytes memory _ ) = contractLogic.delegatecall(constructData); // solium-disable-line
|
||||
require(success, "Construction failed");
|
||||
}
|
||||
|
||||
function() external payable {
|
||||
assembly { // solium-disable-line
|
||||
let contractLogic := sload(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7)
|
||||
calldatacopy(0x0, 0x0, calldatasize)
|
||||
let success := delegatecall(sub(gas, 10000), contractLogic, 0x0, calldatasize, 0, 0)
|
||||
let retSz := returndatasize
|
||||
returndatacopy(0, 0, retSz)
|
||||
switch success
|
||||
case 0 {
|
||||
revert(0, retSz)
|
||||
}
|
||||
default {
|
||||
return(0, retSz)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Token Logic Contract
|
||||
|
||||
``` javascript
|
||||
|
||||
contract Proxiable {
|
||||
// Code position in storage is keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7"
|
||||
|
||||
function updateCodeAddress(address newAddress) internal {
|
||||
require(
|
||||
bytes32(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7) == Proxiable(newAddress).proxiableUUID(),
|
||||
"Not compatible"
|
||||
);
|
||||
assembly { // solium-disable-line
|
||||
sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, newAddress)
|
||||
}
|
||||
}
|
||||
function proxiableUUID() public pure returns (bytes32) {
|
||||
return 0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract Owned {
|
||||
|
||||
address owner;
|
||||
|
||||
function setOwner(address _owner) internal {
|
||||
owner = _owner;
|
||||
}
|
||||
modifier onlyOwner() {
|
||||
require(msg.sender == owner, "Only owner is allowed to perform this action");
|
||||
_;
|
||||
}
|
||||
}
|
||||
|
||||
contract LibraryLockDataLayout {
|
||||
bool public initialized = false;
|
||||
}
|
||||
|
||||
contract LibraryLock is LibraryLockDataLayout {
|
||||
// Ensures no one can manipulate the Logic Contract once it is deployed.
|
||||
// PARITY WALLET HACK PREVENTION
|
||||
|
||||
modifier delegatedOnly() {
|
||||
require(initialized == true, "The library is locked. No direct 'call' is allowed");
|
||||
_;
|
||||
}
|
||||
function initialize() internal {
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
contact ERC20DataLayout is LibraryLockDataLayout {
|
||||
uint256 public totalSupply;
|
||||
mapping(address=>uint256) public tokens;
|
||||
}
|
||||
|
||||
contract ERC20 {
|
||||
// ...
|
||||
function transfer(address to, uint256 amount) public {
|
||||
require(tokens[msg.sender] >= amount, "Not enough funds for transfer");
|
||||
tokens[to] += amount;
|
||||
tokens[msg.sender] -= amount;
|
||||
}
|
||||
}
|
||||
|
||||
contract MyToken is ERC20DataLayout, ERC20, Owned, Proxiable, LibraryLock {
|
||||
|
||||
function constructor1(uint256 _initialSupply) public {
|
||||
totalSupply = _initialSupply;
|
||||
tokens[msg.sender] = _initialSupply;
|
||||
initialize();
|
||||
setOwner(msg.sender);
|
||||
}
|
||||
function updateCode(address newCode) public onlyOwner delegatedOnly {
|
||||
updateCodeAddress(newCode);
|
||||
}
|
||||
function transfer(address to, uint256 amount) public delegatedOnly {
|
||||
ERC20.transfer(to, amount);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- ["Escape-hatch" proxy Medium Post](https://medium.com/terminaldotco/escape-hatch-proxy-efb681de108d)
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
||||
[1]: https://github.com/maraoz/solidity-proxy/blob/master/contracts/Dispatcher.sol
|
||||
[2]: https://blog.gnosis.pm/solidity-delegateproxy-contracts-e09957d0f201
|
|
@ -0,0 +1,158 @@
|
|||
---
|
||||
eip: 1829
|
||||
title: Precompile for Elliptic Curve Linear Combinations
|
||||
author: Remco Bloemen <Recmo@0x.org>
|
||||
discussions-to: https://ethereum-magicians.org/t/ewasm-precompile-for-general-elliptic-curve-math/2581
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2019-03-06
|
||||
---
|
||||
|
||||
# Precompile for Elliptic Curve Linear Combinations
|
||||
|
||||
## Simple Summary
|
||||
<!--"If you can't explain it simply, you don't understand it well enough." Provide a simplified and layman-accessible explanation of the EIP.-->
|
||||
|
||||
Currently the EVM only supports *secp261k1* in a limited way through `ecrecover` and *altbn128* through two pre-compiles. There are draft proposals to add more curves. There are many more elliptic curve that have useful application for integration with existing systems or newly developed curves for zero-knownledge proofs.
|
||||
|
||||
This EIP adds a precompile that allows whole classes of curves to be used.
|
||||
|
||||
## Abstract
|
||||
<!--A short (~200 word) description of the technical issue being addressed.-->
|
||||
|
||||
A precompile that takes a curve and computes a linear combination of curve points.
|
||||
|
||||
## Motivation
|
||||
<!--The motivation is critical for EIPs that want to change the Ethereum protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the EIP solves. EIP submissions without sufficient motivation may be rejected outright.-->
|
||||
|
||||
## Specification
|
||||
<!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (go-ethereum, parity, cpp-ethereum, ethereumj, ethereumjs, and [others](https://github.com/ethereum/wiki/wiki/Clients)).-->
|
||||
|
||||
Given integers `m, α` and `β`, scalars `s_i`, and curve points `A_i` construct the elliptic curve
|
||||
|
||||
```
|
||||
y² = x³ + α ⋅ x + β mod m
|
||||
```
|
||||
|
||||
and compute the following
|
||||
|
||||
```
|
||||
C = s₀ ⋅ A₀ + s₁ ⋅ A₁ + ⋯ + s_n ⋅ A_n
|
||||
```
|
||||
|
||||
aka *linear combination*, *inner product*, *multi-multiplication* or even *multi-exponentiation*.
|
||||
|
||||
```
|
||||
(Cx, Cy) := ecmul(m, α, β, s0, Ax0, As0, s1, Ax1, As1, ...)
|
||||
```
|
||||
|
||||
### Gas cost
|
||||
|
||||
```
|
||||
BASE_GAS = ...
|
||||
ADD_GAS = ...
|
||||
MUL_GAS = ...
|
||||
```
|
||||
|
||||
The total gas cost is `BASE_GAS` plus `ADD_GAS` for each `s_i` that is `1` and `MUL_GAS` for each `s_i > 1` (`s_i = 0` is free).
|
||||
|
||||
### Encoding of points
|
||||
|
||||
Encode as `(x, y')` where `s` is the indicates the wheter `y` or `-y` is to be taken. It follows SEC 1 v 1.9 2.3.4, except uncompressed points (`y' = 0x04`) are not supported.
|
||||
|
||||
| `y'` | `(x, y)` |
|
||||
|--------|-----|
|
||||
| `0x00` | Point at infinity |
|
||||
| `0x02` | Solution with `y` even |
|
||||
| `0x03` | Solution with `y` odd |
|
||||
|
||||
Conversion from affine coordinates to compressed coordinates is trivial: `y' = 0x02 | (y & 0x01)`.
|
||||
|
||||
### Special cases
|
||||
|
||||
**Coordinate recovery.** Set `s₀ = 1`. The output will be the recovered coordinates of `A₀`.
|
||||
|
||||
**On-curve checking.** Do coordinate recovery and compare `y` coordinate.
|
||||
|
||||
**Addition.** Set `s₀ = s₁ = 1`, the output will be `A₀ + A₁`.
|
||||
|
||||
**Doubling.** Set `s₀ = 2`. The output will be `2 ⋅ A₀`. (Note: under current gas model this may be more costly than self-addition!)
|
||||
|
||||
**Scalar multiplication.** Set only `s₀` and `A₀`.
|
||||
|
||||
**Modular square root.** Set `α = s₀ = A = 0` the output will have `Cy² = β mod m`.
|
||||
|
||||
### Edge cases
|
||||
|
||||
* Non-prime moduli or too small modulus
|
||||
* Field elements larger than modulus
|
||||
* Curve has singular points (`4 α³ + 27 β² = 0`)
|
||||
* Invalid sign bytes
|
||||
* x coordinate not on curve
|
||||
* Returning the point at infinity
|
||||
* (Please add if you spot more)
|
||||
|
||||
## Rationale
|
||||
<!--The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The rationale may also provide evidence of consensus within the community, and should discuss important objections or concerns raised during discussion.-->
|
||||
|
||||
**Generic Field and Curve.** Many important optimizations are independent of the field and curve used. Some missed specific optimizations are:
|
||||
|
||||
* Reductions specific to the binary structure of the field prime.
|
||||
* Precomputation of Montgomery factors.
|
||||
* Precomputation of multiples of certain popular points like the generator.
|
||||
* Special point addition/doubling [formulas][formulas] for `α = -3`, `α = -1`, `α = 0`, `β = 0`.
|
||||
|
||||
|
||||
[formulas]: http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
|
||||
|
||||
TODO: The special cases for `α` and `β` might be worth implementing and offered a gas discount.
|
||||
|
||||
**Compressed Coordinates.** Compressed coordinates allow contract to work with only `x` coordinates and sign bytes. It also prevents errors around points not being on-curve. Conversion to compressed coordinates is trivial.
|
||||
|
||||
**Linear Combination.** We could instead have a simple multiply `C = r ⋅ A`. In this case we would need a separate pre-compile for addition. In addtion, a linear combination allows for optimizations that like Shamir's trick that are not available in a single scalar multiplication. ECDSA requires `s₀ ⋅ A₀ + s₁ ⋅ A₁` and would benfit from this.
|
||||
|
||||
The BN254 (aka alt_bn8) multiplication operation introduced by the [EIP-196][eip196] precompile only handles a single scalar multiplication. The missed performance is such that for two or more points it is cheaper to use EVM, as pratically demonstrated by [Weierstrudel][ws].
|
||||
|
||||
[eip196]: https://eips.ethereum.org/EIPS/eip-196
|
||||
[ws]: https://medium.com/aztec-protocol/huffing-for-crypto-with-weierstrudel-9c9568c06901
|
||||
|
||||
**Variable Time Math.** When called during a transaction, there is no assumption of privacy and no mittigations for side-channel attacks are necessary.
|
||||
|
||||
**Prime Fields.** This EIP is for fields of large characteristic. It does not cover Binary fields and other fields of non-prime characteristic.
|
||||
|
||||
**256-bit modulus.** This EIP is for field moduli less than `2^{256}`. This covers many of the popular curves while still having all parameters fit in a single EVM word.
|
||||
|
||||
TODO: Consider a double-word version. 512 bits would cover all known curves except E-521. In particular it will cover the NIST P-384 curve used by the Estonian e-Identity and the BLS12-381 curve used by [ZCash Sappling][sappling].
|
||||
|
||||
[sappling]: https://z.cash/blog/new-snark-curve/
|
||||
|
||||
**Short Weierstrass Curves.** This EIP is for fields specified in short Weierstrass form. While any curve can be converted to short Weierstrass form through a [substitution of variables][cov], this misses out on the performance advantages of those specific forms.
|
||||
|
||||
[cov]: https://safecurves.cr.yp.to/equation.html
|
||||
|
||||
## Backwards Compatibility
|
||||
<!--All EIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The EIP must explain how the author proposes to deal with these incompatibilities. EIP submissions without a sufficient backwards compatibility treatise may be rejected outright.-->
|
||||
|
||||
## Test Cases
|
||||
<!--Test cases for an implementation are mandatory for EIPs that are affecting consensus changes. Other EIPs can choose to include links to test cases if applicable.-->
|
||||
|
||||
## Implementation
|
||||
<!--The implementations must be completed before any EIP is given status "Final", but it need not be completed before the EIP is accepted. While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of "rough consensus and running code" is still useful when it comes to resolving many discussions of API details.-->
|
||||
|
||||
There will be a reference implementation in Rust based on the existing libraries (in particular those by ZCash and The Matter Inc.).
|
||||
|
||||
The reference implementation will be production grade and compile to a native library with a C api and a webassembly version. Node developers are encouraged to use the reference implementation and can use either the rust library, the native C bindings or the webassembly module. Node developers can of course always decide to implement their own.
|
||||
|
||||
## References
|
||||
|
||||
This EIP overlaps in scope with
|
||||
|
||||
* [EIP-196](https://eips.ethereum.org/EIPS/eip-196): ecadd, ecmul for altbn128
|
||||
* [EIP issue 603](https://github.com/ethereum/EIPs/issues/603): ecadd, ecmul for SECP256k1.
|
||||
* [EIP 665](https://eips.ethereum.org/EIPS/eip-665): ECDSA verify for ED25519.
|
||||
* [EIP 1108](https://eips.ethereum.org/EIPS/eip-1108): Optimize ecadd and ecmul for altbn128.
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
eip: 1844
|
||||
title: ENS Interface Discovery
|
||||
author: Nick Johnson (@arachnid)
|
||||
discussions-to: https://ethereum-magicians.org/t/ens-interface-discovery/2924
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
created: 2019-03-15
|
||||
requires: 137, 165
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
Defines a method of associating contract interfaces with ENS names and addresses, and of discovering those interfaces.
|
||||
|
||||
## Abstract
|
||||
This EIP specifies a method for exposing interfaces associated with an ENS name or an address (typically a contract address) and allowing applications to discover those interfaces and interact with them. Interfaces can be implemented either by the target contract (if any) or by any other contract.
|
||||
|
||||
## Motivation
|
||||
EIP 165 supports interface discovery - determining if the contract at a given address supports a requested interface. However, in many cases it's useful to be able to discover functionality associated with a name or an address that is implemented by other contracts.
|
||||
|
||||
For example, a token contract may not itself provide any kind of 'atomic swap' functionality, but there may be associated contracts that do. With ENS interface discovery, the token contract can expose this metadata, informing applications where they can find that functionality.
|
||||
|
||||
## Specification
|
||||
A new profile for ENS resolvers is defined, consisting of the following method:
|
||||
|
||||
```
|
||||
function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address);
|
||||
```
|
||||
|
||||
The EIP-165 interface ID of this interface is `0xb8f2bbb4`.
|
||||
|
||||
Given an ENS name hash `node` and an EIP-165 `interfaceID`, this function returns the address of an appropriate implementer of that interface. If there is no interface matching that interface ID for that node, 0 is returned.
|
||||
|
||||
The address returned by `interfaceImplementer` MUST refer to a smart contract.
|
||||
|
||||
The smart contract at the returned address SHOULD implement EIP-165.
|
||||
|
||||
Resolvers implementing this interface MAY utilise a fallback strategy: If no matching interface was explicitly provided by the user, query the contract returned by `addr()`, returning its address if the requested interface is supported by that contract, and 0 otherwise. If they do this, they MUST ensure they return 0, rather than reverting, if the target contract reverts.
|
||||
|
||||
This field may be used with both forward resolution and reverse resolution.
|
||||
|
||||
## Rationale
|
||||
|
||||
A naive approach to this problem would involve adding this method directly to the target contract. However, doing this has several shortcomings:
|
||||
|
||||
1. Each contract must maintain its own list of interface implementations.
|
||||
2. Modifying this list requires access controls, which the contract may not have previously required.
|
||||
3. Support for this must be designed in when the contract is written, and cannot be retrofitted afterwards.
|
||||
4. Only one canonical list of interfaces can be supported.
|
||||
|
||||
Using ENS resolvers instead mitigates these shortcomings, making it possible for anyone to associate interfaces with a name, even for contracts not previously built with this in mind.
|
||||
|
||||
## Backwards Compatibility
|
||||
There are no backwards compatibility issues.
|
||||
|
||||
## Test Cases
|
||||
TBD
|
||||
|
||||
## Implementation
|
||||
The PublicResolver in the [ensdomains/resolvers](https://github.com/ensdomains/resolvers/) repository implements this interface.
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -88,9 +88,9 @@ Allows for packages which exclude source code or other elements which would be n
|
|||
|
||||
Support for ERC190 is either implemented or in progress for the following:
|
||||
|
||||
* [Truffle](http://truffleframework.com/)
|
||||
* [Populus](http://populus.readthedocs.io/en/latest/)
|
||||
* [Dapple](http://dapple.readthedocs.io/en/master/)
|
||||
* [Truffle](https://truffleframework.com/)
|
||||
* [Populus](https://populus.readthedocs.io/en/latest/)
|
||||
* [Dapple](https://dapple.readthedocs.io/en/master/)
|
||||
* [Eris PM](https://github.com/eris-ltd/eris-cli)
|
||||
* [Embark](https://github.com/iurimatias/embark-framework)
|
||||
* [Browser Solidity](https://github.com/ethereum/remix-ide/issues/386)
|
||||
|
|
|
@ -59,19 +59,23 @@ Using `0x19` thus makes it possible to extend the scheme by defining a version `
|
|||
|
||||
### Example
|
||||
|
||||
function submitTransactionPreSigned(address destination, uint value, bytes data, uint nonce, uint8 v, bytes32 r, bytes32 s)
|
||||
public
|
||||
returns (bytes32 transactionHash)
|
||||
{
|
||||
// Arguments when calculating hash to validate
|
||||
// 1: byte(0x19) - the initial 0x19 byte
|
||||
// 2: byte(0) - the version byte
|
||||
// 3: this - the validator address
|
||||
// 4-7 : Application specific data
|
||||
transactionHash = keccak256(byte(0x19),byte(0),this,destination, value, data, nonce);
|
||||
sender = ecrecover(transactionHash, v, r, s);
|
||||
// ...
|
||||
}
|
||||
The following snippet has been written in Solidity 0.5.0.
|
||||
|
||||
```solidity
|
||||
function submitTransactionPreSigned(address destination, uint value, bytes data, uint nonce, uint8 v, bytes32 r, bytes32 s)
|
||||
public
|
||||
returns (bytes32 transactionHash)
|
||||
{
|
||||
// Arguments when calculating hash to validate
|
||||
// 1: byte(0x19) - the initial 0x19 byte
|
||||
// 2: byte(0) - the version byte
|
||||
// 3: this - the validator address
|
||||
// 4-7 : Application specific data
|
||||
transactionHash = keccak256(abi.encodePacked(byte(0x19),byte(0),address(this),destination, value, data, nonce));
|
||||
sender = ecrecover(transactionHash, v, r, s);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Copyright
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Moved to [eip-20.md](./eip-20.md).
|
||||
Moved to [EIP 20](https://eips.ethereum.org/EIPS/eip-20).
|
||||
|
|
|
@ -95,7 +95,7 @@ function balanceOf(address _owner) public view returns (uint256 balance)
|
|||
#### transfer
|
||||
|
||||
Transfers `_value` amount of tokens to address `_to`, and MUST fire the `Transfer` event.
|
||||
The function SHOULD `throw` if the `_from` account balance does not have enough tokens to spend.
|
||||
The function SHOULD `throw` if the message caller's account balance does not have enough tokens to spend.
|
||||
|
||||
*Note* Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event.
|
||||
|
||||
|
|
|
@ -0,0 +1,475 @@
|
|||
---
|
||||
eip: 225
|
||||
title: Clique proof-of-authority consensus protocol
|
||||
author: Péter Szilágyi <peterke@gmail.com>
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/225
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2017-03-06
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
||||
Clique is a proof-of-authority consensus protocol. It shadows the design of Ethereum mainnet, so it can be added to any client with minimal effort.
|
||||
|
||||
## Motivation
|
||||
|
||||
Ethereum's first official testnet was Morden. It ran from July 2015 to about November 2016, when due to the accumulated junk and some testnet consensus issues between Geth and Parity, it was finally laid to rest in favor of a testnet reboot.
|
||||
|
||||
Ropsten was thus born, clearing out all the junk and starting with a clean slate. This ran well until the end of February 2017, when malicious actors decided to abuse the low PoW and gradually inflate the block gas limits to 9 billion (from the normal 4.7 million), at which point sending in gigantic transactions crippling the entire network. Even before that, attackers attempted multiple extremely long reorgs, causing network splits between different clients, and even different versions.
|
||||
|
||||
The root cause of these attacks is that a PoW network is only as secure as the computing capacity placed behind it. Restarting a new testnet from zero wouldn't solve anything, since the attacker can mount the same attack over and over again. The Parity team decided to go with an emergency solution of rolling back a significant number of blocks, and enacting a soft-fork rule that disallows gas limits above a certain threshold.
|
||||
|
||||
While this solution may work in the short term:
|
||||
|
||||
* It's not elegant: Ethereum supposed to have dynamic block limits
|
||||
* It's not portable: other clients need to implement new fork logic themselves
|
||||
* It's not compatible with sync modes: fast and light clients are both out of luck
|
||||
* It's just prolonging the attacks: junk can still be steadily pushed in ad infinitum
|
||||
|
||||
Parity's solution although not perfect, is nonetheless workable. I'd like to propose a longer term alternative solution, which is more involved, yet should be simple enough to allow rolling out in a reasonable amount of time.
|
||||
|
||||
### Standardized proof-of-authority
|
||||
|
||||
As reasoned above, proof-of-work cannot work securely in a network with no value. Ethereum has its long term goal of proof-of-stake based on Casper, but that is heavy research so we cannot rely on that any time soon to fix today's problems. One solution however is easy enough to implement, yet effective enough to fix the testnet properly, namely a proof-of-authority scheme.
|
||||
|
||||
The main design goals of the PoA protocol described here is that it should be very simple to implement and embed into any existing Ethereum client, while at the same time allow using existing sync technologies (fast, light, warp) without needing client developers to add custom logic to critical software.
|
||||
|
||||
## Design constraints
|
||||
|
||||
There are two approaches to syncing a blockchain in general:
|
||||
|
||||
* The classical approach is to take the genesis block and crunch through all the transactions one by one. This is tried and proven, but in Ethereum complexity networks quickly turns out to be very costly computationally.
|
||||
* The other is to only download the chain of block headers and verify their validity, after which point an arbitrary recent state may be downloaded from the network and checked against recent headers.
|
||||
|
||||
A PoA scheme is based on the idea that blocks may only be minted by trusted signers. As such, every block (or header) that a client sees can be matched against the list of trusted signers. The challenge here is how to maintain a list of authorized signers that can change in time? The obvious answer (store it in an Ethereum contract) is also the wrong answer: fast, light and warp sync don't have access to the state during syncing.
|
||||
|
||||
**The protocol of maintaining the list of authorized signers must be fully contained in the block headers.**
|
||||
|
||||
The next obvious idea would be to change the structure of the block headers so it drops the notions of PoW, and introduces new fields to cater for voting mechanisms. This is also the wrong answer: changing such a core data structure in multiple implementations would be a nightmare development, maintenance and security wise.
|
||||
|
||||
**The protocol of maintaining the list of authorized signers must fit fully into the current data models.**
|
||||
|
||||
So, according to the above, we can't use the EVM for voting, rather have to resort to headers. And we can't change header fields, rather have to resort to the currently available ones. Not much wiggle room.
|
||||
|
||||
### Repurposing header fields for signing and voting
|
||||
|
||||
The most obvious field that currently is used solely as *fun metadata* is the 32 byte **extra-data** section in block headers. Miners usually place their client and version in there, but some fill it with alternative "messages". The protocol would extend this field ~~to~~ with 65 bytes with the purpose of a secp256k1 miner signature. This would allow anyone obtaining a block to verify it against a list of authorized signers. It also makes the **miner** section in block headers obsolete (since the address can be derived from the signature).
|
||||
|
||||
*Note, changing the length of a header field is a non invasive operation as all code (such as RLP encoding, hashing) is agnostic to that, so clients wouldn't need custom logic.*
|
||||
|
||||
The above is enough to validate a chain, but how can we update a dynamic list of signers. The answer is that we can repurpose the newly obsoleted **miner** field and the PoA obsoleted **nonce** field to create a voting protocol:
|
||||
|
||||
* During regular blocks, both of these fields would be set to zero.
|
||||
* If a signer wishes to enact a change to the list of authorized signers, it will:
|
||||
* Set the **miner** to the signer it wishes to vote about
|
||||
* Set the **nonce** to `0` or `0xff...f` to vote in favor of adding or kicking out
|
||||
|
||||
Any clients syncing the chain can "tally" up the votes during block processing, and maintain a dynamically changing list of authorized signers by popular vote.
|
||||
|
||||
To avoid having an infinite window to tally up votes in, and also to allow periodically flushing stale proposals, we can reuse the concept of an epoch from ethash, where every epoch transition flushes all pending votes. Furthermore, these epoch transitions can also act as stateless checkpoints containing the list of current authorized signers within the header extra-data. This permits clients to sync up based only on a checkpoint hash without having to replay all the voting that was done on the chain up to that point. It also allows the genesis header to fully define the chain, containing the list of initial signers.
|
||||
|
||||
### Attack vector: Malicious signer
|
||||
|
||||
It may happen that a malicious user gets added to the list of signers, or that a signer key/machine is compromised. In such a scenario the protocol needs to be able to defend itself against reorganizations and spamming. The proposed solution is that given a list of N authorized signers, any signer may only mint 1 block out of every K. This ensures that damage is limited, and the remainder of the miners can vote out the malicious user.
|
||||
|
||||
### Attack vector: Censoring signer
|
||||
|
||||
Another interesting attack vector is if a signer (or group of signers) attempts to censor out blocks that vote on removing them from the authorization list. To work around this, we restrict the allowed minting frequency of signers to 1 out of N/2. This ensures that malicious signers need to control at least 51% of signing accounts, at which case it's game over anyway.
|
||||
|
||||
### Attack vector: Spamming signer
|
||||
|
||||
A final small attack vector is that of malicious signers injecting new vote proposals inside every block they mint. Since nodes need to tally up all votes to create the actual list of authorized signers, they need to track all votes through time. Without placing a limit on the vote window, this could grow slowly, yet unbounded. The solution is to place a ~~moving~~ window of W blocks after which votes are considered stale. ~~A sane window might be 1-2 epochs.~~ We'll call this an epoch.
|
||||
|
||||
### Attack vector: Concurrent blocks
|
||||
|
||||
If the number of authorized signers are N, and we allow each signer to mint 1 block out of K, then at any point in time N-K+1 miners are allowed to mint. To avoid these racing for blocks, every signer would add a small random "offset" to the time it releases a new block. This ensures that small forks are rare, but occasionally still happen (as on the main net). If a signer is caught abusing it's authority and causing chaos, it can be voted out.
|
||||
|
||||
## Specification
|
||||
|
||||
We define the following constants:
|
||||
|
||||
* **`EPOCH_LENGTH`**: Number of blocks after which to checkpoint and reset the pending votes.
|
||||
* Suggested `30000` for the testnet to remain analogous to the mainnet `ethash` epoch.
|
||||
* **`BLOCK_PERIOD`**: Minimum difference between two consecutive block's timestamps.
|
||||
* Suggested `15s` for the testnet to remain analogous to the mainnet `ethash` target.
|
||||
* **`EXTRA_VANITY`**: Fixed number of extra-data prefix bytes reserved for signer *vanity*.
|
||||
* Suggested `32 bytes` to retain the current extra-data allowance and/or use.
|
||||
* **`EXTRA_SEAL`**: Fixed number of extra-data suffix bytes reserved for signer seal.
|
||||
* `65 bytes` fixed as signatures are based on the standard `secp256k1` curve.
|
||||
* **`NONCE_AUTH`**: Magic nonce number `0xffffffffffffffff` to vote on adding a new signer.
|
||||
* **`NONCE_DROP`**: Magic nonce number `0x0000000000000000` to vote on removing a signer.
|
||||
* **`UNCLE_HASH`**: Always `Keccak256(RLP([]))` as uncles are meaningless outside of PoW.
|
||||
* **`DIFF_NOTURN`**: Block score (difficulty) for blocks containing out-of-turn signatures.
|
||||
* Suggested `1` since it just needs to be an arbitrary baseline constant.
|
||||
* **`DIFF_INTURN`**: Block score (difficulty) for blocks containing in-turn signatures.
|
||||
* Suggested `2` to show a slight preference over out-of-turn signatures.
|
||||
|
||||
We also define the following per-block constants:
|
||||
|
||||
* **`BLOCK_NUMBER`**: Block height in the chain, where the height of the genesis is block `0`.
|
||||
* **`SIGNER_COUNT`**: Number of authorized signers valid at a particular instance in the chain.
|
||||
* **`SIGNER_INDEX`**: Index of the block signer in the sorted list of current authorized signers.
|
||||
* **`SIGNER_LIMIT`**: Number of consecutive blocks out of which a signer may only sign one.
|
||||
* Must be `floor(SIGNER_COUNT / 2) + 1` to enforce majority consensus on a chain.
|
||||
|
||||
We repurpose the `ethash` header fields as follows:
|
||||
|
||||
* **`beneficiary`**: Address to propose modifying the list of authorized signers with.
|
||||
* Should be filled with zeroes normally, modified only while voting.
|
||||
* Arbitrary values are permitted nonetheless (even meaningless ones such as voting out non signers) to avoid extra complexity in implementations around voting mechanics.
|
||||
* **Must** be filled with zeroes on checkpoint (i.e. epoch transition) blocks.
|
||||
* Transaction execution **must** use the actual block signer (see `extraData`) for the `COINBASE` opcode.
|
||||
* **`nonce`**: Signer proposal regarding the account defined by the `beneficiary` field.
|
||||
* Should be **`NONCE_DROP`** to propose deauthorizing `beneficiary` as a existing signer.
|
||||
* Should be **`NONCE_AUTH`** to propose authorizing `beneficiary` as a new signer.
|
||||
* **Must** be filled with zeroes on checkpoint (i.e. epoch transition) blocks.
|
||||
* **Must** not take up any other value apart from the two above (for now).
|
||||
* **`extraData`**: Combined field for signer vanity, checkpointing and signer signatures.
|
||||
* First **`EXTRA_VANITY`** bytes (fixed) may contain arbitrary signer vanity data.
|
||||
* Last **`EXTRA_SEAL`** bytes (fixed) is the signer's signature sealing the header.
|
||||
* Checkpoint blocks **must** contain a list of signers (`N*20 bytes`) in between, **omitted** otherwise.
|
||||
* The list of signers in checkpoint block extra-data sections **must** be sorted in ascending order.
|
||||
* **`mixHash`**: Reserved for fork protection logic, similar to the extra-data during the DAO.
|
||||
* **Must** be filled with zeroes during normal operation.
|
||||
* **`ommersHash`**: **Must** be **`UNCLE_HASH`** as uncles are meaningless outside of PoW.
|
||||
* **`timestamp`**: **Must** be at least the parent timestamp + **`BLOCK_PERIOD`**.
|
||||
* **`difficulty`**: Contains the standalone score of the block to derive the quality of a chain.
|
||||
* **Must** be **`DIFF_NOTURN`** if `BLOCK_NUMBER % SIGNER_COUNT != SIGNER_INDEX`
|
||||
* **Must** be **`DIFF_INTURN`** if `BLOCK_NUMBER % SIGNER_COUNT == SIGNER_INDEX`
|
||||
|
||||
### Authorizing a block
|
||||
|
||||
To authorize a block for the network, the signer needs to sign the block's hash containing **everything except the signature itself**. The means that the hash contains every field of the header (`nonce` and `mixDigest` included), and also the `extraData` with the exception of the 65 byte signature suffix. The fields are hashed in the order of their definition in the yellow paper.
|
||||
|
||||
This hash is signed using the standard `secp256k1` curve, and the resulting 65 byte signature (`R`, `S`, `V`, where `V` is `0` or `1`) is embedded into the `extraData` as the trailing 65 byte suffix.
|
||||
|
||||
To ensure malicious signers (loss of signing key) cannot wreck havoc in the network, each singer is allowed to sign **maximum one** out of **`SIGNER_LIMIT`** consecutive blocks. The order is not fixed, but in-turn signing weighs more (**`DIFF_INTURN`**) than out of turn one (**`DIFF_NOTURN`**).
|
||||
|
||||
#### Authorization strategies
|
||||
|
||||
As long as signers conform to the above specs, they can authorize and distribute blocks as they see fit. The following suggested strategy will however reduce network traffic and small forks, so it's a suggested feature:
|
||||
|
||||
* If a signer is allowed to sign a block (is on the authorized list and didn't sign recently).
|
||||
* Calculate the optimal signing time of the next block (parent + **`BLOCK_PERIOD`**).
|
||||
* If the signer is in-turn, wait for the exact time to arrive, sign and broadcast immediately.
|
||||
* If the signer is out-of-turn, delay signing by `rand(SIGNER_COUNT * 500ms)`.
|
||||
|
||||
This small strategy will ensure that the in-turn signer (who's block weighs more) has a slight advantage to sign and propagate versus the out-of-turn signers. Also the scheme allows a bit of scale with the increase of the number of signers.
|
||||
|
||||
### Voting on signers
|
||||
|
||||
Every epoch transition (genesis block included) acts as a stateless checkpoint, from which capable clients should be able to sync without requiring any previous state. This means epoch headers **must not** contain votes, all non settled votes are discarded, and tallying starts from scratch.
|
||||
|
||||
For all non-epoch transition blocks:
|
||||
|
||||
* Signers may cast one vote per own block to propose a change to the authorization list.
|
||||
* Only the latest proposal per target beneficiary is kept from a single signer.
|
||||
* Votes are tallied live as the chain progresses (concurrent proposals allowed).
|
||||
* Proposals reaching majority consensus **`SIGNER_LIMIT`** come into effect immediately.
|
||||
* Invalid proposals are **not** to be penalized for client implementation simplicity.
|
||||
|
||||
**A proposal coming into effect entails discarding all pending votes for that proposal (both for and against) and starting with a clean slate.**
|
||||
|
||||
#### Cascading votes
|
||||
|
||||
A complex corner case may arise during signer deauthorization. When a previously authorized signer is dropped, the number of signers required to approve a proposal might decrease by one. This might cause one or more pending proposals to reach majority consensus, the execution of which might further cascade into new proposals passing.
|
||||
|
||||
Handling this scenario is non obvious when multiple conflicting proposals pass simultaneously (e.g. add a new signer vs. drop an existing one), where the evaluation order might drastically change the outcome of the final authorization list. Since signers may invert their own votes in every block they mint, it's not so obvious which proposal would be "first".
|
||||
|
||||
To avoid the pitfalls cascading executions would entail, the Clique proposal explicitly forbids cascading effects. In other words: **Only the `beneficiary` of the current header/vote may be added to/dropped from the authorization list. If that causes other proposals to reach consensus, those will be executed when their respective beneficiaries are "touched" again (given that majority consensus still holds at that point).**
|
||||
|
||||
#### Voting strategies
|
||||
|
||||
Since the blockchain can have small reorgs, a naive voting mechanism of "cast-and-forget" may not be optimal, since a block containing a singleton vote may not end up on the final chain.
|
||||
|
||||
A simplistic but working strategy is to allow users to configure "proposals" on the signers (e.g. "add 0x...", "drop 0x..."). The signing code can then pick a random proposal for every block it signs and inject it. This ensures that multiple concurrent proposals as well as reorgs get eventually noted on the chain.
|
||||
|
||||
This list may be expired after a certain number of blocks / epochs, but it's important to realize that "seeing" a proposal pass doesn't mean it won't get reorged, so it should not be immediately dropped when the proposal passes.
|
||||
|
||||
## Test Cases
|
||||
|
||||
```go
|
||||
// block represents a single block signed by a parcitular account, where
|
||||
// the account may or may not have cast a Clique vote.
|
||||
type block struct {
|
||||
signer string // Account that signed this particular block
|
||||
voted string // Optional value if the signer voted on adding/removing someone
|
||||
auth bool // Whether the vote was to authorize (or deauthorize)
|
||||
checkpoint []string // List of authorized signers if this is an epoch block
|
||||
}
|
||||
|
||||
// Define the various voting scenarios to test
|
||||
tests := []struct {
|
||||
epoch uint64 // Number of blocks in an epoch (unset = 30000)
|
||||
signers []string // Initial list of authorized signers in the genesis
|
||||
blocks []block // Chain of signed blocks, potentially influencing auths
|
||||
results []string // Final list of authorized signers after all blocks
|
||||
failure error // Failure if some block is invalid according to the rules
|
||||
}{
|
||||
{
|
||||
// Single signer, no votes cast
|
||||
signers: []string{"A"},
|
||||
blocks: []block{{signer: "A"}},
|
||||
results: []string{"A"},
|
||||
}, {
|
||||
// Single signer, voting to add two others (only accept first, second needs 2 votes)
|
||||
signers: []string{"A"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "B", auth: true},
|
||||
{signer: "B"},
|
||||
{signer: "A", voted: "C", auth: true},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Two signers, voting to add three others (only accept first two, third needs 3 votes already)
|
||||
signers: []string{"A", "B"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: true},
|
||||
{signer: "B", voted: "C", auth: true},
|
||||
{signer: "A", voted: "D", auth: true},
|
||||
{signer: "B", voted: "D", auth: true},
|
||||
{signer: "C"},
|
||||
{signer: "A", voted: "E", auth: true},
|
||||
{signer: "B", voted: "E", auth: true},
|
||||
},
|
||||
results: []string{"A", "B", "C", "D"},
|
||||
}, {
|
||||
// Single signer, dropping itself (weird, but one less cornercase by explicitly allowing this)
|
||||
signers: []string{"A"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "A", auth: false},
|
||||
},
|
||||
results: []string{},
|
||||
}, {
|
||||
// Two signers, actually needing mutual consent to drop either of them (not fulfilled)
|
||||
signers: []string{"A", "B"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "B", auth: false},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Two signers, actually needing mutual consent to drop either of them (fulfilled)
|
||||
signers: []string{"A", "B"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "B", auth: false},
|
||||
{signer: "B", voted: "B", auth: false},
|
||||
},
|
||||
results: []string{"A"},
|
||||
}, {
|
||||
// Three signers, two of them deciding to drop the third
|
||||
signers: []string{"A", "B", "C"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: false},
|
||||
{signer: "B", voted: "C", auth: false},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Four signers, consensus of two not being enough to drop anyone
|
||||
signers: []string{"A", "B", "C", "D"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: false},
|
||||
{signer: "B", voted: "C", auth: false},
|
||||
},
|
||||
results: []string{"A", "B", "C", "D"},
|
||||
}, {
|
||||
// Four signers, consensus of three already being enough to drop someone
|
||||
signers: []string{"A", "B", "C", "D"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "D", auth: false},
|
||||
{signer: "B", voted: "D", auth: false},
|
||||
{signer: "C", voted: "D", auth: false},
|
||||
},
|
||||
results: []string{"A", "B", "C"},
|
||||
}, {
|
||||
// Authorizations are counted once per signer per target
|
||||
signers: []string{"A", "B"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: true},
|
||||
{signer: "B"},
|
||||
{signer: "A", voted: "C", auth: true},
|
||||
{signer: "B"},
|
||||
{signer: "A", voted: "C", auth: true},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Authorizing multiple accounts concurrently is permitted
|
||||
signers: []string{"A", "B"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: true},
|
||||
{signer: "B"},
|
||||
{signer: "A", voted: "D", auth: true},
|
||||
{signer: "B"},
|
||||
{signer: "A"},
|
||||
{signer: "B", voted: "D", auth: true},
|
||||
{signer: "A"},
|
||||
{signer: "B", voted: "C", auth: true},
|
||||
},
|
||||
results: []string{"A", "B", "C", "D"},
|
||||
}, {
|
||||
// Deauthorizations are counted once per signer per target
|
||||
signers: []string{"A", "B"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "B", auth: false},
|
||||
{signer: "B"},
|
||||
{signer: "A", voted: "B", auth: false},
|
||||
{signer: "B"},
|
||||
{signer: "A", voted: "B", auth: false},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Deauthorizing multiple accounts concurrently is permitted
|
||||
signers: []string{"A", "B", "C", "D"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: false},
|
||||
{signer: "B"},
|
||||
{signer: "C"},
|
||||
{signer: "A", voted: "D", auth: false},
|
||||
{signer: "B"},
|
||||
{signer: "C"},
|
||||
{signer: "A"},
|
||||
{signer: "B", voted: "D", auth: false},
|
||||
{signer: "C", voted: "D", auth: false},
|
||||
{signer: "A"},
|
||||
{signer: "B", voted: "C", auth: false},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Votes from deauthorized signers are discarded immediately (deauth votes)
|
||||
signers: []string{"A", "B", "C"},
|
||||
blocks: []block{
|
||||
{signer: "C", voted: "B", auth: false},
|
||||
{signer: "A", voted: "C", auth: false},
|
||||
{signer: "B", voted: "C", auth: false},
|
||||
{signer: "A", voted: "B", auth: false},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Votes from deauthorized signers are discarded immediately (auth votes)
|
||||
signers: []string{"A", "B", "C"},
|
||||
blocks: []block{
|
||||
{signer: "C", voted: "D", auth: true},
|
||||
{signer: "A", voted: "C", auth: false},
|
||||
{signer: "B", voted: "C", auth: false},
|
||||
{signer: "A", voted: "D", auth: true},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Cascading changes are not allowed, only the account being voted on may change
|
||||
signers: []string{"A", "B", "C", "D"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: false},
|
||||
{signer: "B"},
|
||||
{signer: "C"},
|
||||
{signer: "A", voted: "D", auth: false},
|
||||
{signer: "B", voted: "C", auth: false},
|
||||
{signer: "C"},
|
||||
{signer: "A"},
|
||||
{signer: "B", voted: "D", auth: false},
|
||||
{signer: "C", voted: "D", auth: false},
|
||||
},
|
||||
results: []string{"A", "B", "C"},
|
||||
}, {
|
||||
// Changes reaching consensus out of bounds (via a deauth) execute on touch
|
||||
signers: []string{"A", "B", "C", "D"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: false},
|
||||
{signer: "B"},
|
||||
{signer: "C"},
|
||||
{signer: "A", voted: "D", auth: false},
|
||||
{signer: "B", voted: "C", auth: false},
|
||||
{signer: "C"},
|
||||
{signer: "A"},
|
||||
{signer: "B", voted: "D", auth: false},
|
||||
{signer: "C", voted: "D", auth: false},
|
||||
{signer: "A"},
|
||||
{signer: "C", voted: "C", auth: true},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// Changes reaching consensus out of bounds (via a deauth) may go out of consensus on first touch
|
||||
signers: []string{"A", "B", "C", "D"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: false},
|
||||
{signer: "B"},
|
||||
{signer: "C"},
|
||||
{signer: "A", voted: "D", auth: false},
|
||||
{signer: "B", voted: "C", auth: false},
|
||||
{signer: "C"},
|
||||
{signer: "A"},
|
||||
{signer: "B", voted: "D", auth: false},
|
||||
{signer: "C", voted: "D", auth: false},
|
||||
{signer: "A"},
|
||||
{signer: "B", voted: "C", auth: true},
|
||||
},
|
||||
results: []string{"A", "B", "C"},
|
||||
}, {
|
||||
// Ensure that pending votes don't survive authorization status changes. This
|
||||
// corner case can only appear if a signer is quickly added, removed and then
|
||||
// readded (or the inverse), while one of the original voters dropped. If a
|
||||
// past vote is left cached in the system somewhere, this will interfere with
|
||||
// the final signer outcome.
|
||||
signers: []string{"A", "B", "C", "D", "E"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "F", auth: true}, // Authorize F, 3 votes needed
|
||||
{signer: "B", voted: "F", auth: true},
|
||||
{signer: "C", voted: "F", auth: true},
|
||||
{signer: "D", voted: "F", auth: false}, // Deauthorize F, 4 votes needed (leave A's previous vote "unchanged")
|
||||
{signer: "E", voted: "F", auth: false},
|
||||
{signer: "B", voted: "F", auth: false},
|
||||
{signer: "C", voted: "F", auth: false},
|
||||
{signer: "D", voted: "F", auth: true}, // Almost authorize F, 2/3 votes needed
|
||||
{signer: "E", voted: "F", auth: true},
|
||||
{signer: "B", voted: "A", auth: false}, // Deauthorize A, 3 votes needed
|
||||
{signer: "C", voted: "A", auth: false},
|
||||
{signer: "D", voted: "A", auth: false},
|
||||
{signer: "B", voted: "F", auth: true}, // Finish authorizing F, 3/3 votes needed
|
||||
},
|
||||
results: []string{"B", "C", "D", "E", "F"},
|
||||
}, {
|
||||
// Epoch transitions reset all votes to allow chain checkpointing
|
||||
epoch: 3,
|
||||
signers: []string{"A", "B"},
|
||||
blocks: []block{
|
||||
{signer: "A", voted: "C", auth: true},
|
||||
{signer: "B"},
|
||||
{signer: "A", checkpoint: []string{"A", "B"}},
|
||||
{signer: "B", voted: "C", auth: true},
|
||||
},
|
||||
results: []string{"A", "B"},
|
||||
}, {
|
||||
// An unauthorized signer should not be able to sign blocks
|
||||
signers: []string{"A"},
|
||||
blocks: []block{
|
||||
{signer: "B"},
|
||||
},
|
||||
failure: errUnauthorizedSigner,
|
||||
}, {
|
||||
// An authorized signer that signed recenty should not be able to sign again
|
||||
signers: []string{"A", "B"},
|
||||
blocks []block{
|
||||
{signer: "A"},
|
||||
{signer: "A"},
|
||||
},
|
||||
failure: errRecentlySigned,
|
||||
}, {
|
||||
// Recent signatures should not reset on checkpoint blocks imported in a batch
|
||||
epoch: 3,
|
||||
signers: []string{"A", "B", "C"},
|
||||
blocks: []block{
|
||||
{signer: "A"},
|
||||
{signer: "B"},
|
||||
{signer: "A", checkpoint: []string{"A", "B", "C"}},
|
||||
{signer: "A"},
|
||||
},
|
||||
failure: errRecentlySigned,
|
||||
},,
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
A reference implementation is part of [go-ethereum](https://github.com/ethereum/go-ethereum/tree/master/consensus/clique) and has been functioning as the consensus engine behind the [Rinkeby](https://www.rinkeby.io) testnet since April, 2017.
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
eip: 55
|
||||
title: Mixed-case checksum address encoding
|
||||
author: Vitalik Buterin
|
||||
author: Vitalik Buterin <vitalik.buterin@ethereum.org>, Alex Van de Sande <avsa@ethereum.org>
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
status: Final
|
||||
|
@ -107,6 +107,7 @@ Note that the input to the Keccak256 hash is the lowercase hexadecimal string (i
|
|||
| Parity 1.6.6-beta (UI) | Yes | Yes | Yes | Yes |
|
||||
| Jaxx Liberty 2.0.0 | Yes | Yes | Yes | Yes |
|
||||
| Coinomi 1.10 | Yes | Yes | Yes | Yes |
|
||||
| Trust Wallet | Yes | Yes | Yes | Yes |
|
||||
|
||||
### Exchange support for mixed-case address checksums, as of 2017-05-27:
|
||||
|
||||
|
@ -126,3 +127,4 @@ Note that the input to the Keccak256 hash is the lowercase hexadecimal string (i
|
|||
3. Python implementation in [`ethereum-utils`](https://github.com/pipermerriam/ethereum-utils#to_checksum_addressvalue---text)
|
||||
4. Ethereumjs-util implementation https://github.com/ethereumjs/ethereumjs-util/blob/75f529458bc7dc84f85fd0446d0fac92d991c262/index.js#L452-L466
|
||||
5. Swift implementation in [`EthereumKit`](https://github.com/yuzushioh/EthereumKit/blob/master/EthereumKit/Helper/EIP55.swift)
|
||||
6. Kotlin implementation in [`KEthereum`](https://github.com/walleth/kethereum/tree/master/erc55)
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
eip: 600
|
||||
title: Ethereum purpose allocation for Deterministic Wallets
|
||||
author: Nick Johnson (@arachnid), Micah Zoltu (@micahzoltu)
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
status: Draft
|
||||
discussions-to: https://ethereum-magicians.org/t/eip-erc-app-keys-application-specific-wallet-accounts/2742
|
||||
created: 2017-04-13
|
||||
---
|
||||
|
||||
## Abstract
|
||||
This EIP defines a logical hierarchy for deterministic wallets based on [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), the purpose scheme defined in [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) and [this proposed change to BIP43](https://github.com/bitcoin/bips/pull/523).
|
||||
|
||||
This EIP is a particular application of BIP43.
|
||||
|
||||
## Motivation
|
||||
Because Ethereum is based on account balances rather than UTXO, the hierarchy defined by BIP44 is poorly suited. As a result, several competing derivation path strategies have sprung up for deterministic wallets, resulting in inter-client incompatibility. This BIP seeks to provide a path to standardise this in a fashion better suited to Ethereum's unique requirements.
|
||||
|
||||
## Specification
|
||||
We define the following 2 levels in BIP32 path:
|
||||
|
||||
<pre>
|
||||
m / purpose' / subpurpose' / EIP'
|
||||
</pre>
|
||||
|
||||
Apostrophe in the path indicates that BIP32 hardened derivation is used.
|
||||
|
||||
Each level has a special meaning, described in the chapters below.
|
||||
|
||||
### Purpose
|
||||
|
||||
Purpose is set to 43, as documented in [this proposed change to BIP43](https://github.com/bitcoin/bips/pull/523).
|
||||
|
||||
The purpose field indicates that this path is for a non-bitcoin cryptocurrency.
|
||||
|
||||
Hardened derivation is used at this level.
|
||||
|
||||
### Subpurpose
|
||||
Subpurpose is set to 60, the SLIP-44 code for Ethereum.
|
||||
|
||||
Hardened derivation is used at this level.
|
||||
|
||||
### EIP
|
||||
EIP is set to the EIP number specifying the remainder of the BIP32 derivation path. This permits new Ethereum-focused applications of deterministic wallets without needing to interface with the BIP process.
|
||||
|
||||
Hardened derivation is used at this level.
|
||||
|
||||
## Rationale
|
||||
The existing convention is to use the 'Ethereum' coin type, leading to paths starting with `m/44'/60'/*`. Because this still assumes a UTXO-based coin, we contend that this is a poor fit, resulting in standardisation, usability, and security compromises. As a result, we are making the above proposal to define an entirely new hierarchy for Ethereum-based chains.
|
||||
|
||||
## Backwards Compatibility
|
||||
The introduction of another derivation path requires existing software to add support for this scheme in addition to any existing schemes. Given the already confused nature of wallet derivation paths in Ethereum, we anticipate this will cause relatively little additional disruption, and has the potential to improve matters significantly in the long run.
|
||||
|
||||
## Test Cases
|
||||
TBD
|
||||
|
||||
## Implementation
|
||||
None yet.
|
||||
|
||||
## References
|
||||
[This discussion on derivation paths](https://github.com/ethereum/EIPs/issues/84)
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
eip: 601
|
||||
title: Ethereum hierarchy for deterministic wallets
|
||||
author: Nick Johnson (@arachnid), Micah Zoltu (@micahzoltu)
|
||||
type: Standards Track
|
||||
category : ERC
|
||||
status: Draft
|
||||
discussions-to: https://ethereum-magicians.org/t/eip-erc-app-keys-application-specific-wallet-accounts/2742
|
||||
created: 2017-04-13
|
||||
---
|
||||
|
||||
## Abstract
|
||||
This EIP defines a logical hierarchy for deterministic wallets based on [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), the purpose scheme defined in [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) and eip-draft-ethereum-purpose.
|
||||
|
||||
This EIP is a particular application of eip-draft-ethereum-purpose.
|
||||
|
||||
## Motivation
|
||||
At present, different Ethereum clients and wallets use different derivation paths; a summary of them can be found [here](https://github.com/ethereum/EIPs/issues/84#issuecomment-292324521). Some of these paths violate BIP44, the standard defining derivation paths starting with `m/44'/`. This creates confusion and incompatibility between wallet implementations, in some cases making funds from one wallet inaccessible on another, and in others requiring prompting users manually for a derivation path, which hinders usability.
|
||||
|
||||
Further, BIP44 was designed with UTXO-based blockchains in mind, and is a poor fit for Ethereum, which uses an accounts abstraction instead.
|
||||
|
||||
As an alternative, we propose a deterministic wallet hierarchy better tailored to Ethereum's unique requiremnts.
|
||||
|
||||
## Specification
|
||||
We define the following 4 levels in BIP32 path:
|
||||
|
||||
<pre>
|
||||
m / purpose' / subpurpose' / EIP' / wallet'
|
||||
</pre>
|
||||
|
||||
Apostrophe in the path indicates that BIP32 hardened derivation is used.
|
||||
|
||||
Each level has a special meaning, described in the chapters below.
|
||||
|
||||
### Purpose
|
||||
|
||||
Purpose is a constant set to 43, indicating the key derivation is for a non-bitcoin cryptocurrency.
|
||||
|
||||
Hardened derivation is used at this level.
|
||||
|
||||
### Subpurpose
|
||||
Subpurpose is set to 60, the SLIP-44 code for Ethereum.
|
||||
|
||||
Hardened derivation is used at this level.
|
||||
|
||||
### EIP
|
||||
EIP is set to the EIP number specifying the remainder of the BIP32 derivation path. For paths following this EIP specification, the number assigned to this EIP is used.
|
||||
|
||||
Hardened derivation is used at this level.
|
||||
|
||||
### Wallet
|
||||
This component of the path splits the wallet into different user identities, allowing a single wallet to have multiple public identities.
|
||||
|
||||
Accounts are numbered from index 0 in sequentially increasing manner. This number is used as child index in BIP32 derivation.
|
||||
|
||||
Hardened derivation is used at this level.
|
||||
|
||||
Software should prevent a creation of an account if a previous account does not have a transaction history (meaning its address has not been used before).
|
||||
|
||||
Software needs to discover all used accounts after importing the seed from an external source.
|
||||
|
||||
## Rationale
|
||||
The existing convention is to use the 'Ethereum' coin type, leading to paths starting with `m/44'/60'/*`. Because this still assumes a UTXO-based coin, we contend that this is a poor fit, resulting in standardisation, usability, and security compromises. As a result, we are making the above proposal to define an entirely new hierarchy for Ethereum-based chains.
|
||||
|
||||
## Backwards Compatibility
|
||||
The introduction of another derivation path requires existing software to add support for this scheme in addition to any existing schemes. Given the already confused nature of wallet derivation paths in Ethereum, we anticipate this will cause relatively little additional disruption, and has the potential to improve matters significantly in the long run.
|
||||
|
||||
For applications that utilise mnemonics, the authors expect to submit another EIP draft that describes a method for avoiding backwards compatibility concerns when transitioning to this new derivation path.
|
||||
|
||||
## Test Cases
|
||||
TBD
|
||||
|
||||
## Implementation
|
||||
None yet.
|
||||
|
||||
## References
|
||||
[This discussion on derivation paths](https://github.com/ethereum/EIPs/issues/84)
|
||||
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic)
|
|||
type: Meta
|
||||
status: Final
|
||||
created: 2017-04-23
|
||||
requires: 2, 7
|
||||
requires: 2, 7, 8
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
|
|
@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic)
|
|||
type: Meta
|
||||
status: Final
|
||||
created: 2017-04-23
|
||||
requires: 155, 160, 161, 170
|
||||
requires: 155, 160, 161, 170, 608
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
@ -20,10 +20,10 @@ This specifies the changes included in the hard fork named Spurious Dragon.
|
|||
- Block >= 2,675,000 on Mainnet
|
||||
- Block >= 1,885,000 on Morden
|
||||
- Included EIPs:
|
||||
- [EIP 155](eip-155.md) (Simple replay attack protection)
|
||||
- [EIP 160](eip-160.md) (EXP cost increase)
|
||||
- [EIP 161](eip-161.md) (State trie clearing)
|
||||
- [EIP 170](eip-170.md) (Contract code size limit)
|
||||
- [EIP 155](https://eips.ethereum.org/EIPS/eip-155) (Simple replay attack protection)
|
||||
- [EIP 160](https://eips.ethereum.org/EIPS/eip-160) (EXP cost increase)
|
||||
- [EIP 161](https://eips.ethereum.org/EIPS/eip-161) (State trie clearing)
|
||||
- [EIP 170](https://eips.ethereum.org/EIPS/eip-170) (Contract code size limit)
|
||||
|
||||
## References
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic)
|
|||
type: Meta
|
||||
status: Final
|
||||
created: 2017-04-23
|
||||
requires: 150
|
||||
requires: 150, 779
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
|
|
@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic)
|
|||
type: Meta
|
||||
status: Final
|
||||
created: 2017-04-23
|
||||
requires: 100, 140, 196, 197, 198, 211, 214, 649, 658
|
||||
requires: 100, 140, 196, 197, 198, 211, 214, 607, 649, 658
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
@ -20,15 +20,15 @@ This specifies the changes included in the hard fork named Byzantium.
|
|||
- Block >= 4,370,000 on Mainnet
|
||||
- Block >= 1,700,000 on Ropsten testnet
|
||||
- Included EIPs:
|
||||
- [EIP 100](./eip-100.md) (Change difficulty adjustment to target mean block time including uncles)
|
||||
- [EIP 140](./eip-140.md) (REVERT instruction in the Ethereum Virtual Machine)
|
||||
- [EIP 196](./eip-196.md) (Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128)
|
||||
- [EIP 197](./eip-197.md) (Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128)
|
||||
- [EIP 198](./eip-198.md) (Precompiled contract for bigint modular exponentiation)
|
||||
- [EIP 211](./eip-211.md) (New opcodes: RETURNDATASIZE and RETURNDATACOPY)
|
||||
- [EIP 214](./eip-214.md) (New opcode STATICCALL)
|
||||
- [EIP 649](./eip-649.md) (Difficulty Bomb Delay and Block Reward Reduction)
|
||||
- [EIP 658](./eip-658.md) (Embedding transaction status code in receipts)
|
||||
- [EIP 100](https://eips.ethereum.org/EIPS/eip-100) (Change difficulty adjustment to target mean block time including uncles)
|
||||
- [EIP 140](https://eips.ethereum.org/EIPS/eip-140) (REVERT instruction in the Ethereum Virtual Machine)
|
||||
- [EIP 196](https://eips.ethereum.org/EIPS/eip-196) (Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128)
|
||||
- [EIP 197](https://eips.ethereum.org/EIPS/eip-197) (Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128)
|
||||
- [EIP 198](https://eips.ethereum.org/EIPS/eip-198) (Precompiled contract for bigint modular exponentiation)
|
||||
- [EIP 211](https://eips.ethereum.org/EIPS/eip-211) (New opcodes: RETURNDATASIZE and RETURNDATACOPY)
|
||||
- [EIP 214](https://eips.ethereum.org/EIPS/eip-214) (New opcode STATICCALL)
|
||||
- [EIP 649](https://eips.ethereum.org/EIPS/eip-649) (Difficulty Bomb Delay and Block Reward Reduction)
|
||||
- [EIP 658](https://eips.ethereum.org/EIPS/eip-658) (Embedding transaction status code in receipts)
|
||||
|
||||
## References
|
||||
|
||||
|
|
429
EIPS/eip-615.md
429
EIPS/eip-615.md
|
@ -4,205 +4,327 @@ title: Subroutines and Static Jumps for the EVM
|
|||
status: Draft
|
||||
type: Standards Track
|
||||
category: Core
|
||||
author: Greg Colvin <greg@colvin.org>, Paweł Bylica, Christian Reitwiessner
|
||||
author: Greg Colvin <greg@colvin.org>, Brooklyn Zelenka (@expede), Paweł Bylica (@chfast), Christian Reitwiessner (@chriseth)
|
||||
discussions-to: https://ethereum-magicians.org/t/eip-615-subroutines-and-static-jumps-for-the-evm/2728
|
||||
created: 2016-12-10
|
||||
edited: 2017-25-4
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
|
||||
In the 21st century, on a blockchain circulating billions of ETH, formal specification and verification are an essential tool against loss. Yet the design of the EVM makes this unnecessarily difficult. Further, the design of the EVM makes low-gas-cost, high-performance execution difficult. We propose to move forward with proposals to resolve these problems by tightening the security guarantees and pushing the performance limits of the EVM.
|
||||
|
||||
## Abstract
|
||||
|
||||
This EIP introduces new EVM opcodes and conditions on EVM code to support subroutines and static jumps, disallow dynamic jumps, and thereby make EVM code amenable to linear-time static analysis. This will provide for better compilation, interpretation, transpilation, and formal analysis of EVM code.
|
||||
EVM code is currently difficult to statically analyze, hobbling critical tools for preventing the many expensive bugs our blockchain has experienced. Further, none of the current implementations of the Ethereum Virtual Machine—including the compilers—are sufficiently performant to reduce the need for precompiles and otherwise meet the network's long-term demands. This proposal identifies dynamic jumps as a major reason for these issues, and proposes changes to the EVM specification to address the problem, making further efforts towards a safer and more performant EVM possible.
|
||||
|
||||
## MOTIVATION
|
||||
We also propose to validate—in linear time—that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. Well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools.
|
||||
|
||||
All current implementations of the Ethereum Virtual Machine, including the just-in-time compilers, are much too slow. This proposal identifies a major reason for this and proposes changes to the EVM specification to address the problem.
|
||||
## Motivation
|
||||
|
||||
In particular, it imposes restrictions on current EVM code and proposes new instructions to help provide for
|
||||
* better-optimized compilation to native code
|
||||
* faster interpretation
|
||||
* faster transpilation to eWASM
|
||||
* better compilation from other languages,
|
||||
including eWASM and Solidity
|
||||
* better formal analysis tools
|
||||
Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since many jumps can potentially be to any jump destination in the code, the number of possible paths through the code can go up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. Many of these cases are undecidable at deployment time, further inhibiting static and formal analyses.
|
||||
|
||||
These goals are achieved by
|
||||
* disallowing dynamic jumps
|
||||
* introducing subroutines - jumps with return support
|
||||
* disallowing pathological control flow and uses of the stack
|
||||
Absent dynamic jumps code can be statically analyzed in linear time. Static analysis includes validation, and much of optimization, compilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. And absent dynamic jumps, and with proper subroutines the EVM is a better target for code generation from other languages, including
|
||||
* Solidity
|
||||
* Vyper
|
||||
* LLVM IR
|
||||
* front ends include C, C++, Common Lisp, D, Fortran, Haskell, Java, Javascript, Kotlin, Lua, Objective-C, Pony, Pure, Python, Ruby, Rust, Scala, Scheme, and Swift
|
||||
|
||||
We also propose to validate - in linear time - that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. And well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools.
|
||||
The result is that all of the following validations and optimizations can be done at deployment time with **linear** **`(n)`** **or** **near-linear** **`(n log n)`** **time complexity**
|
||||
* The absence of most exceptional halting states can be validated.
|
||||
* The maximum use of resources can sometimes be calculated.
|
||||
* Bytecode can be compiled to machine code.
|
||||
* Compilation can optimize use of smaller registers.
|
||||
* Compilation can optimize injection of gas metering.
|
||||
|
||||
## THE PROBLEM
|
||||
Note that near-linear `(n log n)` time complexity is essential. Otherwise, specially crafted contracts can be used as attack vectors against any validations and optimizations.
|
||||
|
||||
Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since every jump can potentially be to any jump destination in the code, the number of possible paths through the code goes up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. But absent dynamic jumps code can be statically analyzed in linear time.
|
||||
## Specification
|
||||
|
||||
Static analysis includes validation, and much of optimization, compilation, transpilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. In particular, faster control-flow analysis means faster compilation of EVM code to native code, and better data-flow analysis can help the compiler and the interpreter better track the size of the values on the stack and use native 64- and 32-bit operations when possible. Also, conditions which are checked at validation time don’t have to be checked repeatedly at runtime.
|
||||
### Proposal
|
||||
|
||||
Note that analyses of a contract’s bytecode before execution - such as optimizations performed before interpretation, JIT compilation, and on-the-fly machine code generation - must be efficient and linear-time. Otherwise, specially crafted contracts can be used as attack vectors against clients that use static analysis of EVM code before the creation or execution of contracts.
|
||||
We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and propose new instructions to support their legitimate uses. In particular, it must remain possible to compile Solidity and Vyper code to EVM bytecode, with no significant loss of performance or increase in gas price.
|
||||
|
||||
## PROPOSAL
|
||||
Especially important is efficient translation to and from eWasm. To that end we maintain a close correspondence between eWasm instructions and proposed EVM instructions.
|
||||
|
||||
We propose to deprecate two existing instructions - `JUMP` and `JUMPI`. They take their argument on the stack, which means that unless the value is constant they can jump to any `JUMPDEST`. (In simple cases like `PUSH 0 JUMP` the value on the stack can be known to be constant, but in general it's difficult.) We must nonetheless continue to support them in old code.
|
||||
| Wasm | EIP-615 |
|
||||
| -------- | -------- |
|
||||
| br | JUMPTO |
|
||||
| br_if | JUMPIF |
|
||||
| br_table | JUMPV |
|
||||
| call | JUMPSUB |
|
||||
| call_indirect | JUMPSUBV |
|
||||
| return | RETURN |
|
||||
| local.get | GETLOCAL |
|
||||
| local.put | PUTLOCAL |
|
||||
| tables | DATA |
|
||||
|
||||
Having deprecated `JUMP` and `JUMPI`, we propose new instructions to support their legitimate uses.
|
||||
|
||||
### Preliminaries
|
||||
#### Preliminaries
|
||||
|
||||
These forms
|
||||
* `INSTRUCTION x,`
|
||||
* `INSTRUCTION x, y`
|
||||
* `INSTRUCTION n, x ...`
|
||||
> *`INSTRUCTION`*
|
||||
>
|
||||
> *`INSTRUCTION x`*
|
||||
>
|
||||
> *`INSTRUCTION x, y`*
|
||||
|
||||
name instructions with one, two, and two or more arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. The arguments are laid out as immediate data bytes following the opcode. The size and encoding of immediate data fields is open to change. In particular, easily-parsed variable-length encodings might prove useful for bytecode offsets - which are in practice small but in principle can be large.
|
||||
name an *`INSTRUCTION`* with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.)
|
||||
|
||||
### Primitives
|
||||
#### Branches and Subroutines
|
||||
|
||||
The two most important uses of `JUMP` and `JUMPI` are static jumps and return jumps. Conditional and unconditional static jumps are the mainstay of control flow. Return jumps are implemented as a dynamic jump to a return address pushed on the stack. With the combination of a static jump and a dynamic return jump you can - and Solidity does - implement subroutines. The problem is that static analysis cannot tell the one place the return jump is going, so it must analyze every possibility.
|
||||
The two most important uses of `JUMP` and `JUMPI` are static jumps and return jumps. Conditional and unconditional static jumps are the mainstay of control flow. Return jumps are implemented as a dynamic jump to a return address pushed on the stack. With the combination of a static jump and a dynamic return jump you can—and Solidity does—implement subroutines. The problem is that static analysis cannot tell the one place the return jump is going, so it must analyze every possibility (a heavy analysis).
|
||||
|
||||
Static jumps are provided by
|
||||
* `JUMPTO jump_target`
|
||||
* `JUMPIF jump_target`
|
||||
which are the same as `JUMP` and `JUMPI` except that they jump to an immediate `jump_target`, given as four immediate bytes, rather than an address on the stack.
|
||||
> `JUMPTO jump_target`
|
||||
>
|
||||
> `JUMPIF jump_target`
|
||||
>
|
||||
> which are the same as `JUMP` and `JUMPI` except that they jump to an immediate `jump_target` rather than an address on the stack.
|
||||
|
||||
To support subroutines, `BEGINSUB`, `JUMPSUB`, and `RETURNSUB` are provided. Brief descriptions follow, and full semantics are given below.
|
||||
|
||||
* `BEGINSUB n_args, n_results`
|
||||
marks the **single** entry to a subroutine. `n_args` items are taken off of the stack at entry to, and `n_results` items are placed on the stack at return from the subroutine. `n_args` and `n_results` are given as one immediate byte each. The bytecode for a subroutine ends at the next `BEGINSUB` instruction (or `BEGINDATA`, below) or at the end of the bytecode.
|
||||
> `BEGINSUB n_args, n_results`
|
||||
>
|
||||
> marks the **single** entry to a subroutine. `n_args` items are taken off of the stack at entry to, and `n_results` items are placed on the stack at return from the subroutine. The subroutine ends at the next `BEGINSUB` instruction (or `BEGINDATA`, below) or at the end of the bytecode.
|
||||
|
||||
* `JUMPSUB jump_target`
|
||||
jumps to an immediate subroutine address, given as four immediate bytes.
|
||||
> `JUMPSUB jump_target`
|
||||
>
|
||||
> jumps to an immediate subroutine address.
|
||||
|
||||
* `RETURNSUB`
|
||||
returns from the current subroutine to the instruction following the JUMPSUB that entered it.
|
||||
> `RETURNSUB`
|
||||
>
|
||||
>returns from the current subroutine to the instruction following the JUMPSUB that entered it.
|
||||
|
||||
These five simple instructions form the primitives of the proposal.
|
||||
#### Switches, Callbacks, and Virtual Functions
|
||||
|
||||
### Data
|
||||
Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit.
|
||||
|
||||
In order to validate subroutines, EVM bytecode must be sequentially scanned matching jumps to their destinations. Since creation code has to contain the runtime code as data, that code might not correctly validate in the creation context and also does not have to be validated prior to the execution of the creation code. Because of that, there needs to be a way to place data into the bytecode that will be skipped over and not validated. Such data will prove useful for other purposes as well.
|
||||
Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs.
|
||||
|
||||
* `BEGINDATA`
|
||||
specifies that all of the following bytes to the end of the bytecode are data, and not reachable code.
|
||||
> `JUMPV n, jump_targets`
|
||||
>
|
||||
> jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the BEGINDATA bytecode as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used.
|
||||
|
||||
### Indirect Jumps
|
||||
Dynamic jumps to a `BEGINSUB` are used to implement `O(1)` virtual functions and callbacks, which take just two pointer dereferences on most CPUs.
|
||||
|
||||
The primitive operations provide for static jumps. Dynamic jumps are also used for O(1) indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit.
|
||||
> `JUMPSUBV n, jump_targets`
|
||||
>
|
||||
>jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the DATA bytecode, as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used.
|
||||
|
||||
Dynamic jumps to a `JUMPDEST` are used to implement O(1) jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs.
|
||||
* `JUMPV n, jumpdest ...`
|
||||
jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline in the bytecode. If the index is greater than or equal to `n - 1` the last (default) offset is used. `n` is given as four immediate bytes, all `JUMPDEST` offsets as four immediate bytes each.
|
||||
#### Variable Access
|
||||
|
||||
Dynamic jumps to a `BEGINSUB` are used to implement O(1) virtual functions and callbacks, which take just two pointer dereferences on most CPUs.
|
||||
* `JUMPSUBV n, beginsub ...`
|
||||
jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline in the bytecode, MSB-first. If the index is greater than or equal to `n - 1` the last (default) offset is used. `n` is given as four immediate bytes, the `n` offsets as four immediate bytes each.
|
||||
These operations provide convenient access to subroutine parameters and local variables at fixed stack offsets within a subroutine. Otherwise only sixteen variables can be directly addressed.
|
||||
|
||||
`JUMPV` and `JUMPSUBV` are not strictly necessary. They provide O(1) operations that can be replaced by O(n) or O(log n) EVM code using static jumps, but that code will be slower, larger and use more gas for things that can and should be fast, small, and cheap, and that are directly supported in WASM with br_table and call_indirect.
|
||||
> `PUTLOCAL n`
|
||||
>
|
||||
> Pops the stack to the local variable `n`.
|
||||
|
||||
### Variable Access
|
||||
> `GETLOCAL n`
|
||||
>
|
||||
> Pushes the local variable `n` onto the stack.
|
||||
|
||||
These operations provide convenient access to subroutine parameters and other variables at fixed stack offsets within a subroutine.
|
||||
Local variable `n` is the nth stack item below the frame pointer, `FP[-n]`, as defined below.
|
||||
|
||||
* `PUTLOCAL n`
|
||||
Pops the top value on the stack and copies it to local variable `n`.
|
||||
#### Data
|
||||
|
||||
* `GETLOCAL n`
|
||||
Pushes the value of local variable `n` on the EVM stack.
|
||||
There needs to be a way to place unreachable data into the bytecode that will be skipped over and not validated. Indirect jump vectors will not be valid code. Initialization code must create runtime code from data that might not be valid code. And unreachable data might prove useful to programs for other purposes.
|
||||
|
||||
Local variable `n` is `FP[-n]` as defined below.
|
||||
> `BEGINDATA`
|
||||
>
|
||||
> specifies that all of the following bytes to the end of the bytecode are data, and not reachable code.
|
||||
|
||||
## SEMANTICS
|
||||
### Semantics
|
||||
|
||||
Jumps to and returns from subroutines are described here in terms of
|
||||
* the EVM data stack, (as defined in the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) usually just called “the stack”,
|
||||
* a return stack of `JUMPSUB` and `JUMPSUBV` offsets, and
|
||||
* a frame stack of frame pointers.
|
||||
* The EVM data stack, (as defined in the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf)) usually just called “the stack.”
|
||||
* A return stack of `JUMPSUB` and `JUMPSUBV` offsets.
|
||||
* A frame stack of frame pointers.
|
||||
|
||||
We will adopt the following conventions to describe the machine state:
|
||||
* The _program counter_ `PC` is (as usual) the byte offset of the currently executing instruction.
|
||||
* The _stack pointer_ `SP` corresponds to the number of items on the stack - the _stack size_. As a negative offset it addresses the current top of the stack of data values, where new items are pushed.
|
||||
* The _stack pointer_ `SP` corresponds to the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf)'s substate `s` of the machine state.
|
||||
* `SP[0]` is where a new item is can be pushed on the stack.
|
||||
* `SP[1]` is the first item on the stack, which can be popped off the stack.
|
||||
* The stack grows towards lower addresses.
|
||||
* The _frame pointer_ `FP` is set to `SP + n_args` at entry to the currently executing subroutine.
|
||||
* The _stack items_ between the frame pointer and the current stack pointer are called the _frame_.
|
||||
* The current number of items in the frame, `FP - SP`, is the _frame size_.
|
||||
* The _stack items_ between the frame pointer and the current stack pointer are called the _frame_.
|
||||
* The current number of items in the frame, `FP - SP`, is the _frame size_.
|
||||
|
||||
Defining the frame pointer so as to include the arguments is unconventional, but better fits our stack semantics and simplifies the remainder of the proposal.
|
||||
|
||||
The frame pointer and return stacks are internal to the subroutine mechanism, and not directly accessible to the program. This is necessary to prevent the program from modifying its state in ways that could be invalid.
|
||||
The frame pointer and return stacks are internal to the subroutine mechanism, and not directly accessible to the program. This is necessary to prevent the program from modifying its own state in ways that could be invalid.
|
||||
|
||||
The first instruction of an array of EVM bytecode begins execution of a _main_ routine with no arguments, `SP` and `FP` set to 0, and with one value on the return stack - `code size - 1`. (Executing the virtual byte of 0 after this offset causes an EVM to stop. Thus executing a `RETURNSUB` with no prior `JUMPSUB` or `JUMBSUBV` - that is, in the _main_ routine - executes a `STOP`.)
|
||||
The first instruction of an array of EVM bytecode begins execution of a _main_ routine with no arguments, `SP` and `FP` set to 0, and with one value on the return stack—`code_size - 1`. (Executing the virtual byte of 0 after this offset causes an EVM to stop. Thus executing a `RETURNSUB` with no prior `JUMPSUB` or `JUMBSUBV`—that is, in the _main_ routine—executes a `STOP`.)
|
||||
|
||||
Execution of a subroutine begins with `JUMPSUB` or `JUMPSUBV`, which
|
||||
* push `PC` on the return stack,
|
||||
* push `FP` on the frame stack,
|
||||
thus suspending execution of the current subroutine, and
|
||||
* set `FP` to `SP + n_args`, and
|
||||
* set `PC` to the specified `BEGINSUB` address,
|
||||
thus beginning execution of the new subroutine.
|
||||
(The _main_ routine is not addressable by `JUMPSUB` instructions.)
|
||||
|
||||
Execution of a subroutine is suspended during and resumed after execution of nested subroutines, and ends upon encountering a `RETURNSUB`, which
|
||||
* sets `FP` to the top of the virtual frame stack and pops the stack, and
|
||||
* sets `PC` to top of the return stack and pops the stack
|
||||
* pushes `PC` on the return stack,
|
||||
* pushes `FP` on the frame stack
|
||||
* thus suspending execution of the current subroutine,
|
||||
* sets `FP` to `SP + n_args`, and
|
||||
* sets `PC` to the specified `BEGINSUB` address
|
||||
* thus beginning execution of the new subroutine.
|
||||
|
||||
The _main_ routine is not addressable by `JUMPSUB` instructions. Execution of a subroutine is suspended during and resumed after execution of nested subroutines, and ends upon encountering a `RETURNSUB`, which
|
||||
|
||||
* sets `FP` to the top of the virtual frame stack and pops the stack,
|
||||
* sets `SP` to `FP + n_results`,
|
||||
* sets `PC` to top of the return stack and pops the stack, and
|
||||
* advances `PC` to the next instruction
|
||||
thus resuming execution of the enclosing subroutine or _main_ program.
|
||||
A `STOP or `RETURN` also ends the execution of a subroutine.
|
||||
|
||||
## VALIDITY
|
||||
thus resuming execution of the enclosing subroutine or _main_ program. A `STOP` or `RETURN` also ends the execution of a subroutine.
|
||||
|
||||
We would like to consider EVM code valid if and only if no execution of the program can lead to an exceptional halting state. But we must and will validate code in linear time. So our validation does not consider the code’s data and computations, only its control flow and stack use. This means we will reject programs with invalid code paths, even if those paths cannot be executed at runtime. Most conditions can be validated, and will not need to be checked at runtime; the exceptions are sufficient gas and sufficient stack. So some false negatives and runtime checks are the price we pay for linear time validation.
|
||||
For example, starting from this stack,
|
||||
```
|
||||
_________________
|
||||
| locals 20 <- FP
|
||||
frame | 21
|
||||
______|___________ 22
|
||||
<- SP
|
||||
```
|
||||
and after pushing two arguments and branching with `JUMPSUB` to a `BEGINSUB 2, 3`
|
||||
```
|
||||
PUSH 10
|
||||
PUSH 11
|
||||
JUMPSUB beginsub
|
||||
```
|
||||
and initializing three local variables
|
||||
```
|
||||
PUSH 99
|
||||
PUSH 98
|
||||
PUSH 97
|
||||
```
|
||||
the stack looks like this
|
||||
```
|
||||
20
|
||||
21
|
||||
__________________ 22
|
||||
| arguments 10 <- FP
|
||||
frame |___________ 11
|
||||
| locals 99
|
||||
| 98
|
||||
______|___________ 97
|
||||
<- SP
|
||||
```
|
||||
After some amount of computation the stack could look like this
|
||||
```
|
||||
20
|
||||
21
|
||||
__________________ 22
|
||||
| returns 44 <- FP
|
||||
| 43
|
||||
frame |___________ 42
|
||||
| locals 13
|
||||
______|___________ 14
|
||||
<- SP
|
||||
```
|
||||
and after `RETURNSUB` would look like this
|
||||
```
|
||||
_________________
|
||||
| locals 20 <- FP
|
||||
| 21
|
||||
frame |___________ 22
|
||||
| returns 44
|
||||
| 43
|
||||
______|___________ 42
|
||||
<- SP
|
||||
```
|
||||
|
||||
_Execution_ is as defined in the Yellow Paper - a sequence of changes in the EVM state. The conditions on valid code are preserved by state changes. At runtime, if execution of an instruction would violate a condition the execution is in an exceptional halting state. The yellow paper defines five such states.
|
||||
>1 Insufficient gas
|
||||
### Validity
|
||||
|
||||
>2 More than 1024 stack items
|
||||
We would like to consider EVM code valid iff no execution of the program can lead to an exceptional halting state, but we must validate code in linear time. So our validation does not consider the code’s data and computations, only its control flow and stack use. This means we will reject programs with invalid code paths, even if those paths are not reachable. Most conditions can be validated, and will not need to be checked at runtime; the exceptions are sufficient gas and sufficient stack. As such, static analysis may yield false negatives belonging to well-understood classes of code requiring runtime checks. Aside from those cases, we can validate large classes at validation time and with linear complexity.
|
||||
|
||||
>3 Insufficient stack items
|
||||
_Execution_ is as defined in the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf)—a sequence of changes in the EVM state. The conditions on valid code are preserved by state changes. At runtime, if execution of an instruction would violate a condition the execution is in an exceptional halting state. The Yellow Paper defines five such states.
|
||||
>**1** Insufficient gas
|
||||
|
||||
>4 Invalid jump destination
|
||||
>**2** More than 1024 stack items
|
||||
|
||||
>5 Invalid instruction
|
||||
>**3** Insufficient stack items
|
||||
|
||||
>**4** Invalid jump destination
|
||||
|
||||
>**5** Invalid instruction
|
||||
|
||||
We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose.
|
||||
|
||||
To handle the return stack we expand the conditions on stack size:
|
||||
>2a The size of the data stack does not exceed 1024.
|
||||
>**2a** The size of the data stack does not exceed 1024.
|
||||
|
||||
>2b The size of the return stack does not exceed 1024.
|
||||
>**2b** The size of the return stack does not exceed 1024.
|
||||
|
||||
Given our more detailed description of the data stack we restate condition 3 - stack underflow - as
|
||||
>3 `SP` must be less than or equal to `FP`
|
||||
Given our more detailed description of the data stack we restate condition 3—stack underflow—as
|
||||
>**3** `SP` must be less than or equal to `FP`
|
||||
|
||||
Since the various `DUP` and `SWAP` operations are formalized as taking items off the stack and putting them back on, this prevents `DUP` and `SWAP` from accessing data below the frame pointer, since taking too many items off of the stack would mean that `SP` is less than `FP`.
|
||||
Since the various `DUP` and `SWAP` operations—as well as `PUTLOCAL` and `GETLOCAL`—are defined as taking items off the stack and putting them back on, this prevents them from accessing data below the frame pointer, since taking too many items off of the stack would mean that `SP` is less than `FP`.
|
||||
|
||||
To handle the new jump instructions and subroutine boundaries we expand the conditions on jumps and jump destinations.
|
||||
>4a `JUMPTO`, `JUMPIF`, and `JUMPV` address only `JUMPDEST` instructions.
|
||||
To handle the new jump instructions and subroutine boundaries, we expand the conditions on jumps and jump destinations.
|
||||
>**4a** `JUMPTO`, `JUMPIF`, and `JUMPV` address only `JUMPDEST` instructions.
|
||||
|
||||
>4b `JUMPSUB` and `JUMPSUBV` address only `BEGINSUB` instructions.
|
||||
>**4b** `JUMPSUB` and `JUMPSUBV` address only `BEGINSUB` instructions.
|
||||
|
||||
>4c `JUMP` instructions do not address instructions outside of the subroutine they occur in.
|
||||
>**4c** `JUMP` instructions do not address instructions outside of the subroutine they occur in.
|
||||
|
||||
We have two new conditions on execution to ensure consistent use of the stack by subroutines:
|
||||
>6 For `JUMPSUB` and `JUMPSUBV` the frame size is at least the `n_args` of the `BEGINSUB`(s) to jump to.
|
||||
>**6** For `JUMPSUB` and `JUMPSUBV` the frame size is at least the `n_args` of the `BEGINSUB`(s) to jump to.
|
||||
|
||||
>7 For `RETURNSUB` the frame size is equal to the `n_results` of the enclosing `BEGINSUB`.
|
||||
>**7** For `RETURNSUB` the frame size is equal to the `n_results` of the enclosing `BEGINSUB`.
|
||||
|
||||
Finally, we have one condition that prevents pathological uses of the stack:
|
||||
>8 For every instruction in the code the frame size is constant.
|
||||
>**8** For every instruction in the code the frame size is constant.
|
||||
|
||||
In practice, we must test at runtime for conditions 1 and 2 - sufficient gas and sufficient stack. We don’t know how much gas there will be, we don’t know how deep a recursion may go, and analysis of stack depth even for non-recursive programs is non-trivial.
|
||||
In practice, we must test at runtime for conditions 1 and 2—sufficient gas and sufficient stack. We don’t know how much gas there will be, we don’t know how deep a recursion may go, and analysis of stack depth even for non-recursive programs is nontrivial.
|
||||
|
||||
All of the remaining conditions we validate statically.
|
||||
|
||||
## VALIDATION
|
||||
|
||||
#### Costs & Codes
|
||||
|
||||
All of the instructions are `O(1)` with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` should be _verylow_. Measurement will tell.
|
||||
|
||||
We suggest the following opcodes:
|
||||
```
|
||||
0xb0 JUMPTO
|
||||
0xb1 JUMPIF
|
||||
0xb2 JUMPV
|
||||
0xb3 JUMPSUB
|
||||
0xb4 JUMPSUBV
|
||||
0xb5 BEGINSUB
|
||||
0xb6 BEGINDATA
|
||||
0xb7 RETURNSUB
|
||||
0xb8 PUTLOCAL
|
||||
0xb9 GETLOCAL
|
||||
```
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
These changes would need to be implemented in phases at decent intervals:
|
||||
>**1.** If this EIP is accepted, invalid code should be deprecated. Tools should stop generating invalid code, users should stop writing it, and clients should warn about loading it.
|
||||
|
||||
>**2.** A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely.
|
||||
|
||||
If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying phase 2. Since we must continue to run old code this is not technically difficult.
|
||||
|
||||
## Rationale
|
||||
|
||||
This design was highly constrained by the existing EVM semantics, the requirement for eWasm compatibility, and the security demands of the Ethereum environment. It was also informed by the lead author's previous work implementing Java and Scheme interpreters. As such there was very little room for alternative designs.
|
||||
|
||||
As described above, the approach was simply to deprecate the problematic dynamic jumps, then ask what opcodes were necessary to provide for the features they supported. These needed to include those provided by eWasm, which themselves were modeled after typical hardware. The only real innovation was to move the frame pointer and the return pointer to their own stacks, so as to prevent any possibility of overwriting them. (Although Forth also uses a return stack.) This allowed for treating subroutine arguments as local variables, and facilitated the return of multiple values.
|
||||
|
||||
## Implementation
|
||||
|
||||
Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. Compiled code can use native call instructions, greatly improving performance. Further optimizations include minimizing runtime checks for exceptions, condensing gas metering, and otherwise taking advantage of validated code wherever possible. A lightly tested reference implementation is available in [Greg Colvin's Aleth fork.](https://github.com/gcolvin/aleth/tree/master/libaleth-interpreter)
|
||||
|
||||
## Appendix A
|
||||
### Validation
|
||||
|
||||
Validation comprises two tasks:
|
||||
* Checking that jump destinations are correct and instructions valid.
|
||||
* Checking that subroutines satisfy the conditions on control flow and stack use.
|
||||
* Check that jump destinations are correct and instructions valid.
|
||||
* Check that subroutines satisfy the conditions on control flow and stack use.
|
||||
|
||||
We sketch out these two validation functions in pseudo-C below. To simplify the presentation only the five primitives are handled (`JUMPV` and `JUMPSUBV` would just add more complexity to loop over their vectors), we assume helper functions for extracting instruction arguments from immediate data and managing the stack pointer and program counter, and some optimizations are forgone.
|
||||
We sketch out these two validation functions in pseudo-C below. To simplify the presentation only the five primitives are handled (`JUMPV` and `JUMPSUBV` would just add more complexity to loop over their vectors), we assume helper functions for extracting instruction arguments from immediate data and managing the stack pointer and program counter, and some optimizations are forgone.
|
||||
|
||||
### Validating jumps
|
||||
#### Validating Jumps
|
||||
|
||||
Validating that jumps are to valid addresses takes two sequential passes over the bytecode - one to build sets of jump destinations and subroutine entry points, another to check that addresses jumped to are in the appropriate sets.
|
||||
Validating that jumps are to valid addresses takes two sequential passes over the bytecode—one to build sets of jump destinations and subroutine entry points, another to check that addresses jumped to are in the appropriate sets.
|
||||
```
|
||||
bytecode[code_size] // contains EVM bytecode to validate
|
||||
is_sub[code_size] // is there a BEGINSUB at PC?
|
||||
|
@ -211,14 +333,15 @@ Validating that jumps are to valid addresses takes two sequential passes over th
|
|||
|
||||
bool validate_jumps(PC)
|
||||
{
|
||||
current_sub = PC
|
||||
|
||||
// build sets of BEGINSUBs and JUMPDESTs
|
||||
current_sub = 0
|
||||
for (PC = 0; instruction = bytecode[PC]; PC = advance_pc(PC))
|
||||
{
|
||||
if instruction is invalid
|
||||
return false
|
||||
if instruction is BEGINDATA
|
||||
break
|
||||
break;
|
||||
if instruction is BEGINSUB
|
||||
is_sub[PC] = true
|
||||
current_sub = PC
|
||||
|
@ -229,7 +352,6 @@ Validating that jumps are to valid addresses takes two sequential passes over th
|
|||
}
|
||||
|
||||
// check that targets are in subroutine
|
||||
current_sub = 0
|
||||
for (PC = 0; instruction = bytecode[PC]; PC = advance_pc(PC))
|
||||
{
|
||||
if instruction is BEGINDATA
|
||||
|
@ -245,16 +367,16 @@ Validating that jumps are to valid addresses takes two sequential passes over th
|
|||
if sub_for_pc[PC] is not current_sub
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return true
|
||||
}
|
||||
```
|
||||
Note that code like this is already run by EVMs to check dynamic jumps, including building the jump destination set every time a contract is run, and doing a lookup in the jump destination set before every jump.
|
||||
|
||||
### Validating subroutines
|
||||
#### Subroutine Validation
|
||||
|
||||
This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is O(n-vertices + n-edges)
|
||||
This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|)`: The sum of the number of edges and number of verticies in the graph.
|
||||
|
||||
The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise.
|
||||
The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise.
|
||||
|
||||
```
|
||||
bytecode[code_size] // contains EVM bytecode to validate
|
||||
|
@ -263,7 +385,8 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t
|
|||
// we validate each subroutine individually, as if at top level
|
||||
// * PC is the offset in the code to start validating at
|
||||
// * return_pc is the top PC on return stack that RETURNSUB returns to
|
||||
// * at top level FP = 0, so SP is both the frame size and the stack size
|
||||
// * at top level FP = SP = 0 is both the frame size and the stack size
|
||||
// * as items are pushed SP get more negative, so the stack size is -SP
|
||||
validate_subroutine(PC, return_pc, SP)
|
||||
{
|
||||
// traverse code sequentially, recurse for jumps
|
||||
|
@ -276,32 +399,32 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t
|
|||
{
|
||||
// check for constant frame size
|
||||
if instruction is JUMPDEST
|
||||
if SP != frame_size[PC]
|
||||
if -SP != frame_size[PC]
|
||||
return false
|
||||
|
||||
// return to break cycle
|
||||
return true
|
||||
}
|
||||
frame_size[PC] = SP
|
||||
frame_size[PC] = -SP
|
||||
|
||||
// effect of instruction on stack
|
||||
n_removed = removed_items(instructions)
|
||||
n_added = added_items(instruction)
|
||||
|
||||
// check for stack underflow
|
||||
if SP < n_removed
|
||||
if -SP < n_removed
|
||||
return false
|
||||
|
||||
// net effect of removing and adding stack items
|
||||
SP -= n_removed
|
||||
SP += n_added
|
||||
SP += n_removed
|
||||
SP -= n_added
|
||||
|
||||
// check for stack overflow
|
||||
if SP > 1024
|
||||
if -SP > 1024
|
||||
return false
|
||||
|
||||
if instruction is STOP, RETURN, SUICIDE or BEGINDATA
|
||||
return true
|
||||
if instruction is STOP, RETURN, or SUICIDE
|
||||
return true
|
||||
|
||||
// violates single entry
|
||||
if instruction is BEGINSUB
|
||||
|
@ -309,13 +432,13 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t
|
|||
|
||||
// return to top or from recursion to JUMPSUB
|
||||
if instruction is RETURNSUB
|
||||
break;
|
||||
return true;;
|
||||
|
||||
if instruction is JUMPSUB
|
||||
{
|
||||
// check for enough arguments
|
||||
sub_pc = jump_target(PC)
|
||||
if SP < n_args(sub_pc)
|
||||
if -SP < n_args(sub_pc)
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
@ -339,36 +462,44 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t
|
|||
}
|
||||
|
||||
// check for right number of results
|
||||
if SP != n_results(return_pc)
|
||||
if (-SP != n_results(return_pc)
|
||||
return false
|
||||
return true
|
||||
}
|
||||
```
|
||||
## Appendix B
|
||||
### EVM Analysis
|
||||
|
||||
### COSTS & CODES
|
||||
There is a large and growing ecosystem of researchers, authors, teachers, auditors, and analytic tools--providing software and services focused on the correctness and security of EVM code. A small saample is given here.
|
||||
|
||||
All of the instructions are O(1) with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` should be _verylow_. Measurement will tell.
|
||||
#### Some Tools
|
||||
|
||||
We tentatively suggest the following opcodes:
|
||||
```
|
||||
0xB0 JUMPTO
|
||||
0xB1 JUMPIF
|
||||
0XB2 JUMPSUB
|
||||
0xB4 JUMPSUBV
|
||||
0xB5 BEGINSUB
|
||||
0xB6 BEGINDATA
|
||||
0xB8 RETURNSUB
|
||||
0xB9 PUTLOCAL
|
||||
0xBA GETLOCAL
|
||||
```
|
||||
* [Contract Library](https://contract-library.com/)
|
||||
* [EthereumJ](https://github.com/ethereum/ethereumj)
|
||||
* [Exthereum](https://github.com/exthereum/blockchain)
|
||||
* [Harmony](https://github.com/ether-camp/ethereum-harmony)
|
||||
* [JEB](https://www.pnfsoftware.com/blog/ethereum-smart-contract-decompiler/)
|
||||
* [Mythril](https://github.com/ConsenSys/mythril)
|
||||
* [Securify](https://github.com/eth-sri/securify)
|
||||
* [Skale](https://www.skalelabs.com/)
|
||||
* [Status](https://status.im/)
|
||||
|
||||
### GETTING THERE FROM HERE
|
||||
#### Some Papers
|
||||
|
||||
These changes would need to be implemented in phases at decent intervals:
|
||||
>1 If this EIP is accepted, invalid code should be deprecated. Tools should stop generating invalid code, users should stop writing it, and clients should warn about loading it.
|
||||
* [A Formal Verification Tool for Ethereum VM Bytecode](https://www.google.com/url?q=http://fsl.cs.illinois.edu/FSL/papers/2018/park-zhang-saxena-daian-rosu-2018-fse/park-zhang-saxena-daian-rosu-2018-fse-public.pdf)
|
||||
* [A Lem formalization of EVM and some Isabelle/HOL proofs](https://github.com/pirapira/eth-isabelle)
|
||||
* [A survey of attacks on Ethereum smart contracts](https://eprint.iacr.org/2016/1007.pdf)
|
||||
* [Defining the Ethereum Virtual Machine for Interactive Theorem Provers](https://www.google.com/url?q=http://fc17.ifca.ai/wtsc/Defining%2520the%2520Ethereum%2520Virtual%2520Machine%2520for%2520Interactive%2520Theorem%2520Provers.pdf)
|
||||
* [Ethereum 2.0 Specifications](https://github.com/ethereum/eth2.0-specs)
|
||||
* [Formal Verification of Smart Contracts](https://www.cs.umd.edu/~aseem/solidetherplas.pdf)
|
||||
* [JelloPaper: Human Readable Semantics of EVM in K](https://jellopaper.org/)
|
||||
* [KEVM: A Complete Semantics of the Ethereum Virtual Machine.](https://www.ideals.illinois.edu/bitstream/handle/2142/97207/hildenbrandt-saxena-zhu-rodrigues-guth-daian-rosu-2017-tr.pdf)
|
||||
* [Making Smart Contracts Smarter](https://eprint.iacr.org/2016/633.pdf)
|
||||
* [Securify: Practical Security Analysis of Smart Contracts](https://arxiv.org/pdf/1806.01143.pdf)
|
||||
* [The Thunder Protocol](https://docs.thundercore.com/thunder-whitepaper.pdf)
|
||||
* [Towards Verifying Ethereum Smart Contract Bytecode in Isabelle/HOL](https://ts.data61.csiro.au/publications/csiro_full_text//Amani_BBS_18.pdf)
|
||||
|
||||
>2 A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely.
|
||||
|
||||
If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new - but without validation. That is, by delaying step 2. Since we must continue to run old code this is not technically difficult.
|
||||
## Copyright
|
||||
|
||||
Implementation of this proposal need not be difficult, At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. JIT code can use native calls. Further optimizations include minimizing runtime checks for exceptions and taking advantage of validated code wherever possible.
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
|
|
@ -16,12 +16,12 @@ A proposal to provide Single Instruction Multiple Data types and operations for
|
|||
|
||||
Most all modern CPUs include SIMD hardware that operates on wide registers of data, applying a Single Instruction to Multiple Data lanes in parallel, where lanes divide a register into a vector of scalar elements of equal size. This model is an excellent fit for the wide stack items of the EVM, offering substantial performance boosts for operations that can be expressed as parallel operations on vectors of scalars. For some examples, a brief literature search finds SIMD speedups of
|
||||
* up to 7X for [SHA-512](http://keccak.noekeon.org/sw_performance.html)
|
||||
* 4X for [elliptic curve scalar multiplication](http://link.springer.com/chapter/10.1007/3-540-45439-X_16)
|
||||
* 3X to 4X for [BLAKE2b](http://github.com/minio/blake2b-simd)
|
||||
* 4X for [elliptic curve scalar multiplication](https://link.springer.com/chapter/10.1007/3-540-45439-X_16)
|
||||
* 3X to 4X for [BLAKE2b](https://github.com/minio/blake2b-simd)
|
||||
* up to 3X for [OpenSSL](https://software.intel.com/en-us/articles/improving-openssl-performance)
|
||||
* 2X to 3X for [elliptic curve modular multiplication](http://ieee-hpec.org/2013/index_htm_files/24-Simd-acceleration-Pabbuleti-2886999.pdf)
|
||||
* 1.7X to 1.9X for [SHA-256](https://github.com/minio/sha256-simd)
|
||||
* 1.3X for [RSA encryption](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.738.1218&rep=rep1&type=pdf)
|
||||
* 1.3X for [RSA encryption](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.738.1218&rep=rep1&type=pdf)
|
||||
|
||||
## SPECIFICATION
|
||||
|
||||
|
@ -118,7 +118,7 @@ For most modern languages (including Rust, Python, Go, Java, and C++) compilers
|
|||
|
||||
One motivation for these operations, besides taking full advantage of the hardware, is assigning lower gas costs for operations on smaller scalars.
|
||||
|
||||
On a machine with 64-bit registers the standard algorithms from Knuth's [Art of Computer Programming](http://library.aceondo.net/ebooks/Computer_Science/algorithm-the_art_of_computer_programming-knuth.pdf) require 32-bit digits, using the upper half of a register for overflows, so for 256-bit values N=8 digits are needed, and for 64-bit values N=2 digits are needed. The cycle counts for these algorithms are:
|
||||
On a machine with 64-bit registers the standard algorithms from Knuth's [Art of Computer Programming](https://library.aceondo.net/ebooks/Computer_Science/algorithm-the_art_of_computer_programming-knuth.pdf) require 32-bit digits, using the upper half of a register for overflows, so for 256-bit values N=8 digits are needed, and for 64-bit values N=2 digits are needed. The cycle counts for these algorithms are:
|
||||
|
||||
operation | cycles | N = 2 | N = 4 | N = 8
|
||||
-|-|-|-|-
|
||||
|
|
|
@ -4,13 +4,13 @@ title: Whisper Specification
|
|||
author: Vlad Gluhovsky <gluk256@gmail.com>
|
||||
type: Standards Track
|
||||
category: Networking
|
||||
status: Draft
|
||||
status: Final
|
||||
created: 2017-05-05
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
||||
This draft EIP describes the format of Whisper messages within the ÐΞVp2p Wire Protocol.
|
||||
This EIP describes the format of Whisper messages within the ÐΞVp2p Wire Protocol.
|
||||
This EIP should substitute the [existing specification](https://github.com/ethereum/wiki/wiki/Whisper-Wire-Protocol).
|
||||
More detailed documentation on Whisper could be found [here](https://github.com/ethereum/go-ethereum/wiki/Whisper).
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
eip: 663
|
||||
title: Unlimited SWAP and DUP instructions
|
||||
author: Alex Beregszaszi (@axic)
|
||||
type: Standards Track
|
||||
category: Core
|
||||
status: Draft
|
||||
created: 2017-07-03
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
||||
`SWAP` and `DUP` instructions are limited to a stack depth of 16. Introduce two new instructions, `SWAPn` and `DUPn`, which lift this limitation and allow accessing the stack up to its full depth of 1024 items.
|
||||
|
||||
## Motivation
|
||||
|
||||
Implementing higher level constructs, such as functions, on top of EVM will result in a list of input and output parameters as well as an instruction offset to return to.
|
||||
|
||||
The number of these arguments (or stack items) can easily exceed 16 and thus will require extra care from a compiler to lay them out in a way that all of them are still accessible.
|
||||
|
||||
Introducing `SWAPn` and `DUPn` will provide an option to compilers to simplify accessing deep stack items at the price of possibly increased gas costs.
|
||||
|
||||
## Specification
|
||||
|
||||
Instructions `DUPn` (`0xb0`) and `SWAPn` (`0xb1`) are introduced, which take the top item from stack (referred to as `n`).
|
||||
|
||||
If `n` exceeds 1024 or the current stack depth is less than `n`, then a stack underflow exception is issued. If the current stack depth is at the limit, a stack overflow exception is issued.
|
||||
|
||||
Otherwise
|
||||
- for `DUPn` the stack item at depth `n` is duplicated at the top of the stack
|
||||
- for `SWAPn` the top stack item is swapped with the item at depth `n`
|
||||
|
||||
The gas cost for both instructions is set at 3. In reality the cost for such an operation is 6 including the required `PUSH`.
|
||||
|
||||
Since both of these instructions require the top stack item to contain the position, it is still only possible to reach more than 16 stack items if there is at least one free stack slot.
|
||||
|
||||
## Rationale
|
||||
|
||||
TBA
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
This has no effect on backwards compatibility.
|
||||
|
||||
## Test Cases
|
||||
|
||||
- executing `602a600160026003600460056006600760086009600a600b600c600d600e600f60106011b0` should have `42` as the top stack item
|
||||
- executing `602a600160026003600460056006600760086009600a600b600c600d600e600f60106011b1` should have `42` as the top stack item
|
||||
|
||||
## Implementation
|
||||
|
||||
TBA
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -130,8 +130,8 @@ Implementations of this proposal are here:
|
|||
* Test vectors for Ed25519: https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-6
|
||||
* NaCl regression tests: https://ed25519.cr.yp.to/python/sign.py and https://ed25519.cr.yp.to/python/sign.input
|
||||
* On the recoverability of public keys from signature+message (alone): https://crypto.stackexchange.com/questions/9936/what-signature-schemes-allow-recovering-the-public-key-from-a-signature
|
||||
* Bernstein, D., "Curve25519: new Diffie-Hellman speed records", DOI 10.1007/11745853_14, February 2006, http://cr.yp.to/ecdh.html
|
||||
* Hamburg, M., "Ed448-Goldilocks, a new elliptic curve", June 2015, http://eprint.iacr.org/2015/625>
|
||||
* Bernstein, D., "Curve25519: new Diffie-Hellman speed records", DOI 10.1007/11745853_14, February 2006, https://cr.yp.to/ecdh.html
|
||||
* Hamburg, M., "Ed448-Goldilocks, a new elliptic curve", June 2015, https://eprint.iacr.org/2015/625>
|
||||
* RFC8080: Edwards-Curve Digital Security Algorithm (EdDSA) for DNSSEC (https://tools.ietf.org/html/rfc8080)
|
||||
|
||||
## Copyright
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
eip: 698
|
||||
title: OPCODE 0x46 BLOCKREWARD
|
||||
author: Cody Burns <dontPanic@codywburns.com>
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/698
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: Core
|
||||
created: 2017-28-08
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
|
||||
This EIP adds an additional opcode to the EVM which will return a finalized blocks reward value.
|
||||
|
||||
## Abstract
|
||||
|
||||
In the EVM, the 0x40 opcodes are reserved for `Block Information`. Currently reserved opcodes are:
|
||||
* `0X40 BLOCKHASH`
|
||||
* `0X41 COINBASE`
|
||||
* `0X42 TIMESTAMP`
|
||||
* `0X43 NUMBER`
|
||||
* `0X44 DIFFICULTY`
|
||||
* `0X45 GASLIMIT`
|
||||
|
||||
This EIP would add an additional opcode, `0x46 BLOCKREWARD`, which would return the block reward for any finalized block. The finalized block reward would include the base reward, uncle payments, and gas.
|
||||
|
||||
## Motivation
|
||||
|
||||
|
||||
Per EIP-649 ( #669 ) periodic block reward reductions/variance are now planned in the roadmap, however, this EIP is consensus system agnostic and is most useful in decentralized pool operations and for any contract that benefits from knowing a block reward payout(i.e. Merge mined tokens)
|
||||
|
||||
## Specification
|
||||
|
||||
After block `n` all clients should process opcode `0x46` as follows:
|
||||
|
||||
* Value: `0x46`
|
||||
* Mnemonic: `BLOCKREWARD`
|
||||
* δ:` 0` nothing removed from stack
|
||||
* α:`1` block reward added to stack
|
||||
* Description: `Get the block's reward emission`
|
||||
* GasCost: `G<sub>base</sub>`
|
||||
|
||||
Where:`µ'<sub>s</sub>[0] ≡ I<sub>HR</sub>`
|
||||
|
||||
|
||||
## Rationale
|
||||
|
||||
### Contract Mining Pools
|
||||
|
||||
For distributed consensus systems(staking pools and mining pools) ad hoc groups combine resources in order to reduce variance in payouts. Broadly, pool operations function by allowing a collective of miners / stakers to verify their contribution to solving PoW or staking share by periodically submitting solutions which are is representative of the miners probability of finding a true block.
|
||||
|
||||
In all these schemes `B` stands for a block reward minus pool fee and `p` is a probability of finding a block in a share attempt ( `p=1/D`, where `D` is current block difficulty).
|
||||
|
||||
Some common methods of mining pool payout are pay-per-share, `R = B * p`, proportional [`R = B * (n/N)` where `n` is amount of a miners shares, and `N` is amount of all shares in this round.], and pay-per-last-N-shares [`R = B * (n/N)` where miner's reward is calculated on a basis of `N` last shares, instead of all shares for the last round]. All of these methods are predicated on knowing the block reward paid for a given block. In order to provide a trust minimized solution, `0x46` can be used to call a blocks reward for computing payouts.
|
||||
|
||||
### Merge mined tokens
|
||||
|
||||
Contracts could create tokens which could be variably ‘minted’ as a function of block reward by calling `0x46`
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
|
||||
### Currently deployed contracts
|
||||
|
||||
No impact
|
||||
|
||||
### Current clients
|
||||
|
||||
This EIP would be incompatible with currently deployed clients that are not able to handle `0x46` and would process all transactions and block containing the opcode as invalid.
|
||||
|
||||
Implementation should occur as part of a coordinated hardfork.
|
||||
|
||||
## Implementation
|
||||
|
||||
|
||||
## Further reading
|
||||
|
||||
[Mining Pools](https://en.wikipedia.org/wiki/Mining_pool)
|
||||
|
||||
The Yellow Paper Appendix H. Virtual Machine Specification section H.2
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -207,7 +207,7 @@ By adding a prefix to the message makes the calculated signature recognisable as
|
|||
|
||||
Typed data is a JSON object containing type information, domain seprator parameters and the message object. Below is the [json-schema][jsons] definition for `TypedData` param.
|
||||
|
||||
[jsons]: http://json-schema.org/
|
||||
[jsons]: https://json-schema.org/
|
||||
|
||||
```JavaScript
|
||||
{
|
||||
|
@ -274,7 +274,7 @@ There also should be a corresponding `personal_signTypedData` method which accep
|
|||
|
||||
Two methods are added to [Web 3 version 1][web3-1] that parallel the `web3.eth.sign` and `web3.eth.personal.sign` methods.
|
||||
|
||||
[web3-1]: http://web3js.readthedocs.io/en/1.0/index.html
|
||||
[web3-1]: https://web3js.readthedocs.io/en/1.0/index.html
|
||||
|
||||
#### web3.eth.signTypedData
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S
|
|||
pragma solidity ^0.4.20;
|
||||
|
||||
/// @title ERC-721 Non-Fungible Token Standard
|
||||
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
|
||||
/// @dev See https://eips.ethereum.org/EIPS/eip-721
|
||||
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
|
||||
interface ERC721 /* is ERC165 */ {
|
||||
/// @dev This emits when ownership of any NFT changes by any mechanism.
|
||||
|
@ -176,7 +176,7 @@ The **metadata extension** is OPTIONAL for ERC-721 smart contracts (see "caveats
|
|||
|
||||
```solidity
|
||||
/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
|
||||
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
|
||||
/// @dev See https://eips.ethereum.org/EIPS/eip-721
|
||||
/// Note: the ERC-165 identifier for this interface is 0x5b5e139f.
|
||||
interface ERC721Metadata /* is ERC721 */ {
|
||||
/// @notice A descriptive name for a collection of NFTs in this contract
|
||||
|
@ -220,7 +220,7 @@ The **enumeration extension** is OPTIONAL for ERC-721 smart contracts (see "cave
|
|||
|
||||
```solidity
|
||||
/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
|
||||
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
|
||||
/// @dev See https://eips.ethereum.org/EIPS/eip-721
|
||||
/// Note: the ERC-165 identifier for this interface is 0x780e9d63.
|
||||
interface ERC721Enumerable /* is ERC721 */ {
|
||||
/// @notice Count NFTs tracked by this contract
|
||||
|
@ -390,29 +390,29 @@ XXXXERC721, by William Entriken -- a scalable example implementation
|
|||
|
||||
**Standards**
|
||||
|
||||
1. ERC-20 Token Standard. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
|
||||
1. ERC-165 Standard Interface Detection. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
|
||||
1. ERC-173 Owned Standard. https://github.com/ethereum/EIPs/issues/173
|
||||
1. ERC-223 Token Standard. https://github.com/ethereum/EIPs/issues/223
|
||||
1. ERC-677 `transferAndCall` Token Standard. https://github.com/ethereum/EIPs/issues/677
|
||||
1. ERC-827 Token Standard. https://github.com/ethereum/EIPs/issues/827
|
||||
1. ERC-20 Token Standard. https://eips.ethereum.org/EIPS/eip-20
|
||||
1. ERC-165 Standard Interface Detection. https://eips.ethereum.org/EIPS/eip-165
|
||||
1. ERC-173 Owned Standard. https://eips.ethereum.org/EIPS/eip-173
|
||||
1. ERC-223 Token Standard. https://eips.ethereum.org/EIPS/eip-223
|
||||
1. ERC-677 `transferAndCall` Token Standard. https://eips.ethereum.org/EIPS/eip-677
|
||||
1. ERC-827 Token Standard. https://eips.ethereum.org/EIPS/eip-827
|
||||
1. Ethereum Name Service (ENS). https://ens.domains
|
||||
1. Instagram -- What's the Image Resolution? https://help.instagram.com/1631821640426723
|
||||
1. JSON Schema. http://json-schema.org/
|
||||
1. JSON Schema. https://json-schema.org/
|
||||
1. Multiaddr. https://github.com/multiformats/multiaddr
|
||||
1. RFC 2119 Key words for use in RFCs to Indicate Requirement Levels. https://www.ietf.org/rfc/rfc2119.txt
|
||||
|
||||
**Issues**
|
||||
|
||||
1. The Original ERC-721 Issue. https://github.com/ethereum/eips/issues/721
|
||||
1. Solidity Issue \#2330 -- Interface Functions are Axternal. https://github.com/ethereum/solidity/issues/2330
|
||||
1. Solidity Issue \#2330 -- Interface Functions are External. https://github.com/ethereum/solidity/issues/2330
|
||||
1. Solidity Issue \#3412 -- Implement Interface: Allow Stricter Mutability. https://github.com/ethereum/solidity/issues/3412
|
||||
1. Solidity Issue \#3419 -- Interfaces Can't Inherit. https://github.com/ethereum/solidity/issues/3419
|
||||
1. Solidity Issue \#3494 -- Compiler Incorrectly Reasons About the `selector` Function. https://github.com/ethereum/solidity/issues/3494
|
||||
1. Solidity Issue \#3544 -- Cannot Calculate Selector of Function Named `transfer`. https://github.com/ethereum/solidity/issues/3544
|
||||
1. CryptoKitties Bounty Issue \#4 -- Listing all Kitties Owned by a User is `O(n^2)`. https://github.com/axiomzen/cryptokitties-bounty/issues/4
|
||||
1. OpenZeppelin Issue \#438 -- Implementation of `approve` method violates ERC20 standard. https://github.com/OpenZeppelin/zeppelin-solidity/issues/438
|
||||
1. Solidity DelegateCallReturnValue Bug. http://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue
|
||||
1. Solidity DelegateCallReturnValue Bug. https://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue
|
||||
|
||||
**Discussions**
|
||||
|
||||
|
|
305
EIPS/eip-725.md
305
EIPS/eip-725.md
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
eip: 725
|
||||
title: Proxy Identity
|
||||
author: Fabian Vogelsteller (@frozeman)
|
||||
title: Proxy Account
|
||||
author: Fabian Vogelsteller (@frozeman), Tyler Yasaka (@tyleryasaka)
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/725
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
|
@ -10,283 +10,158 @@ created: 2017-10-02
|
|||
---
|
||||
|
||||
## Simple Summary
|
||||
A proxy contract for key management and execution, to establish a Blockchain identity.
|
||||
A standard interface for a simple proxy account.
|
||||
|
||||
## Abstract
|
||||
The following describes standard functions for a unique identity for humans, groups, objects and machines.
|
||||
This identity can hold keys to sign actions (transactions, documents, logins, access, etc), and claims, which are attested from third parties (issuers) and self-attested ([#ERC735](https://github.com/ethereum/EIPs/issues/735)), as well as a proxy function, to act directly on the blockchain.
|
||||
|
||||
The following describes standard functions for a unique identifiable proxy account to be used by humans, groups, organisations, objects and machines. The proxy has 2 abilities: (1) it can execute arbitrary contract calls, and (2) it can hold arbitrary data through a generic key/value store. One of these keys should hold the owner of the contract. The owner may be an address or a key manager contract for more complex management logic. Most importantly, this contract should be the reference point for a long-lasting identifiable profiles.
|
||||
|
||||
## Motivation
|
||||
This standardized identity interface will allow Dapps, smart contracts and third parties to check the validity of a person, organization, object or machine through 2 steps as described in the function XXX. Trust is here transferred to the issuers of claims.
|
||||
|
||||
The most important functions to verify an identity are: `XXX`
|
||||
|
||||
The most important functions to manage an identity are: `XXX`
|
||||
|
||||
|
||||
## Definitions
|
||||
|
||||
- `keys`: Keys are public keys from either external accounts, or contracts' addresses.
|
||||
- `claim issuer`: is another smart contract or external account, which issues claims about this identity. The claim issuer can be an identity contract itself.
|
||||
- `claim`: For details about claims see [#ERC735](https://github.com/ethereum/EIPs/issues/735)
|
||||
|
||||
|
||||
Standardizing a minimal interface for an proxy account allows third parties to interact with various proxy accounts contracts in a consistent manner.
|
||||
the benefit is a persistent account that is independed from single keys and can attach an arbitrary amount of information to verifiy, or enhance the accounts purpose.
|
||||
|
||||
## Specification
|
||||
|
||||
|
||||
### Key Management
|
||||
### Methods
|
||||
|
||||
Keys are cryptographic public keys, or contract addresses associated with this identity.
|
||||
The structure should be as follows:
|
||||
|
||||
- `key`: A public key owned by this identity
|
||||
- `purpose`: `uint256` The key purpose. e.g., 1 = MANAGEMENT, 2 = ACTION, 3 = CLAIM, 4 = ENCRYPTION
|
||||
- `keyType`: The type of key used, which would be a `uint256` for different key types. e.g. 1 = ECDSA, 2 = RSA, etc.
|
||||
- `key`: `bytes32` The public key. // for non-hex and long keys, its the Keccak256 hash of the key
|
||||
#### owner
|
||||
|
||||
Returns the current owner
|
||||
|
||||
```js
|
||||
struct Key {
|
||||
uint256 purpose;
|
||||
uint256 keyType;
|
||||
bytes32 key;
|
||||
}
|
||||
address public owner;
|
||||
```
|
||||
|
||||
#### getKey
|
||||
#### changeOwner
|
||||
|
||||
Returns the full key data, if present in the identity.
|
||||
Changes the current owner. MUST only be called by the current owner of the contract.
|
||||
|
||||
``` js
|
||||
function getKey(bytes32 _key) constant returns(uint256 purpose, uint256 keyType, bytes32 key);
|
||||
```js
|
||||
function changeOwner(address _owner);
|
||||
```
|
||||
|
||||
#### keyHasPurpose
|
||||
**Triggers Event:** [OwnerChanged](#ownerchanged)
|
||||
|
||||
Returns `TRUE` if a key is present and has the given purpose. If the key is not present it returns `FALSE`.
|
||||
#### getData
|
||||
|
||||
``` js
|
||||
function keyHasPurpose(bytes32 _key, uint256 purpose) constant returns(bool exists);
|
||||
Returns the data at the specified key.
|
||||
|
||||
```js
|
||||
function getData(bytes32 _key) external view returns (bytes _value);
|
||||
```
|
||||
|
||||
#### setData
|
||||
|
||||
#### getKeysByPurpose
|
||||
Sets the data at a specific key. MUST only be called by the current owner of the contract.
|
||||
|
||||
Returns an array of public key bytes32 held by this identity.
|
||||
**Triggers Event:** [DataChanged](#datachanged)
|
||||
|
||||
``` js
|
||||
function getKeysByPurpose(uint256 _purpose) constant returns(bytes32[] keys);
|
||||
```js
|
||||
function setData(bytes32 _key, bytes _value) external;
|
||||
```
|
||||
|
||||
|
||||
#### addKey
|
||||
|
||||
Adds a `_key` to the identity. The `_purpose` specifies the purpose of the key. Initially, we propose four purposes:
|
||||
|
||||
- `1`: MANAGEMENT keys, which can manage the identity
|
||||
- `2`: ACTION keys, which perform actions in this identity's name (signing, logins, transactions, etc.)
|
||||
- `3`: CLAIM signer keys, used to sign claims on other identities which need to be revocable.
|
||||
- `4`: ENCRYPTION keys, used to encrypt data e.g. hold in claims.
|
||||
|
||||
MUST only be done by keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval.
|
||||
|
||||
**Triggers Event:** [KeyAdded](#keyadded)
|
||||
|
||||
``` js
|
||||
function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) returns (bool success)
|
||||
```
|
||||
|
||||
|
||||
#### removeKey
|
||||
|
||||
Removes `_key` from the identity.
|
||||
|
||||
MUST only be done by keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval.
|
||||
|
||||
**Triggers Event:** [KeyRemoved](#keyremoved)
|
||||
|
||||
``` js
|
||||
function removeKey(bytes32 _key, uint256 _purpose) returns (bool success)
|
||||
```
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
### Identity usage
|
||||
|
||||
|
||||
#### execute
|
||||
|
||||
Executes an action on other contracts, or itself, or a transfer of ether.
|
||||
SHOULD require `approve` to be called with one or more keys of purpose `1` or `2` to approve this execution.
|
||||
Executes an action on other contracts or a transfer of the blockchains native cryptocurrency. MUST only be called by the current owner of the contract.
|
||||
|
||||
Execute COULD be used as the only accessor for `addKey`, `removeKey` and `replaceKey` and `removeClaim`.
|
||||
|
||||
**Returns `executionId`:** SHOULD be sent to the `approve` function, to approve or reject this execution.
|
||||
|
||||
**Triggers Event:** [ExecutionRequested](#executionrequested)
|
||||
**Triggers on direct execution Event:** [Executed](#executed)
|
||||
|
||||
``` js
|
||||
function execute(address _to, uint256 _value, bytes _data) returns (uint256 executionId)
|
||||
```js
|
||||
function execute(uint256 _operationType, address _to, uint256 _value, bytes _data) external;
|
||||
```
|
||||
|
||||
The `operationType` should represent the assembly operation as follows:
|
||||
- `0` for `call`
|
||||
- `1` for `create`
|
||||
|
||||
#### approve
|
||||
|
||||
Approves an execution or claim addition.
|
||||
This SHOULD require `n` of `m` approvals of keys purpose `1`, if the `_to` of the execution is the identity contract itself, to successfully approve an execution.
|
||||
And COULD require `n` of `m` approvals of keys purpose `2`, if the `_to` of the execution is another contract, to successfully approve an execution.
|
||||
|
||||
**Triggers Event:** [Approved](#approved)
|
||||
**Triggers on successfull execution Event:** [Executed](#executed)
|
||||
**Triggers on successfull claim addition Event:** [ClaimAdded](#claimadded)
|
||||
|
||||
``` js
|
||||
function approve(uint256 _id, bool _approve) returns (bool success)
|
||||
```
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
|
||||
### Identity verification
|
||||
|
||||
Requires: [ERC 735](https://github.com/ethereum/EIPs/issues/735)
|
||||
|
||||
##### The following changes to [ERC 735](https://github.com/ethereum/EIPs/issues/735) are REQUIRED:
|
||||
|
||||
#### addClaim
|
||||
|
||||
This SHOULD create a pending claim, which SHOULD be approved or rejected by `n` of `m` `approve` calls from keys of purpose `1`.
|
||||
|
||||
Only Events:
|
||||
**Triggers if the claim is new Event and approval process exists:** [ClaimRequested](#claimrequested)
|
||||
**Triggers if the claim index existed Event:** [ClaimChanged](https://github.com/ethereum/EIPs/issues/735)
|
||||
|
||||
|
||||
#### removeClaim
|
||||
|
||||
MUST only be done by the `issuer` of the claim, or keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval.
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
Others may be added in the future. Inspired by [ERC1077](https://eips.ethereum.org/EIPS/eip-1077) and [Gnosis](https://github.com/gnosis/safe-contracts/blob/master/contracts/Enum.sol#L7)
|
||||
|
||||
### Events
|
||||
|
||||
|
||||
#### KeyAdded
|
||||
#### DataChanged
|
||||
|
||||
MUST be triggered when `addKey` was successfully called.
|
||||
MUST be triggered when `setData` was successfully called.
|
||||
|
||||
``` js
|
||||
event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType)
|
||||
```js
|
||||
event DataChanged(bytes32 indexed key, bytes value);
|
||||
```
|
||||
|
||||
#### ContractCreated
|
||||
|
||||
MUST be triggered when `execute` creates a new contract using the `_operationType` `1`.
|
||||
|
||||
```js
|
||||
event ContractCreated(address indexed contractAddress);
|
||||
```
|
||||
|
||||
#### OwnerChanged
|
||||
|
||||
MUST be triggered when `changeOwner` was successfully called.
|
||||
|
||||
```js
|
||||
event OwnerChanged(address indexed ownerAddress);
|
||||
```
|
||||
|
||||
|
||||
#### KeyRemoved
|
||||
### Ownership
|
||||
|
||||
MUST be triggered when `removeKey` was successfully called.
|
||||
This contract is controlled by the owner. The owner can be a smart contract or an address, or itself.
|
||||
|
||||
``` js
|
||||
event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType)
|
||||
```
|
||||
### Data keys
|
||||
|
||||
Data keys, should be the keccak256 hash of a type name.
|
||||
e.g. `myNewKeyType` is `0xa94996022594f93c34a730df0ae89d1ecd69dff98c17d0387e69ce58346323a4`
|
||||
|
||||
#### Multiple keys of the same type
|
||||
|
||||
#### ExecutionRequested
|
||||
Multiple keys for the same key type must add a `keyTypeName-1` at the end of the key type.
|
||||
|
||||
MUST be triggered when `execute` was successfully called.
|
||||
|
||||
``` js
|
||||
event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)
|
||||
```
|
||||
|
||||
|
||||
#### Executed
|
||||
|
||||
MUST be triggered when `approve` was called and the execution was successfully approved.
|
||||
|
||||
``` js
|
||||
event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)
|
||||
```
|
||||
|
||||
|
||||
#### Approved
|
||||
|
||||
MUST be triggered when `approve` was successfully called.
|
||||
|
||||
``` js
|
||||
event Approved(uint256 indexed executionId, bool approved)
|
||||
```
|
||||
|
||||
##### The following changes to [ERC 735](https://github.com/ethereum/EIPs/issues/735) are REQUIRED:
|
||||
|
||||
#### ClaimRequested
|
||||
|
||||
MUST be triggered when `addClaim` was successfully called.
|
||||
|
||||
|
||||
#### ClaimAdded
|
||||
|
||||
MUST be triggered when `approve` was called and the claim was successfully added.
|
||||
|
||||
|
||||
## Constraints
|
||||
|
||||
- A claim can only be one type per type per issuer.
|
||||
This would looks as follows for `myNewKeyType`:
|
||||
version 0 `myNewKeyType`: `0xa94996022594f93c34a730df0ae89d1ecd69dff98c17d0387e69ce58346323a4`
|
||||
version 1 `myNewKeyType-1`: `0xb6dace1ed14874742c4d1b8cd9b270305176f769e0ae22118a02c2db4e620f29`
|
||||
version 2 `myNewKeyType-2`: `0x6cc96a01de588f4550e8c3a821aed065ae7897f8dfb61836c78c0389e499d9ed`
|
||||
...
|
||||
|
||||
Anyone that would like to standardize a new data key should make a pull request to update the table below.
|
||||
|
||||
| Name | Description | Key | value |
|
||||
| --- | --- | --- | --- |
|
||||
| owner | The owner of the proxy account | 0x0000000000000000000000000000000000000000000000000000000000000000 | left padded owner address, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` |
|
||||
| 735 | The proxy accounts claim holder contract (per [ERC735](https://github.com/ethereum/EIPs/issues/735)) | 0xb0f23aea7d77ce19f9393243a7b50a3bcaac893c7d68a5a309dea7cacf035fd0 | left padded address of the claim holder contract, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` |
|
||||
| 780 | The proxy accounts claim holder contract (per [ERC735](https://github.com/ethereum/EIPs/issues/735)) | 0xdaf52dba5981246bcf8fd7c6b00dce587fdcf5e2a95b281eea95dcd1376afdcd | left padded address of the claim registry contract, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` |
|
||||
|
||||
## Rationale
|
||||
This specification was chosen to allow most flexibility and experimentation around identity. By having each identity in a separate contract it allows for cross identity compatibility, but at the same time extra and altered functionality for new use cases.
|
||||
|
||||
The main critic of this standard is the verification where each identity that issues a claim, also should have a separate CLAIM signing key attached. While [#ERC780](https://github.com/ethereum/EIPs/issues/780) uses a standardized registry to assign claims to addresses.
|
||||
Both systems could work in conjunction and should be explored.
|
||||
While also off-chain claims using DID verifiable claims and merkle tries can be added as claims and should be explored.
|
||||
The purpose of an identity proxy is to allow an entity to exist as a first-class citizen in Ethereum, with the ability to execute arbitrary contract calls. At that same time the proxy account should be managed by an arbitrary simple or complex logic.
|
||||
|
||||
The rationale of this standard is to function as an open and very flexible container for identity.
|
||||
It also opens up the possibility of [meta transactions](https://medium.com/@austin_48503/ethereum-meta-transactions-90ccf0859e84), where a third party can send a transaction to the owner contract, that then verifies the execution permission based on a signed message.
|
||||
|
||||
It further allows any information to be attached to that proxy accounts which can be in the forms of claims via [ERC735](https://github.com/ethereum/EIPs/issues/735) or [ERC780](https://github.com/ethereum/EIPs/issues/780), or any arbitrary new systems and protocols.
|
||||
|
||||
This specification was chosen to allow the most flexibility and experimentation around verifiable manageable accounts.
|
||||
|
||||
|
||||
## Implementation
|
||||
|
||||
- [DID resolver specification](https://github.com/WebOfTrustInfo/rebooting-the-web-of-trust-spring2018/blob/master/topics-and-advance-readings/DID-Method-erc725.md)
|
||||
- [Implementation by mirceapasoi](https://github.com/mirceapasoi/erc725-735)
|
||||
- [Implementation by Nick Poulden](https://github.com/OriginProtocol/identity-playground), interface at: https://erc725.originprotocol.com/
|
||||
- [Implementation by ERC725Alliance](https://github.com/ERC725Alliance/erc725/tree/master/contracts/contracts)
|
||||
|
||||
|
||||
### Solidity Interface
|
||||
```js
|
||||
pragma solidity ^0.4.18;
|
||||
pragma solidity ^0.5.4;
|
||||
|
||||
contract ERC725 {
|
||||
interface ERC725 {
|
||||
event DataChanged(bytes32 indexed key, bytes32 indexed value);
|
||||
event OwnerChanged(address indexed ownerAddress);
|
||||
event ContractCreated(address indexed contractAddress);
|
||||
|
||||
uint256 constant MANAGEMENT_KEY = 1;
|
||||
uint256 constant ACTION_KEY = 2;
|
||||
uint256 constant CLAIM_SIGNER_KEY = 3;
|
||||
uint256 constant ENCRYPTION_KEY = 4;
|
||||
// address public owner;
|
||||
|
||||
event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
|
||||
event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
|
||||
event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
|
||||
event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
|
||||
event Approved(uint256 indexed executionId, bool approved);
|
||||
|
||||
struct Key {
|
||||
uint256 purpose; //e.g., MANAGEMENT_KEY = 1, ACTION_KEY = 2, etc.
|
||||
uint256 keyType; // e.g. 1 = ECDSA, 2 = RSA, etc.
|
||||
bytes32 key;
|
||||
}
|
||||
|
||||
function getKey(bytes32 _key) public constant returns(uint256 purpose, uint256 keyType, bytes32 key);
|
||||
function keyHasPurpose(bytes32 _key, uint256 _purpose) public constant returns (bool exists);
|
||||
function getKeysByPurpose(uint256 _purpose) public constant returns (bytes32[] keys);
|
||||
function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) public returns (bool success);
|
||||
function removeKey(bytes32 _key, uint256 _purpose) public returns (bool success);
|
||||
function execute(address _to, uint256 _value, bytes _data) public returns (uint256 executionId);
|
||||
function approve(uint256 _id, bool _approve) public returns (bool success);
|
||||
function changeOwner(address _owner) external;
|
||||
function getData(bytes32 _key) external view returns (bytes32 _value);
|
||||
function setData(bytes32 _key, bytes32 _value) external;
|
||||
function execute(uint256 _operationType, address _to, uint256 _value, bytes calldata _data) external;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -294,9 +169,9 @@ contract ERC725 {
|
|||
|
||||
- [Slides of the ERC Identity presentation](https://www.slideshare.net/FabianVogelsteller/erc-725-identity)
|
||||
- [In-contract claim VS claim registry](https://github.com/ethereum/wiki/wiki/ERC-735:-Claim-Holder-Registry-vs.-in-contract)
|
||||
- [Identity related reports](http://www.weboftrust.info/specs.html)
|
||||
- [Identity related reports](https://www.weboftrust.info/specs.html)
|
||||
- [W3C Verifiable Claims Use Cases](https://w3c.github.io/vc-use-cases/)
|
||||
- [Decentralised Identity Foundation](http://identity.foundation)
|
||||
- [Decentralised Identity Foundation](https://identity.foundation)
|
||||
- [Sovrin Foundation Self Sovereign Identity](https://sovrin.org/wp-content/uploads/2017/06/The-Inevitable-Rise-of-Self-Sovereign-Identity.pdf)
|
||||
|
||||
## Copyright
|
||||
|
|
740
EIPS/eip-777.md
740
EIPS/eip-777.md
File diff suppressed because it is too large
Load Diff
|
@ -5,6 +5,7 @@ author: Casey Detrio
|
|||
type: Meta
|
||||
status: Final
|
||||
created: 2017-11-26
|
||||
requires: 606
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
|
|
@ -85,7 +85,7 @@ The proposed changes address forward compatibility by applying Postel's Law (als
|
|||
the Robustness Principle) throughout the protocol stack. The merit and applicability of
|
||||
this approach has been studied repeatedly since its original application in RFC 761. For a
|
||||
recent perspective, see
|
||||
["The Robustness Principle Reconsidered" (Eric Allman, 2011)](http://queue.acm.org/detail.cfm?id=1999945).
|
||||
["The Robustness Principle Reconsidered" (Eric Allman, 2011)](https://queue.acm.org/detail.cfm?id=1999945).
|
||||
|
||||
#### Changes to the devp2p Wire Protocol
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -10,7 +10,7 @@ created: 2018-02-14
|
|||
|
||||
# Delaware General Corporations Law (DGCL) compatible share token
|
||||
|
||||
Ref: [proposing-an-eip-for-DGCL-tokens](http://forum.ethereum.org/discussion/17200/proposing-an-eip-for-regulation-a-Tokens)
|
||||
Ref: [proposing-an-eip-for-DGCL-tokens](https://forum.ethereum.org/discussion/17200/proposing-an-eip-for-regulation-a-Tokens)
|
||||
|
||||
## Simple Summary
|
||||
|
||||
|
@ -49,7 +49,7 @@ The recently amended 'Title 8 of the Delaware Code Relating to the General Corpo
|
|||
|
||||
By using a `DGCL` compatible token, a firm may be able to raise funds via IPO, conforming to Delaware Corporations Law, but bypassing the need for involvement of a traditional Stock Exchange.
|
||||
|
||||
The are currently no token standards that conform to the `DGCL` rules. `ERC-20` tokens do not support KYC/AML rules required by the General Corporation Law, and do not provide facilities for the exporting of lists of shareholders.
|
||||
There are currently no token standards that conform to the `DGCL` rules. `ERC-20` tokens do not support KYC/AML rules required by the General Corporation Law, and do not provide facilities for the exporting of lists of shareholders.
|
||||
|
||||
### What about ERC-721?
|
||||
|
||||
|
|
147
EIPS/eip-902.md
147
EIPS/eip-902.md
|
@ -1,56 +1,51 @@
|
|||
---
|
||||
eip: 902
|
||||
title: Token Validation
|
||||
author: Brooklyn Zelenka <brooklyn@finhaven.com>, Tom Carchrae <tom@finhaven.com>, Gleb Naumenko <gleb@finhaven.com>
|
||||
author: Brooklyn Zelenka (@expede), Tom Carchrae (@carchrae), Gleb Naumenko (@naumenkogs)
|
||||
discussions-to: https://ethereum-magicians.org/t/update-on-erc902-validated-token/1639
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
status: Draft
|
||||
created: 2018-02-14
|
||||
requires: 1066
|
||||
---
|
||||
|
||||
## Simple Summary
|
||||
# Simple Summary
|
||||
A protocol for services providing token ownership and transfer validation.
|
||||
|
||||
## Abstract
|
||||
This standard provides a registry contract method for authorizing token transfers.
|
||||
By nature, this covers both initially issuing tokens to users (ie: transfer from contract to owner),
|
||||
transferring tokens between users, and token spends.
|
||||
# Abstract
|
||||
This standard provides a registry contract method for authorizing token transfers. By nature, this covers both initially issuing tokens to users (ie: transfer from contract to owner), transferring tokens between users, and token spends.
|
||||
|
||||
## Motivation
|
||||
The tokenization of assets has wide application,
|
||||
not least of which is financial instruments such as securities.
|
||||
Most jurisdictions have placed legal constraints on what may be traded,
|
||||
and who can hold such tokens which are regarded as securities. Broadly this includes KYC and AML validation,
|
||||
but may also include time-based spend limits, total volume of transactions, and so on.
|
||||
# Motivation
|
||||
The tokenization of assets has wide application, not least of which is financial instruments such as securities and security tokens. Most jurisdictions have placed legal constraints on what may be traded, and who can hold such tokens which are regarded as securities. Broadly this includes KYC and AML validation, but may also include time-based spend limits, total volume of transactions, and so on.
|
||||
|
||||
Regulators and sanctioned third-party compliance agencies need some way to link
|
||||
off-chain compliance information such as identity and residency to an on-chain service.
|
||||
The application of this design is broader than legal regulation, encompassing all manner
|
||||
of business logic permissions for the creation, management, and trading of tokens.
|
||||
Regulators and sanctioned third-party compliance agencies need some way to link off-chain compliance information such as identity and residency to an on-chain service. The application of this design is broader than legal regulation, encompassing all manner of business logic permissions for the creation, management, and trading of tokens.
|
||||
|
||||
## Specification
|
||||
Rather than each token maintaining its own whitelist (or other mechanism), it is preferable to share on-chain resources, rules, lists, and so on. There is also a desire to aggregate data and rules spread across multiple validators, or to apply complex behaviours (ex. switching logic, gates, state machines) to apply distributed data to an application.
|
||||
|
||||
### TokenValidator
|
||||
# Specification
|
||||
|
||||
## `TokenValidator`
|
||||
|
||||
```solidity
|
||||
interface TokenValidator {
|
||||
function check(
|
||||
address _token,
|
||||
address _subject
|
||||
) public returns(byte result)
|
||||
function check(
|
||||
address _token,
|
||||
address _subject
|
||||
) public returns(byte statusCode)
|
||||
|
||||
function check(
|
||||
address _token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount
|
||||
) public returns (byte result)
|
||||
function check(
|
||||
address _token,
|
||||
address _from,
|
||||
address _to,
|
||||
uint256 _amount
|
||||
) public returns (byte statusCode)
|
||||
}
|
||||
```
|
||||
|
||||
#### Methods
|
||||
### Methods
|
||||
|
||||
##### check/2
|
||||
#### `check`/2
|
||||
|
||||
`function check(address _token, address _subject) public returns (byte _resultCode)`
|
||||
|
||||
|
@ -58,9 +53,9 @@ interface TokenValidator {
|
|||
> * `_token`: the token under review
|
||||
> * `_subject`: the user or contract to check
|
||||
>
|
||||
> *returns* a one-byte status code, often encoded as hex
|
||||
> *returns* an ERC1066 status code
|
||||
|
||||
##### check/4
|
||||
#### `check`/4
|
||||
|
||||
`function check(address token, address from, address to, uint256 amount) public returns (byte resultCode)`
|
||||
|
||||
|
@ -70,29 +65,29 @@ interface TokenValidator {
|
|||
> * `_to`: in the case of a transfer, who is accepting token ownership
|
||||
> * `_amount`: The number of tokens being transferred
|
||||
>
|
||||
> *returns* a one-byte status code, often encoded as hex
|
||||
> *returns* an ERC1066 status code
|
||||
|
||||
### ValidatedToken
|
||||
## `ValidatedToken`
|
||||
|
||||
```solidity
|
||||
interface ValidatedToken {
|
||||
event Validation(
|
||||
address indexed subject,
|
||||
byte indexed result
|
||||
)
|
||||
event Validation(
|
||||
address indexed subject,
|
||||
byte indexed result
|
||||
)
|
||||
|
||||
event Validation(
|
||||
address indexed from,
|
||||
address indexed to,
|
||||
uint256 value,
|
||||
byte indexed result
|
||||
)
|
||||
event Validation(
|
||||
address indexed from,
|
||||
address indexed to,
|
||||
uint256 value,
|
||||
byte indexed statusCode
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Events
|
||||
### Events
|
||||
|
||||
##### Validation/2
|
||||
#### `Validation`/2
|
||||
|
||||
`event Validation(address indexed subject, byte indexed resultCode)`
|
||||
|
||||
|
@ -100,17 +95,17 @@ This event MUST be fired on return from a call to a `TokenValidator.check/2`.
|
|||
|
||||
> parameters
|
||||
> * `subject`: the user or contract that was checked
|
||||
> * `resultCode`: a status code
|
||||
> * `statusCode`: an ERC1066 status code
|
||||
|
||||
|
||||
##### Validation/4
|
||||
#### `Validation`/4
|
||||
|
||||
```solidity
|
||||
event Validation(
|
||||
address indexed from,
|
||||
address indexed to,
|
||||
uint256 amount,
|
||||
byte indexed result
|
||||
address indexed from,
|
||||
address indexed to,
|
||||
uint256 amount,
|
||||
byte indexed statusCode
|
||||
)
|
||||
```
|
||||
|
||||
|
@ -120,26 +115,16 @@ This event MUST be fired on return from a call to a `TokenValidator.check/4`.
|
|||
> * `from`: in the case of a transfer, who is relinquishing token ownership
|
||||
> * `to`: in the case of a transfer, who is accepting token ownership
|
||||
> * `amount`: The number of tokens being transferred
|
||||
> * `resultCode`: a status code
|
||||
> * `statusCode`: an ERC1066 status code
|
||||
|
||||
## Rationale
|
||||
# Rationale
|
||||
|
||||
This proposal includes a financial permissions system on top of any financial token.
|
||||
This design is not a general roles/permission system. In any system, the more you know
|
||||
about the context where a function will be called, the more powerful your function can be.
|
||||
By restricting ourselves to token transfers (ex. ERC20 or EIP-777), we can make
|
||||
assumptions about the use cases our validators will need to handle, and can make
|
||||
the API both small, useful, and extensible.
|
||||
This proposal includes a financial permissions system on top of any financial token. This design is not a general roles/permission system. In any system, the more you know about the context where a function will be called, the more powerful your function can be. By restricting ourselves to token transfers (ex. ERC20 or EIP-777), we can make assumptions about the use cases our validators will need to handle, and can make the API both small, useful, and extensible.
|
||||
|
||||
The events are fired by the calling token. Since `Validator`s may aggregate or delegate
|
||||
to other `Validator`s, it would generate a lot of useless events were it the
|
||||
`Validator`'s responsibility. This is also the reason why we include the `token`
|
||||
in the `call/4` arguments: a `Validator` cannot rely on `msg.sender` to determine
|
||||
the token that the call is concerning.
|
||||
The events are fired by the calling token. Since `Validator`s may aggregate or delegate to other `Validator`s, it would generate a lot of useless events were it the
|
||||
`Validator`'s responsibility. This is also the reason why we include the `token` in the `call/4` arguments: a `Validator` cannot rely on `msg.sender` to determine the token that the call is concerning.
|
||||
|
||||
We have also seen a similar design from [R-Token](https://github.com/harborhq/r-token) that uses an additional field: `spender`.
|
||||
While there are potential use cases for this, it's not widely used enough to justify passing
|
||||
a dummy value along with every call. Instead, such a call would look more like this:
|
||||
We have also seen a similar design from [R-Token](https://github.com/harborhq/r-token) that uses an additional field: `spender`. While there are potential use cases for this, it's not widely used enough to justify passing a dummy value along with every call. Instead, such a call would look more like this:
|
||||
|
||||
```solidity
|
||||
function approve(address spender, uint amount) public returns (bool success) {
|
||||
|
@ -153,28 +138,16 @@ function approve(address spender, uint amount) public returns (bool success) {
|
|||
}
|
||||
```
|
||||
|
||||
A second `check/2` function is also required, that is more general-purpose, and does not
|
||||
specify a transfer amount or recipient. This is intended for general checks,
|
||||
such as checking roles (admin, owner, &c), or if a user is on a simple whitelist.
|
||||
A second `check/2` function is also required, that is more general-purpose, and does not specify a transfer amount or recipient. This is intended for general checks, such as checking roles (admin, owner, &c), or if a user is on a simple whitelist.
|
||||
|
||||
We have left the decision to make associated `Validator` addresses public, private, or hardcoded
|
||||
up to the implementer. The proposed design does not include a centralized registry.
|
||||
It also does not include an interface for a `Validated` contract.
|
||||
A token may require one or many `Validator`s for different purposes,
|
||||
requiring different validations for different, or just a single `Validator`.
|
||||
The potential use cases are too varied to provide a single unified set of methods.
|
||||
We have provided a set of example contracts [here](https://github.com/Finhaven/ValidatedToken/)
|
||||
that may be inherited from for common use cases.
|
||||
We have left the decision to make associated `Validator` addresses public, private, or hardcoded up to the implementer. The proposed design does not include a centralized registry. It also does not include an interface for a `Validated` contract. A token may require one or many `Validator`s for different purposes, requiring different validations for different, or just a single `Validator`. The potential use cases are too varied to provide a single unified set of methods. We have provided a set of example contracts [here](https://github.com/Finhaven/ValidatedToken/) that may be inherited from for common use cases.
|
||||
|
||||
The status codes in the `byte` returns are unspecified. Any status code scheme
|
||||
may be used, though a general status code proposal is fortcoming.
|
||||
The status codes in the `byte` returns are unspecified. Any status code scheme may be used, though a general status code proposal is fortcoming.
|
||||
|
||||
By only defining the validation check, this standard is widely compatible with
|
||||
ERC-20, EIP-721, EIP-777, future token standards, centralized and decentralized exchanges,
|
||||
and so on.
|
||||
By only defining the validation check, this standard is widely compatible with ERC-20, EIP-721, EIP-777, future token standards, centralized and decentralized exchanges, and so on.
|
||||
|
||||
## Implementation
|
||||
[Reference implementations](https://github.com/Finhaven/ValidatedToken/)
|
||||
# Implementation
|
||||
[Reference implementation](https://github.com/expede/validated-token/)
|
||||
|
||||
## Copyright
|
||||
# Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
|
|
@ -22,7 +22,7 @@ The tragedy of the commons is a phenomenon that is well known in many sectors, m
|
|||
Reward mechanisms that are external to being built in to the protocol are beyond the scope of this EIP. Such extra-protocol reward methods include state channel payments for extra services such as light client servers providing faster information such as receipts; state channel payments for buying state reads from full nodes; archival services (which is only applicable to future proposed versions of Ethereum with stateless clients); and tokens for the client and running full nodes.
|
||||
|
||||
## Motivation
|
||||
Currently there is a lack of incentives for anyone to run a full node, while joining a mining pool is not really economical if one has to purchase a mining rig (several GPUs) now, since there is unlikely to be a return on investment by the time that Ethereum transitions to hybrid Proof-of-Work/Proof-of-Stake with [Casper FFG](http://eips.ethereum.org/EIPS/eip-1011), then full PoS with [CBC Casper](https://github.com/ethereum/research/blob/master/papers/CasperTFG/CasperTFG.pdf).
|
||||
Currently there is a lack of incentives for anyone to run a full node, while joining a mining pool is not really economical if one has to purchase a mining rig (several GPUs) now, since there is unlikely to be a return on investment by the time that Ethereum transitions to hybrid Proof-of-Work/Proof-of-Stake with [Casper FFG](https://eips.ethereum.org/EIPS/eip-1011), then full PoS with [CBC Casper](https://github.com/ethereum/research/blob/master/papers/CasperTFG/CasperTFG.pdf).
|
||||
|
||||
Additionally, providing a reward for clients gives a revenue stream that is independent of state channels or other layer 2 mechanisms, which are less secure, although this insecurity can be offset by mechanisms such as insurance, bonded payments and time locks. Rationalising that investors may invest in a client because it is an enabler for the Ethereum ecosystem (and thus opening up investment opportunities) may not scale very well, and it seems that it is more sustainable to monetize the client as part of the service(s) that it provides.
|
||||
|
||||
|
@ -40,7 +40,7 @@ Implementing this as a layer 2 solution may not ensure the sustainability of the
|
|||
|
||||
Not providing incentives for clients is an issue now as there is less incentive to build a client that aligns with the needs of users, funds need to be raised externally to the protocol to fund client development, which is not as decentralized. If only a smaller subset is able to fund client development, such as VCs, angel investors and institutional investors, that may not align well with the interests of all current and potential stakeholders of Ethereum (which includes future stakeholders). Ostensibly, one of the goals of Ethereum is to decentralize everything, including wealth, or in other words, to improve wealth equality. Not providing incentives for full nodes validating transactions may not seem like as much of an issue now, but not doing so could hinder the growth of the protocol. Of course, incentives aren't enough, it also needs to be technically decentralized so that it is ideally possible for a low-end mainstream computer or perhaps even a mobile or embedded IoT device to be a verifying full node, or at least to be able to help with securing the network if it is deemed impractical for them to be a full node.
|
||||
|
||||
Note that with a supply cap (as in [EIP 960](https://github.com/ethereum/EIPs/issues/960), the issuance can be prevented from increasing indefinitely. Alternatively, it could at least be reduced (still potentially but not necessarily to zero, or to the same rate at which Ether is burnt when slashing participants, such as validators under a Casper PoS scheme or notaries under a sharding scheme), e.g. by hard forks, or as per [EIP 1015](http://eips.ethereum.org/EIPS/eip-1015), an on-chain contract governed by a decision assembly that gets signalling from other contracts that represent some set of stakeholders.
|
||||
Note that with a supply cap (as in [EIP 960](https://github.com/ethereum/EIPs/issues/960), the issuance can be prevented from increasing indefinitely. Alternatively, it could at least be reduced (still potentially but not necessarily to zero, or to the same rate at which Ether is burnt when slashing participants, such as validators under a Casper PoS scheme or notaries under a sharding scheme), e.g. by hard forks, or as per [EIP 1015](https://eips.ethereum.org/EIPS/eip-1015), an on-chain contract governed by a decision assembly that gets signalling from other contracts that represent some set of stakeholders.
|
||||
|
||||
## Specification
|
||||
Add a new field to each block called `PrevBlockVerifications`, which is an arbitrary, unlimited size byte array. When a client verifies that a previous block is [valid](https://ethereum.github.io/yellowpaper/paper.pdf#subsubsection.4.3.2), the client appends a user agent to PrevBlockVerifications via an opcode in a transaction, PREV_BLOCK_VERIF. The user agent is a vector with the immutable fields: the blockhash of the block that is validated, and the index of a client address in an access list (details are below). A miner validates a transaction before including it in a block, however they are not able to change these fields of the vector because they're immutable.
|
||||
|
@ -55,9 +55,9 @@ A miner could create a client and fill their block with transactions that only c
|
|||
|
||||
### More details on the access list
|
||||
|
||||
The access list prevents anyone inserting any address to the first element of the vector, where there may be a way to prevent censorship and centralization of authority of who decides to register new addresses in the list, e.g. on-chain governance with signalling (possibly similar to [EIP 1015](http://eips.ethereum.org/EIPS/eip-1015), which also specifies an alternative way of sending funds) or a layer 2 proof of authority network where new addresses can be added via a smart contract. Note that there may be serious drawbacks to implementing either of these listed examples. There is a refutation of [on-chain governance](https://medium.com/@Vlad_Zamfir/against-on-chain-governance-a4ceacd040ca) as well as of [plutocracy](https://vitalik.ca/general/2018/03/28/plutocracy.html). [Proof of Authority](https://en.wikipedia.org/wiki/Proof-of-authority) isn't suitable for a public network since it doesn't distribute trust well. However, using signalling in layer 2 contracts is more acceptable, but Vlad Zamfir argues that using that to influence outcomes in the protocol can disenfranchise miners from being necessary participants in the governance process. Thus, in light of these counterpoints, having an access list may not be suitable until a decentralized, trustless way of maintaining it is implemented and ideally accepted by the majority of a random sample that represents the population of Ethereum users.
|
||||
The access list prevents anyone inserting any address to the first element of the vector, where there may be a way to prevent censorship and centralization of authority of who decides to register new addresses in the list, e.g. on-chain governance with signalling (possibly similar to [EIP 1015](https://eips.ethereum.org/EIPS/eip-1015), which also specifies an alternative way of sending funds) or a layer 2 proof of authority network where new addresses can be added via a smart contract. Note that there may be serious drawbacks to implementing either of these listed examples. There is a refutation of [on-chain governance](https://medium.com/@Vlad_Zamfir/against-on-chain-governance-a4ceacd040ca) as well as of [plutocracy](https://vitalik.ca/general/2018/03/28/plutocracy.html). [Proof of Authority](https://en.wikipedia.org/wiki/Proof-of-authority) isn't suitable for a public network since it doesn't distribute trust well. However, using signalling in layer 2 contracts is more acceptable, but Vlad Zamfir argues that using that to influence outcomes in the protocol can disenfranchise miners from being necessary participants in the governance process. Thus, in light of these counterpoints, having an access list may not be suitable until a decentralized, trustless way of maintaining it is implemented and ideally accepted by the majority of a random sample that represents the population of Ethereum users.
|
||||
|
||||
However, another alternative to managing the access list would be to have decentralized verification that the address produced from querying an index in the access list does correspond to that of a "legitimate" client. Part of this verification would involve checking that there is a client that claims that this address is owned by them, that they are happy to receive funds in this manner and agree or arranged to putting the address in the access list, and that the client passes all tests in the [Ethereum test suite](https://github.com/ethereum/tests). However, this last proviso would then preclude new clients being funded from the start of development, although such would-be clients would not be able to receive funds in-protocol until they implement the client anyway (as an aside, they could raise funds in various ways—a DAII, pronounced die-yee, is recommended, while a platform for DAIIs is under development by [Dogezer](http://dogezer.com/)). All of this could be done off-chain, and if anyone found that some address in the access list was not legitimate, then they could challenge that address with a proof of illegitimacy, and the participant that submitted the address to the access list could be slashed (while they must hold a deposit in order to register and keep an address in the access list).
|
||||
However, another alternative to managing the access list would be to have decentralized verification that the address produced from querying an index in the access list does correspond to that of a "legitimate" client. Part of this verification would involve checking that there is a client that claims that this address is owned by them, that they are happy to receive funds in this manner and agree or arranged to putting the address in the access list, and that the client passes all tests in the [Ethereum test suite](https://github.com/ethereum/tests). However, this last proviso would then preclude new clients being funded from the start of development, although such would-be clients would not be able to receive funds in-protocol until they implement the client anyway (as an aside, they could raise funds in various ways—a DAII, pronounced die-yee, is recommended, while a platform for DAIIs is under development by [Dogezer](https://dogezer.com/)). All of this could be done off-chain, and if anyone found that some address in the access list was not legitimate, then they could challenge that address with a proof of illegitimacy, and the participant that submitted the address to the access list could be slashed (while they must hold a deposit in order to register and keep an address in the access list).
|
||||
|
||||
Additionally, it should help with being only able to read the client's address from the client, and the whole transaction could revert if the address is not in the access list. You could provide the index of the address in the access list, and then you could `assert` that the address found at that index matches that which can be read by the client (where the latter would be a read-only address).
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ type: Standards Track
|
|||
category: ERC
|
||||
status: Draft
|
||||
created: 2018-03-12
|
||||
dependencies: 165
|
||||
requires: 165
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
|
|
@ -6,7 +6,7 @@ type: Standards Track
|
|||
category: ERC
|
||||
status: Draft
|
||||
created: 2018-03-12
|
||||
dependencies: 926
|
||||
requires: 926
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
|
|
@ -159,7 +159,7 @@ An analysis can be done regarding the dispersion of these constants as compared
|
|||
`0x01000193`, using the following snippet.
|
||||
|
||||
``` c
|
||||
// http://eips.ethereum.org/EIPS/eip-969
|
||||
// https://eips.ethereum.org/EIPS/eip-969
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -3,10 +3,10 @@ ATTENTION! If you would like to submit an EIP and it has already been written as
|
|||
|
||||
If you are considering a proposal but would like to get some feedback on the idea before submitting a draft, then continue opening an Issue as a thread for discussion. Note that the more clearly and completely you state your idea the higher the quality of the feedback you are likely to receive.
|
||||
|
||||
Keep in mind the following guidelines from [EIP-1](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1.md):
|
||||
Keep in mind the following guidelines from [EIP-1](https://eips.ethereum.org/EIPS/eip-1):
|
||||
|
||||
> Each EIP must have a champion - someone who writes the EIP using the style and format described below, shepherds the discussions in the appropriate forums, and attempts to build community consensus around the idea. The EIP champion (a.k.a. Author) should first attempt to ascertain whether the idea is EIP-able. Posting to the the Protocol Discussion forum or opening an Issue is the best way to go about this.
|
||||
|
||||
> Vetting an idea publicly before going as far as writing a EIP is meant to save the potential author time. Asking the Ethereum community first if an idea is original helps prevent too much time being spent on something that is guaranteed to be rejected based on prior discussions (searching the Internet does not always do the trick). It also helps to make sure the idea is applicable to the entire community and not just the author. Just because an idea sounds good to the author does not mean it will work for most people in most areas where Ethereum is used.
|
||||
|
||||
> Once the champion has asked the Ethereum community as to whether an idea has any chance of acceptance, a draft EIP should be presented as a Pull Request. This gives the author a chance to flesh out the draft EIP to make properly formatted, of high quality, and to address initial concerns about the proposal.
|
||||
> Once the champion has asked the Ethereum community as to whether an idea has any chance of acceptance, a draft EIP should be presented as a Pull Request. This gives the author a chance to flesh out the draft EIP to make properly formatted, of high quality, and to address initial concerns about the proposal.
|
||||
|
|
10
README.md
10
README.md
|
@ -1,7 +1,7 @@
|
|||
# EIPs [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/EIPs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
Ethereum Improvement Proposals (EIPs) describe standards for the Ethereum platform, including core protocol specifications, client APIs, and contract standards.
|
||||
|
||||
A browsable version of all current and draft EIPs can be found on [the official EIP site](http://eips.ethereum.org/).
|
||||
A browsable version of all current and draft EIPs can be found on [the official EIP site](https://eips.ethereum.org/).
|
||||
|
||||
# Contributing
|
||||
|
||||
|
@ -22,11 +22,11 @@ When you believe your EIP is mature and ready to progress past the draft phase,
|
|||
- **For all other EIPs**, open a PR changing the state of your EIP to 'Final'. An editor will review your draft and ask if anyone objects to its being finalised. If the editor decides there is no rough consensus - for instance, because contributors point out significant issues with the EIP - they may close the PR and request that you fix the issues in the draft before trying again.
|
||||
|
||||
# EIP Status Terms
|
||||
* **Draft** - an EIP that is undergoing rapid iteration and changes
|
||||
* **Last Call** - an EIP that is done with its initial iteration and ready for review by a wide audience
|
||||
* **Accepted** - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author
|
||||
* **Draft** - an EIP that is undergoing rapid iteration and changes.
|
||||
* **Last Call** - an EIP that is done with its initial iteration and ready for review by a wide audience.
|
||||
* **Accepted** - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. The process for Core Devs to decide whether to encode an EIP into their clients as part of a hard fork is not part of the EIP process. If such a decision is made, the EIP wil move to final.
|
||||
* **Final (non-Core)** - an EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author.
|
||||
* **Final (Core)** - an EIP that the Core Devs have decide to implement and release in a future hard fork or has already been released in a hard fork
|
||||
* **Final (Core)** - an EIP that the Core Devs have decided to implement and release in a future hard fork or has already been released in a hard fork.
|
||||
* **Deferred** - an EIP that is not being considered for immediate adoption. May be reconsidered in the future for a subsequent hard fork.
|
||||
|
||||
# Preferred Citation Format
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
{%- if site.linkedin_username -%}<li><a href="https://www.linkedin.com/in/{{ site.linkedin_username| cgi_escape | escape }}"><svg class="svg-icon"><use xlink:href="{{ '/assets/minima-social-icons.svg#linkedin' | relative_url }}"></use></svg> <span class="username">{{ site.linkedin_username| escape }}</span></a></li>{%- endif -%}
|
||||
{%- if site.pinterest_username -%}<li><a href="https://www.pinterest.com/{{ site.pinterest_username| cgi_escape | escape }}"><svg class="svg-icon"><use xlink:href="{{ '/assets/minima-social-icons.svg#pinterest' | relative_url }}"></use></svg> <span class="username">{{ site.pinterest_username| escape }}</span></a></li>{%- endif -%}
|
||||
{%- for mst in site.mastodon -%}{%- if mst.username and mst.instance -%}<li><a href="https://{{ mst.instance| cgi_escape | escape}}/@{{mst.username}}"><svg class="svg-icon"><use xlink:href="{{ '/assets/minima-social-icons.svg#mastodon' | relative_url }}"></use></svg> <span class="username">{{ mst.username|escape }}</span></a></li>{%- endif -%}{%- endfor -%}
|
||||
{%- if site.twitter_username -%}<li><a href="https://www.twitter.com/{{ site.twitter_username| cgi_escape | escape }}"><svg class="svg-icon"><use xlink:href="{{ '/assets/minima-social-icons.svg#twitter' | relative_url }}"></use></svg> <span class="username">{{ site.twitter_username| escape }}</span></a></li>{%- endif -%}
|
||||
{%- if site.twitter_username -%}<li><a href="https://twitter.com/{{ site.twitter_username| cgi_escape | escape }}"><svg class="svg-icon"><use xlink:href="{{ '/assets/minima-social-icons.svg#twitter' | relative_url }}"></use></svg> <span class="username">{{ site.twitter_username| escape }}</span></a></li>{%- endif -%}
|
||||
{%- if site.youtube_username -%}<li><a href="https://youtube.com/{{ site.youtube_username| cgi_escape | escape }}"><svg class="svg-icon"><use xlink:href="{{ '/assets/minima-social-icons.svg#youtube' | relative_url }}"></use></svg> <span class="username">{{ site.youtube_username| escape }}</span></a></li>{%- endif -%}
|
||||
{%- if site.googleplus_username -%}<li><a href="https://plus.google.com/{{ site.googleplus_username| escape }}"><svg class="svg-icon"><use xlink:href="{{ '/assets/minima-social-icons.svg#googleplus' | relative_url }}"></use></svg> <span class="username">{{ site.googleplus_username| escape }}</span></a></li>{%- endif -%}
|
||||
{%- if site.rss -%}<li><a href="{{ 'feed.xml' | relative_url }}"><svg class="svg-icon"><use xlink:href="{{ '/assets/minima-social-icons.svg#rss' | relative_url }}"></use></svg> <span>{{ site.rss | escape }}</span></a></li>{%- endif -%}
|
||||
|
|
|
@ -5,14 +5,18 @@ layout: default
|
|||
<div class="home">
|
||||
<h1 class="page-heading">
|
||||
EIP {{ page.eip | xml_escape }}: {{ page.title | xml_escape }}
|
||||
<a href="{{site.github.repository_url}}/blob/master/{{page.path}}"><svg role="img" aria-label="Source" xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><title>Source</title><path fill-rule="evenodd" d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"/></svg></a>
|
||||
<a href="{{site.github.repository_url}}/blob/master/{{page.path}}"><svg role="img" aria-label="Source" xmlns="https://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><title>Source</title><path fill-rule="evenodd" d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"/></svg></a>
|
||||
</h1>
|
||||
<table>
|
||||
<tr><th>Author</th><td>{% include authorlist.html authors=page.author %}</td></tr>
|
||||
{% if page["discussions-to"] != undefined %}
|
||||
<tr><th>Discussions-To</th><td><a href="{{ page["discussions-to"] | uri_escape }}">{{ page["discussions-to"] | xml_escape }}</a></td></tr>
|
||||
{% endif %}
|
||||
<tr><th>Status</th><td>{{ page.status | xml_escape }}</td></tr>
|
||||
<tr><th>Status</th><td>{{ page.status | xml_escape }}
|
||||
{% if page.review-period-end != undefined %}
|
||||
<strong>(review ends {{ page.review-period-end | xml_escape }})</strong>
|
||||
{% endif %}
|
||||
</td></tr>
|
||||
<tr><th>Type</th><td>{{ page.type | xml_escape }}</td></tr>
|
||||
{% if page.category != undefined %}
|
||||
<tr><th>Category</th><td>{{ page.category | xml_escape }}</td></tr>
|
||||
|
|
|
@ -0,0 +1,457 @@
|
|||
# Test Vectors for EIP-1057 - ProgPow
|
||||
|
||||
Many of these vectors are dervived from [chfast/ethash](https://github.com/chfast/ethash)
|
||||
|
||||
## fnv1a
|
||||
|
||||
| `h` | `d` | _result_ |
|
||||
| -----------: | -----------: | -----------: |
|
||||
| `0X811C9DC5` | `0XDDD0A47B` | `0XD37EE61A` |
|
||||
| `0XD37EE61A` | `0XEE304846` | `0XDEDC7AD4` |
|
||||
| `0XDEDC7AD4` | `0X00000000` | `0XA9155BBC` |
|
||||
|
||||
## kiss99
|
||||
|
||||
For `z`=`362436069`, `w`=`521288629`, `jsr`=`123456789`, and `jcong`=`380116160` the result of each iterative call to `kiss99` is as follows:
|
||||
|
||||
| _iteration_ | _result_ |kernel
|
||||
| ----------: | -----------: |
|
||||
| `1` | `769445856` |
|
||||
| `2` | `742012328` |
|
||||
| `3` | `2121196314` |
|
||||
| `4` | `2805620942` |
|
||||
| `100000` | `941074834` |
|
||||
|
||||
## fill_mix
|
||||
|
||||
For `hash_seed`=`0xEE304846DDD0A47B` and `lane_id`=`0` the values stored in the `mix` array will be
|
||||
|
||||
> ```
|
||||
> 0x10C02F0D, 0x99891C9E, 0xC59649A0, 0x43F0394D,
|
||||
> 0x24D2BAE4, 0xC4E89D4C, 0x398AD25C, 0xF5C0E467,
|
||||
> 0x7A3302D6, 0xE6245C6C, 0x760726D3, 0x1F322EE7,
|
||||
> 0x85405811, 0xC2F1E765, 0xA0EB7045, 0xDA39E821,
|
||||
> 0x79FC6A48, 0x089E401F, 0x8488779F, 0xD79E414F,
|
||||
> 0x041A826B, 0x313C0D79, 0x10125A3C, 0x3F4BDFAC,
|
||||
> 0xA7352F36, 0x7E70CB54, 0x3B0BB37D, 0x74A3E24A,
|
||||
> 0xCC37236A, 0xA442B311, 0x955AB27A, 0x6D175B7E
|
||||
> ```
|
||||
|
||||
For the same hash and `lane_id`=`13` the value in the `mix` array will be
|
||||
|
||||
> ```
|
||||
> 0x4E46D05D, 0x2E77E734, 0x2C479399, 0x70712177,
|
||||
> 0xA75D7FF5, 0xBEF18D17, 0x8D42252E, 0x35B4FA0E,
|
||||
> 0x462C850A, 0x2DD2B5D5, 0x5F32B5EC, 0xED5D9EED,
|
||||
> 0xF9E2685E, 0x1F29DC8E, 0xA78F098B, 0x86A8687B,
|
||||
> 0xEA7A10E7, 0xBE732B9D, 0x4EEBCB60, 0x94DD7D97,
|
||||
> 0x39A425E9, 0xC0E782BF, 0xBA7B870F, 0x4823FF60,
|
||||
> 0xF97A5A1C, 0xB00BCAF4, 0x02D0F8C4, 0x28399214,
|
||||
> 0xB4CCB32D, 0x83A09132, 0x27EA8279, 0x3837DDA3
|
||||
> ```
|
||||
|
||||
## keccak_f800_progpow
|
||||
|
||||
Test case 1:
|
||||
|
||||
| | |
|
||||
| -------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| header | `0xCCDDEEFF`, `0x8899AABB`, `0x44556677`, `0x00112233`,<br>`0x33221100`, `0x77665544`, `0xBBAA9988`, `0xFFEEDDCC` |
|
||||
| seed | `0x123456789ABCDEF0` |
|
||||
| digest | `0x00000000`, `0x00000000`, `0x00000000`, `0x00000000`,<br>`0x00000000`, `0x00000000`, `0x00000000`, `0x00000000` |
|
||||
| _result_ | `0x464830EE`, `0x7BA4D0DD`, `0x969E1798`, `0xCEC50EB6`,<br>`0x7872E2EA`, `0x597E3634`, `0xE380E73D`, `0x2F89D1E6` |
|
||||
|
||||
Test case 2:
|
||||
|
||||
| | |
|
||||
| -------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| header | `0xCCDDEEFF`, `0x8899AABB`, `0x44556677`, `0x00112233`,<br>`0x33221100`, `0x77665544`, `0xBBAA9988`, `0xFFEEDDCC` |
|
||||
| seed | `0xEE304846DDD0A47B` |
|
||||
| digest | `0x0598F111`, `0x66B48AC5`, `0x719CFF10`, `0x5F0ACF9D`,<br>`0x162FFA18`, `0xEF8E7905`, `0x21470C77`, `0x7D767492` |
|
||||
| _result_ | `0x47CD7C5B`, `0xD9FDBE2D`, `0xAC5C895B`, `0xFF67CE8E`,<br>`0x6B5AEB0D`, `0xE1C6ECD2`, `0x003D3862`, `0xCE8E72C3` |
|
||||
|
||||
## progPowInit
|
||||
|
||||
For ProgPow period 600 (block 30,000) the configurations should be
|
||||
|
||||
src array:
|
||||
|
||||
> `0x1A`, `0x1E`, `0x01`, `0x13`, `0x0B`, `0x15`, `0x0F`, `0x12`,
|
||||
> `0x03`, `0x11`, `0x1F`, `0x10`, `0x1C`, `0x04`, `0x16`, `0x17`,
|
||||
> `0x02`, `0x0D`, `0x1D`, `0x18`, `0x0A`, `0x0C`, `0x05`, `0x14`,
|
||||
> `0x07`, `0x08`, `0x0E`, `0x1B`, `0x06`, `0x19`, `0x09`, `0x00`
|
||||
|
||||
dst array
|
||||
|
||||
> `0x00`, `0x04`, `0x1B`, `0x1A`, `0x0D`, `0x0F`, `0x11`, `0x07`,
|
||||
> `0x0E`, `0x08`, `0x09`, `0x0C`, `0x03`, `0x0A`, `0x01`, `0x0B`,
|
||||
> `0x06`, `0x10`, `0x1C`, `0x1F`, `0x02`, `0x13`, `0x1E`, `0x16`,
|
||||
> `0x1D`, `0x05`, `0x18`, `0x12`, `0x19`, `0x17`, `0x15`, `0x14`
|
||||
|
||||
Kiss 99 state:
|
||||
`z`=`0x6535921C` `w`=`0x29345B16`, `jsr`=`0xC0DD7F78`, `jcong`=`0x1165D7EB`
|
||||
|
||||
## merge
|
||||
|
||||
| `a` | `b` | `r` | _result_ | _path exercised_ |
|
||||
| ------------ | ------------ | ------------ | ------------ | ---------------- |
|
||||
| `0x3B0BB37D` | `0xA0212004` | `0x9BD26AB0` | `0x3CA34321` | mul/add |
|
||||
| `0x10C02F0D` | `0x870FA227` | `0xD4F45515` | `0x91C1326A` | xor/mul |
|
||||
| `0x24D2BAE4` | `0x0FFB4C9B` | `0x7FDBC2F2` | `0x2EDDD94C` | rotl/xor |
|
||||
| `0xDA39E821` | `0x089C4008` | `0x8B6CD8C3` | `0x8A81E396` | rotr/xor |
|
||||
|
||||
## math
|
||||
|
||||
| `a` | `b` | `r` | _result_ | _operation exercised_ |
|
||||
| ------------ | ------------ | ------------ | ------------ | ----------------------- |
|
||||
| `0x8626BB1F` | `0xBBDFBC4E` | `0x883E5B49` | `0x4206776D` | add |
|
||||
| `0x3F4BDFAC` | `0xD79E414F` | `0x36B71236` | `0x4C5CB214` | mul |
|
||||
| `0x6D175B7E` | `0xC4E89D4C` | `0x944ECABB` | `0x53E9023F` | mul_hi32 |
|
||||
| `0x2EDDD94C` | `0x7E70CB54` | `0x3F472A85` | `0x2EDDD94C` | min |
|
||||
| `0x61AE0E62` | `0xe0596b32` | `0x3F472A85` | `0x61AE0E62` | min again (unsigned) |
|
||||
| `0x8A81E396` | `0x3F4BDFAC` | `0xCEC46E67` | `0x1E3968A8` | rotl32 |
|
||||
| `0x8A81E396` | `0x7E70CB54` | `0xDBE71FF7` | `0x1E3968A8` | rotr32 |
|
||||
| `0xA7352F36` | `0xA0EB7045` | `0x59E7B9D8` | `0xA0212004` | bitwise and |
|
||||
| `0xC89805AF` | `0x64291E2F` | `0x1BDC84A9` | `0xECB91FAF` | bitwise or |
|
||||
| `0x760726D3` | `0x79FC6A48` | `0xC675CAC5` | `0x0FFB4C9B` | bitwise xor |
|
||||
| `0x75551D43` | `0x3383BA34` | `0x2863AD31` | `0x00000003` | clz (leading zeros) |
|
||||
| `0xEA260841` | `0xE92C44B7` | `0xF83FFE7D` | `0x0000001B` | popcount (number of 1s) |
|
||||
|
||||
## progPowLoop
|
||||
|
||||
For the first loop iteration of block 30,000 the seed to use for `fill_mix`
|
||||
would be `0xEE304846DDD0A47B`. A two dimensional `mix` array should be created
|
||||
passing the rows into `fill_mix` witht he column number as the loop argument.
|
||||
|
||||
The state of the mix array after the call to `progPowLoop` for block 30,000,
|
||||
loop 1 are as follows.
|
||||
|
||||
`mix[0]` -
|
||||
|
||||
> ```
|
||||
> 0x40E09E9C, 0x967A7DF0, 0x8626BB1F, 0x12C2392F,
|
||||
> 0xA21D8305, 0x44C2702E, 0x94C93945, 0x6B66B158,
|
||||
> 0x0CF00FAA, 0x26F5E6B5, 0x36EC0134, 0xC89805AF,
|
||||
> 0x58118540, 0x8617DC4D, 0xC759F486, 0x8A81E396,
|
||||
> 0x22443D4D, 0x64291E2F, 0x1998AB7F, 0x11C0FBBB,
|
||||
> 0xBEA9C139, 0x82D1E47E, 0x7ED3E850, 0x2F81531A,
|
||||
> 0xBBDFBC4E, 0xF58AEE4D, 0x3CA34321, 0x357BD48A,
|
||||
> 0x2F9C8B5D, 0x2319B193, 0x2856BB38, 0x2E3C33E6
|
||||
> ```
|
||||
|
||||
`mix[1]` -
|
||||
|
||||
> ```
|
||||
> 0x4EB8A8F9, 0xD978BF17, 0x7D5074D4, 0x7A092D5D,
|
||||
> 0x8682D1BE, 0xC3D2941C, 0xF1A1A38B, 0x54BB6D34,
|
||||
> 0x2F0FB257, 0xB5464B50, 0x40927B67, 0xBB92A7E1,
|
||||
> 0x1305A517, 0xE06C6765, 0xA75FD647, 0x9F232D6E,
|
||||
> 0x0D9213ED, 0x8884671D, 0x54352B96, 0x6772E58E,
|
||||
> 0x1B8120C9, 0x179F3CFB, 0x116FFC82, 0x6D019BCE,
|
||||
> 0x1C26A750, 0x89716638, 0x02BEB948, 0x2E0AD5CE,
|
||||
> 0x7FA915B2, 0x93024F2F, 0x2F58032E, 0xF02E550C
|
||||
> ```
|
||||
|
||||
`mix[2]` -
|
||||
|
||||
> ```
|
||||
> 0x008FF9BD, 0xC41F9802, 0x2E36FDC8, 0x9FBA2A91,
|
||||
> 0x0A921670, 0x231308E6, 0xEF09A56E, 0x9657A64A,
|
||||
> 0xF67723FE, 0x963DCD40, 0x354CBFDB, 0x57C07B9A,
|
||||
> 0x06AF5B40, 0xBA5DE5A6, 0xDA5AAE7B, 0x9F8A5E4B,
|
||||
> 0x7D6AFC9A, 0xE4783F78, 0x89B24946, 0x5EE94228,
|
||||
> 0xA209DAAA, 0xDCC27C64, 0x3366FBED, 0x0FEFB673,
|
||||
> 0x0FC205E3, 0xB61515B2, 0x70A45E9B, 0xBB225E5D,
|
||||
> 0xB8C38EA0, 0xE01DE9B4, 0x866FAA5B, 0x1A125220
|
||||
> ```
|
||||
|
||||
`mix[3]` -
|
||||
|
||||
> ```
|
||||
> 0xE5F9C5CC, 0x6F75CFA2, 0xE0F50924, 0xE7B4F5EF,
|
||||
> 0x779B903D, 0x5F068253, 0x05FF68E5, 0x39348653,
|
||||
> 0x654B89E4, 0x0559769E, 0xA3D46B93, 0xD084454D,
|
||||
> 0xCFC5CF7D, 0x8C11D8E4, 0x795BDB59, 0xD9E03113,
|
||||
> 0xBAE8C355, 0x12B63814, 0x4046A018, 0xA269A32E,
|
||||
> 0x54A57C4B, 0x2ED1065B, 0xB69A2C76, 0x4AEF0950,
|
||||
> 0x6C2D187B, 0x8252FAE7, 0x3E9C0ED2, 0x26E47B15,
|
||||
> 0xFEFB48E3, 0xDA088C7F, 0xA82B0379, 0xA49C6D86
|
||||
> ```
|
||||
|
||||
`mix[4]` -
|
||||
|
||||
> ```
|
||||
> 0xB926334C, 0x686A29AF, 0xD9E2EF15, 0x1C8A2D39,
|
||||
> 0x307ED4F4, 0x2ABB1DB6, 0xD6F95128, 0xDFCA05F8,
|
||||
> 0x904D9472, 0xEC09E200, 0x7143F47F, 0xEE488438,
|
||||
> 0xFCA48DA8, 0xA64C7DD4, 0xC4AE9A30, 0xEBA30BC9,
|
||||
> 0xB02630BF, 0xD1DF40CC, 0x4DFE8B7B, 0x205C97B3,
|
||||
> 0xE40376F8, 0x2491117E, 0x34984321, 0xA01546A7,
|
||||
> 0xB254F2F9, 0xC78A7C25, 0xFFC615E2, 0x5839FC88,
|
||||
> 0x2A04DF6C, 0xC02A9A8A, 0x39238EAD, 0x7139060C
|
||||
> ```
|
||||
|
||||
`mix[5]` -
|
||||
|
||||
> ```
|
||||
> 0xC416E54B, 0x64AD1C57, 0xBF7CBA55, 0x176F714E,
|
||||
> 0xBE733426, 0x995C4132, 0x5F50F779, 0x0F76FDF3,
|
||||
> 0x526F7870, 0xE56A1A8A, 0xDCEB677E, 0xD471CC19,
|
||||
> 0xA9ED60E4, 0x145E807F, 0x8D652E92, 0x80E8116F,
|
||||
> 0xFF1A37EB, 0x1E0C49A1, 0x59D756DA, 0x39A8E761,
|
||||
> 0x2F0F646F, 0x43F41278, 0x88CC48DA, 0x8FDFF7A4,
|
||||
> 0x9AEACA2E, 0x59E7808C, 0x7F72E46B, 0xCA572333,
|
||||
> 0xC6029C88, 0x7736E592, 0xF1338231, 0x262B2C7F
|
||||
> ```
|
||||
|
||||
`mix[6]` -
|
||||
|
||||
> ```
|
||||
> 0x3C554151, 0x70999423, 0x64BB49A8, 0xF9EBE9E9,
|
||||
> 0x7D9C28CF, 0x23EE7659, 0xD6504FCF, 0x1C58C2A1,
|
||||
> 0x62B9C627, 0x680AE248, 0xF196A153, 0x2A3C345A,
|
||||
> 0x860E6EB2, 0x266D2652, 0x3C9F2420, 0xF790A538,
|
||||
> 0x710A5523, 0xBEA2603A, 0x1C1CC272, 0xF91D482A,
|
||||
> 0x1CA19931, 0x7A80ED37, 0x9572513D, 0x376F1CFE,
|
||||
> 0xE57C1264, 0xE47BF931, 0xC7310E05, 0x7866CC9E,
|
||||
> 0xC676BBD5, 0x4C167FEB, 0x0FE03D2B, 0x46C6D26C
|
||||
> ```
|
||||
|
||||
`mix[7]` -
|
||||
|
||||
> ```
|
||||
> 0x3395F65A, 0x7142A5B1, 0x97780661, 0xE5EE45B8,
|
||||
> 0xCD9FDC42, 0x25BF044C, 0x0350F81B, 0x55D50703,
|
||||
> 0xA8CB893E, 0xEE795201, 0xC2D6E598, 0xC2AC2D7A,
|
||||
> 0xD2E81716, 0xAD876790, 0x0F3339C7, 0xEEC31E01,
|
||||
> 0xA293ABF6, 0x28AE317D, 0x44A7AC05, 0xBEBA1C5E,
|
||||
> 0x325ED29E, 0x4344131E, 0x921CD8DD, 0x08AB9E0B,
|
||||
> 0xC18E66A6, 0x87E6BCA3, 0x24CE82AE, 0xC910B4F1,
|
||||
> 0x9E513EC0, 0xA1B8CB76, 0xF0455815, 0x36BC0DCF
|
||||
> ```
|
||||
|
||||
`mix[8]` -
|
||||
|
||||
> ```
|
||||
> 0x0117C85F, 0xE018F2C6, 0x416C897D, 0x9D288A0F,
|
||||
> 0x2AA9EA93, 0x5A6D3CEA, 0xAA99B726, 0x0A42DAB7,
|
||||
> 0x72F6EA4A, 0x1DB074E6, 0x2E2A606C, 0xAC5D509B,
|
||||
> 0x53F13E85, 0x1D44B521, 0x24234C42, 0xAD5BAD70,
|
||||
> 0xAB2DA791, 0x6479546A, 0xD27B3771, 0xBB0A09DD,
|
||||
> 0x6D3C8056, 0x96572D4B, 0x52DB6535, 0x3D242BC1,
|
||||
> 0xF37D7C7A, 0xA60F7111, 0x59B59667, 0xF28635B0,
|
||||
> 0xC2A8F9F5, 0x7CFB9CCB, 0xDF8697AA, 0xA3260D94
|
||||
> ```
|
||||
|
||||
`mix[9]` -
|
||||
|
||||
> ```
|
||||
> 0xA387FC4B, 0xC757D3A0, 0xA584E879, 0xB0A1EC29,
|
||||
> 0x82CB2EC3, 0x6BF33664, 0x41FECC42, 0xF60C2AC5,
|
||||
> 0xEA250BE5, 0x42BE9F33, 0x9227B0B3, 0x9080A6AB,
|
||||
> 0xAF193598, 0xC708BC8A, 0x020CDEDB, 0x7FA2F773,
|
||||
> 0x4338E670, 0x069E0242, 0x5AD87326, 0xD7A87124,
|
||||
> 0x220D5C46, 0x26D3400D, 0x4899D1EE, 0x90EAD2F6,
|
||||
> 0xFA3F1F74, 0x9C5A5D58, 0xAE20567C, 0x424B690D,
|
||||
> 0xC9A4057A, 0x9F2A5CD1, 0xAA33CD5F, 0x18F58C00
|
||||
> ```
|
||||
|
||||
`mix[10]` -
|
||||
|
||||
> ```
|
||||
> 0xEAFE893C, 0x1ABB2971, 0x29803BB3, 0x5BC2F71F,
|
||||
> 0x619DAFAD, 0xD9CFEFB6, 0xB4FEFAB5, 0x5EB249EC,
|
||||
> 0x1A6E2B3A, 0xFB05DD28, 0xDCB33C2E, 0x630BB8AE,
|
||||
> 0x43463B39, 0x3BD2F552, 0xFB20C0A2, 0x3383BA34,
|
||||
> 0x2E9C1A99, 0x60A949B2, 0x861372AB, 0xC149D929,
|
||||
> 0xA77A0A93, 0xE0CEE0D9, 0x791E7E82, 0x66A8D75A,
|
||||
> 0x44D1845F, 0xE534DC4A, 0x2C7DD20C, 0xEEDAB329,
|
||||
> 0x3209FE2A, 0x0C0406BC, 0xD6D4BD2A, 0x5FDB13CC
|
||||
> ```
|
||||
|
||||
`mix[11]` -
|
||||
|
||||
> ```
|
||||
> 0x2520ABB3, 0xCD942485, 0x9A2929BC, 0x0E10F18C,
|
||||
> 0xDFB1815E, 0x8BEF05A3, 0x531A8837, 0x668838E4,
|
||||
> 0xBACCE200, 0x003F85C2, 0x56226F05, 0xC2233173,
|
||||
> 0x2F39A0D9, 0xF4466D0D, 0x0B9E686C, 0x82C69BDA,
|
||||
> 0x0C8A8CD6, 0xA93F3001, 0x36A65EC1, 0x40CCFD7A,
|
||||
> 0x84484E23, 0xF0896D45, 0x06D9F760, 0x6559142C,
|
||||
> 0x9FFE2E88, 0x9593DC89, 0x89C9E3B9, 0x33285F41,
|
||||
> 0x16F636C8, 0xA08169C7, 0xA5E1C956, 0xC22CCF52
|
||||
> ```
|
||||
|
||||
`mix[12]` -
|
||||
|
||||
> ```
|
||||
> 0xDC3B8CAA, 0xC6941197, 0x9969D596, 0x46453D3E,
|
||||
> 0x568EAFEA, 0x5B823345, 0xDE606E8E, 0x7523C86D,
|
||||
> 0x0EDAF441, 0x00C3D848, 0xAE5BAB99, 0xD705B9EE,
|
||||
> 0x54B49E3D, 0xF364A6A4, 0x42C55975, 0xFE41EED5,
|
||||
> 0xAD46170F, 0xAABE4868, 0x270379F9, 0xD33D0D7C,
|
||||
> 0xF39C476C, 0xA449118E, 0x71BCC1E4, 0x5E300E77,
|
||||
> 0x1CACD489, 0x4D82FABD, 0x090F9F80, 0xB2DB9626,
|
||||
> 0xE12A973B, 0x1B77460C, 0xD25F89F5, 0x5753612E
|
||||
> ```
|
||||
|
||||
`mix[13]` -
|
||||
|
||||
> ```
|
||||
> 0x042D951C, 0x38833AA7, 0xBEA9894D, 0x7AE7F381,
|
||||
> 0x42DB6723, 0x1FB0294F, 0x41452A28, 0xA7A97B9C,
|
||||
> 0x228AA7EA, 0x781A7420, 0x4589736D, 0xB3C19349,
|
||||
> 0x685EF9E6, 0xB4987DF6, 0xC9C3B188, 0x2DCA6A03,
|
||||
> 0xE89A6D3D, 0x50EF7CF5, 0xF6274868, 0x8AA22824,
|
||||
> 0x980FFDE3, 0xD4A6CB4E, 0x06FF9E1A, 0xBADB6DF5,
|
||||
> 0xEDE3ADF3, 0xC9CF45F6, 0xFDFA194C, 0xAF076AA8,
|
||||
> 0x7B876CEA, 0xB0C89575, 0x35A72155, 0x6CFDFC06
|
||||
> ```
|
||||
|
||||
`mix[14]` -
|
||||
|
||||
> ```
|
||||
> 0x0E3E28C8, 0xEC329DEC, 0x06D0A1D1, 0xF95ABEF8,
|
||||
> 0x168DCF28, 0xDD7714C1, 0x769C119E, 0xA5530A7D,
|
||||
> 0x1EEACB59, 0x30FD21BB, 0x082A3691, 0x1C4C9BCA,
|
||||
> 0x420F27DE, 0xA8FDA3AE, 0xE182142E, 0x5102F0FF,
|
||||
> 0x15B82277, 0x120C3217, 0x7BE714ED, 0xA251DCD5,
|
||||
> 0x6FB4F831, 0xB71D7B32, 0xD5F7A04A, 0x763E1A20,
|
||||
> 0x38E68B0C, 0xBB5A4121, 0x9340BF06, 0x948B03F8,
|
||||
> 0xE71BF17B, 0x1BB5F06B, 0x26F2A200, 0x5F28C415
|
||||
> ```
|
||||
|
||||
`mix[15]` -
|
||||
|
||||
> ```
|
||||
> 0xC818CD64, 0xBC910343, 0xB18B7776, 0x7182DEBA,
|
||||
> 0x9DB319EE, 0x9AE7F32F, 0x3CA9F8B5, 0xC63F48ED,
|
||||
> 0x8321533A, 0x059C96B1, 0x8DCDA60A, 0x75B6C1D1,
|
||||
> 0xC3406B57, 0x3DFE9E9B, 0xC01E1FD7, 0xC4643218,
|
||||
> 0x6873F0BA, 0x8ABD36B9, 0xA74D0CBD, 0x8A637118,
|
||||
> 0x6916416C, 0xB6E3A8DD, 0xB68DD4FA, 0xFBD543EE,
|
||||
> 0x56F05592, 0x33D6DB82, 0x58D0A7DD, 0x18630C6E,
|
||||
> 0xB33749CA, 0x5D2E87F7, 0x0F3C39DB, 0x3CAE9895
|
||||
> ```
|
||||
|
||||
## progPowHash
|
||||
|
||||
Block 30000:
|
||||
|
||||
- `prog_seed` - 600
|
||||
- `nonce` - `123456789abcdef0`
|
||||
- `header` - `ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff`
|
||||
- _digest_ - `11f19805c58ab46610ff9c719dcf0a5f18fa2f1605798eef770c47219274767d`
|
||||
- _result_ - `5b7ccd472dbefdd95b895cac8ece67ff0deb5a6bd2ecc6e162383d00c3728ece`
|
||||
|
||||
Block 0:
|
||||
|
||||
- `prog_seed` - 0
|
||||
- `nonce` - `0000000000000000`
|
||||
- `header` - `0000000000000000000000000000000000000000000000000000000000000000`
|
||||
- _digest_ - `faeb1be51075b03a4ff44b335067951ead07a3b078539ace76fd56fc410557a3`
|
||||
- _result_ - `63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12`
|
||||
|
||||
Block 49:
|
||||
|
||||
- `prog_seed` - 0
|
||||
- `nonce` - `0000000006ff2c47`
|
||||
- `header` - `63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12b`
|
||||
- _digest_ - `c789c1180f890ec555ff42042913465481e8e6bc512cb981e1c1108dc3f2227d`
|
||||
- _result_ - `9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd92`
|
||||
|
||||
Block 50:
|
||||
|
||||
- `prog_seed` - 1
|
||||
- `nonce` - `00000000076e482e`
|
||||
- `header` - `9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd922`
|
||||
- _digest_ - `c7340542c2a06b3a7dc7222635f7cd402abf8b528ae971ddac6bbe2b0c7cb518`
|
||||
- _result_ - `de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188`
|
||||
|
||||
Block 99:
|
||||
|
||||
- `prog_seed` - 1
|
||||
- `nonce` - `000000003917afab`
|
||||
- `header` - `de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188d`
|
||||
- _digest_ - `f5e60b2c5bfddd136167a30cbc3c8dbdbd15a512257dee7964e0bc6daa9f8ba7`
|
||||
- _result_ - `ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcc`
|
||||
|
||||
Block 29,950:
|
||||
|
||||
- `prog_seed` - 599
|
||||
- `nonce` - `005d409dbc23a62a`
|
||||
- `header` - `ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcce`
|
||||
- _digest_ - `07393d15805eb08ee6fc6cb3ad4ad1010533bd0ff92d6006850246829f18fd6e`
|
||||
- _result_ - `e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f`
|
||||
|
||||
Block 29,999:
|
||||
|
||||
- `prog_seed` - 599
|
||||
- `nonce` - `005db5fa4c2a3d03`
|
||||
- `header` - `e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f5`
|
||||
- _digest_ - `7551bddf977491da2f6cfc1679299544b23483e8f8ee0931c4c16a796558a0b8`
|
||||
- _result_ - `d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c645`
|
||||
|
||||
Block 30,000:
|
||||
|
||||
- `prog_seed` - 600
|
||||
- `nonce` - `005db8607994ff30`
|
||||
- `header` - `d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c6454`
|
||||
- _digest_ - `f1c2c7c32266af9635462e6ce1c98ebe4e7e3ecab7a38aaabfbf2e731e0fbff4`
|
||||
- _result_ - `8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef6`
|
||||
|
||||
Block 30,049:
|
||||
|
||||
- `prog_seed` - 600
|
||||
- `nonce` - `005e2e215a8ca2e7`
|
||||
- `header` - `8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef64`
|
||||
- _digest_ - `57fe6a9fbf920b4e91deeb66cb0efa971e08229d1a160330e08da54af0689add`
|
||||
- _result_ - `c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe0904`
|
||||
|
||||
Block 30,050:
|
||||
|
||||
- `prog_seed` - 601
|
||||
- `nonce` - `005e30899481055e`
|
||||
- `header` - `c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe09047`
|
||||
- _digest_ - `ba30c61cc5a2c74a5ecaf505965140a08f24a296d687e78720f0b48baf712f2d`
|
||||
- _result_ - `ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc7`
|
||||
|
||||
Block 30,099:
|
||||
|
||||
- `prog_seed` - 601
|
||||
- `nonce` - `005ea6aef136f88b`
|
||||
- `header` - `ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc71`
|
||||
- _digest_ - `cfd5e46048cd133d40f261fe8704e51d3f497fc14203ac6a9ef6a0841780b1cd`
|
||||
- _result_ - `49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd`
|
||||
|
||||
Block 59,950:
|
||||
|
||||
- `prog_seed` - 1,199
|
||||
- `nonce` - `02ebe0503bd7b1da`
|
||||
- `header` - `49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd6`
|
||||
- _digest_ - `21511fbaa31fb9f5fc4998a754e97b3083a866f4de86fa7500a633346f56d773`
|
||||
- _result_ - `f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19c`
|
||||
|
||||
Block 59,999:
|
||||
|
||||
- `prog_seed` - 1,199
|
||||
- `nonce` - `02edb6275bd221e3`
|
||||
- `header` - `f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19cf`
|
||||
- _digest_ - `653eda37d337e39d311d22be9bbd3458d3abee4e643bee4a7280a6d08106ef98`
|
||||
- _result_ - `341562d10d4afb706ec2c8d5537cb0c810de02b4ebb0a0eea5ae335af6fb2e8`
|
||||
|
||||
Block 10,000,000:
|
||||
|
||||
- `prog_seed` - 200,000
|
||||
- `nonce` - `005e30899481055e`
|
||||
- `header` - `efda178de857b2b1703d8d5403bd0f848e19cff5c50ba5c0d6210ddb16250ec3`
|
||||
- _digest_ - `b2403f56c426177856eaf0eedd707c86ae78a432b9169c3689a67058fcf2a848`
|
||||
- _result_ - `206aee640c0fd21473d5cc3654d63c80442d9e2dfa676d2801d3ec1fbab38a6d`
|
||||
|
||||
Block 100,000,000:
|
||||
|
||||
- `prog_seed` - 2,000,000
|
||||
- `nonce` - `02abe0589481055e`
|
||||
- `header` - `49e15ba4bf501ce8fe88765403bd0f848e19cff5c50ba5c0d6210ddb16250ec3`
|
||||
- _digest_ - `ac452084d6f4e6eacf4282ad58dbd4ce7ef2653fb5e6b5c877f56928c907432a`
|
||||
- _result_ - `b879f84923e71b812ef5a42ece0b5b9366c31cab218f40afe65f8a2cae448a6f`
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -76,7 +76,7 @@ function encodeType(primaryType) {
|
|||
}
|
||||
|
||||
function typeHash(primaryType) {
|
||||
return ethUtil.sha3(encodeType(primaryType));
|
||||
return ethUtil.keccak256(encodeType(primaryType));
|
||||
}
|
||||
|
||||
function encodeData(primaryType, data) {
|
||||
|
@ -92,11 +92,11 @@ function encodeData(primaryType, data) {
|
|||
let value = data[field.name];
|
||||
if (field.type == 'string' || field.type == 'bytes') {
|
||||
encTypes.push('bytes32');
|
||||
value = ethUtil.sha3(value);
|
||||
value = ethUtil.keccak256(value);
|
||||
encValues.push(value);
|
||||
} else if (types[field.type] !== undefined) {
|
||||
encTypes.push('bytes32');
|
||||
value = ethUtil.sha3(encodeData(field.type, value));
|
||||
value = ethUtil.keccak256(encodeData(field.type, value));
|
||||
encValues.push(value);
|
||||
} else if (field.type.lastIndexOf(']') === field.type.length - 1) {
|
||||
throw 'TODO: Arrays currently unimplemented in encodeData';
|
||||
|
@ -110,11 +110,11 @@ function encodeData(primaryType, data) {
|
|||
}
|
||||
|
||||
function structHash(primaryType, data) {
|
||||
return ethUtil.sha3(encodeData(primaryType, data));
|
||||
return ethUtil.keccak256(encodeData(primaryType, data));
|
||||
}
|
||||
|
||||
function signHash() {
|
||||
return ethUtil.sha3(
|
||||
return ethUtil.keccak256(
|
||||
Buffer.concat([
|
||||
Buffer.from('1901', 'hex'),
|
||||
structHash('EIP712Domain', typedData.domain),
|
||||
|
@ -123,7 +123,7 @@ function signHash() {
|
|||
);
|
||||
}
|
||||
|
||||
const privateKey = ethUtil.sha3('cow');
|
||||
const privateKey = ethUtil.keccak256('cow');
|
||||
const address = ethUtil.privateToAddress(privateKey);
|
||||
const sig = ethUtil.ecsign(signHash(), privateKey);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
| Variable | Symbol | Value | Unit | Source |
|
||||
| -------------------|--------------|---------------|---------------|--------|
|
||||
| Network Hashrate |H<sub>N</sub> | 296000 | GH/s | https://etherscan.io/chart/hashrate |
|
||||
| GPU Hashrate |H<sub>M</sub> | 31.2 | MH/s | http://www.legitreviews.com/geforce-gtx-1070-ethereum-mining-small-tweaks-great-hashrate-low-power_195451 |
|
||||
| GPU Hashrate |H<sub>M</sub> | 31.2 | MH/s | https://www.legitreviews.com/geforce-gtx-1070-ethereum-mining-small-tweaks-great-hashrate-low-power_195451 |
|
||||
| GPU Power |P<sub>M</sub> | 110.6 | W | https://www.reddit.com/r/ethereum/comments/7vewys/10000_tons_co2_per_day_and_climbing_eip_858/dtrswyz/ |
|
||||
|
||||
|
||||
|
|
533
eip-1175.md
533
eip-1175.md
|
@ -1,533 +0,0 @@
|
|||
---
|
||||
eip: 1175
|
||||
title: Wallet & shop standard for all tokens (erc20)
|
||||
author: Jet Lim (@Nitro888)
|
||||
discussions-to: https://github.com/ethereum/EIPs/issues/1182
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
category: ERC
|
||||
created: 2018-06-21
|
||||
requires: 20
|
||||
---
|
||||
|
||||
# All tokens go to heaven
|
||||
## Simple Summary
|
||||
Make wallets and shops created from certified contracts make erc20 tokens easy to use for commerce.
|
||||
|
||||
![wallet](https://user-images.githubusercontent.com/11692220/41762799-ee17c480-7636-11e8-9930-681be2c59b56.png)
|
||||
|
||||
## Abstract
|
||||
The mutual trust between the wallet and the shop created by the authenticated contract allows you to pay for and purchase items at a simple process.
|
||||
|
||||
## Motivation
|
||||
New standards with improvements have been released, but the majority of tokens currently being developed are erc20 tokens. So I felt I needed a proposal to use old tokens in commerce.
|
||||
To use various erc20 tokens for trading, you need a custom contract. However, a single wallet with a variety of tokens, and a mutually trusted store, can make transactions that are simple and efficient. The erc20 token is traded through two calls, `approve (address _spender, uint256 _value)` and `transferFrom (address _from, address _to, uint256 _value)`, but when using the wallet contract, `paySafe (address _shop, uint256 _item)`will be traded only in one call.
|
||||
And if you only reuse the store interface, you can also trade using `payUnsafe (address _shop, uint256 _item)`.
|
||||
|
||||
## Specification
|
||||
![workflow](https://user-images.githubusercontent.com/11692220/41841025-2ed6e024-78a2-11e8-9faf-2b43aeaa2303.png)
|
||||
## WalletCenter
|
||||
### Methods
|
||||
#### createWallet
|
||||
Create wallet contract and add to list. Returns the address of new wallet.
|
||||
|
||||
``` js
|
||||
function createWallet() public returns (address _wallet)
|
||||
```
|
||||
|
||||
#### isWallet
|
||||
Returns true or false value for test this address is a created by createWallet.
|
||||
|
||||
``` js
|
||||
function isWallet(address _wallet) public constant returns (bool)
|
||||
```
|
||||
|
||||
#### createShop
|
||||
Create Shop contract and add to list. Returns the address of new Shop with erc20 token address.
|
||||
|
||||
``` js
|
||||
function createShop(address _erc20) public returns (address _shop)
|
||||
```
|
||||
|
||||
#### isShop
|
||||
Returns true or false value for test this address is a created by createWallet.
|
||||
|
||||
``` js
|
||||
function isShop(address _shop) public constant returns (bool)
|
||||
```
|
||||
|
||||
### Events
|
||||
#### Wallet
|
||||
Search for my wallet.
|
||||
``` js
|
||||
event Wallet(address indexed _owner, address indexed _wallet)
|
||||
```
|
||||
|
||||
#### Shop
|
||||
Search for my shop.
|
||||
``` js
|
||||
event Shop(address indexed _owner, address indexed _shop, address indexed _erc20)
|
||||
```
|
||||
|
||||
## Wallet
|
||||
Wallet must be created by wallet center.
|
||||
### Methods
|
||||
#### balanceOf
|
||||
Returns the account balance of Wallet.
|
||||
``` js
|
||||
function balanceOf(address _erc20) public constant returns (uint256 balance)
|
||||
```
|
||||
|
||||
#### withdrawal
|
||||
withdrawal `_value` amount of `_erc20` token to `_owner`.
|
||||
``` js
|
||||
function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success)
|
||||
```
|
||||
|
||||
#### paySafe
|
||||
Pay for safe shop (created by contract) item with item index `_item`.
|
||||
``` js
|
||||
function paySafe(address _shop, uint256 _item) onlyOwner onlyShop(_shop) public payable returns (bool success)
|
||||
```
|
||||
|
||||
#### payUnsafe
|
||||
Pay for unsafe shop (did not created by contract) item with item index `_item`.
|
||||
``` js
|
||||
function payUnsafe(address _shop, uint256 _item) onlyOwner public payable returns (bool success)
|
||||
```
|
||||
|
||||
#### payCancel
|
||||
Cancel pay and refund. (only weekly model)
|
||||
``` js
|
||||
function payCancel(address _shop, uint256 _item) onlyOwner public returns (bool success)
|
||||
```
|
||||
|
||||
#### refund
|
||||
Refund from shop with item index `_item`.
|
||||
``` js
|
||||
function refund(uint256 _item, uint256 _value) public payable returns (bool success)
|
||||
```
|
||||
|
||||
### Events
|
||||
#### Pay
|
||||
``` js
|
||||
event Pay(address indexed _shop, uint256 indexed _item, uint256 indexed _value)
|
||||
```
|
||||
|
||||
#### Refund
|
||||
``` js
|
||||
event Refund(address indexed _shop, uint256 indexed _item, uint256 indexed _value)
|
||||
```
|
||||
|
||||
## Shop
|
||||
Shop is created by wallet center or not. but Shop that created by wallet center is called safe shop.
|
||||
### Methods
|
||||
#### balanceOf
|
||||
Returns the account balance of Shop.
|
||||
``` js
|
||||
function balanceOf(address _erc20) public constant returns (uint256 balance)
|
||||
```
|
||||
|
||||
#### withdrawal
|
||||
withdrawal `_value` amount of `_erc20` token to `_owner`.
|
||||
``` js
|
||||
function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success)
|
||||
```
|
||||
|
||||
#### pay
|
||||
Pay from buyer with item index `_item`.
|
||||
``` js
|
||||
function pay(uint256 _item) onlyWallet(msg.sender) public payable returns (bool success)
|
||||
```
|
||||
|
||||
#### refund
|
||||
refund token to `_to`.
|
||||
``` js
|
||||
function refund(address _buyer, uint256 _item, uint256 _value) onlyWallet(_buyer) onlyOwner public payable returns (bool success)
|
||||
```
|
||||
|
||||
#### resister
|
||||
Listing item for sell.
|
||||
``` js
|
||||
function resister(uint8 _category, uint256 _price, uint256 _stock) onlyOwner public returns (uint256 _itemId)
|
||||
```
|
||||
|
||||
#### update
|
||||
Update item state for sell. (change item `_price` or add item `_stock`)
|
||||
``` js
|
||||
function update(uint256 _item, uint256 _price, uint256 _stock) onlyOwner public
|
||||
```
|
||||
|
||||
#### price
|
||||
Get token address and price from buyer with item index `_item`.
|
||||
``` js
|
||||
function price(uint256 _item) public constant returns (address _erc20, uint256 _value)
|
||||
```
|
||||
|
||||
#### canBuy
|
||||
`_who` can Buy `_item`.
|
||||
``` js
|
||||
function canBuy(address _who, uint256 _item) public constant returns (bool _canBuy)
|
||||
```
|
||||
|
||||
#### isBuyer
|
||||
`_who` is buyer of `_item`.
|
||||
``` js
|
||||
function isBuyer(address _who, uint256 _item) public constant returns (bool _buyer)
|
||||
```
|
||||
|
||||
#### info
|
||||
Set shop information bytes.
|
||||
``` js
|
||||
function info(bytes _msgPack)
|
||||
```
|
||||
|
||||
#### upVote
|
||||
Up vote for this shop.
|
||||
``` js
|
||||
function upVote()
|
||||
```
|
||||
|
||||
#### dnVote
|
||||
Down vote for this shop.
|
||||
``` js
|
||||
function dnVote()
|
||||
```
|
||||
|
||||
#### about
|
||||
Get shop token, up vote and down vote.
|
||||
``` js
|
||||
function about() view returns (address _erc20, uint256 _up, uint256 _down)
|
||||
```
|
||||
|
||||
#### infoItem
|
||||
Set item information bytes.
|
||||
``` js
|
||||
function infoItem(uint256 _item, bytes _msgPack)
|
||||
```
|
||||
|
||||
#### upVoteItem
|
||||
Up vote for this item.
|
||||
``` js
|
||||
function upVoteItem(uint256 _item)
|
||||
```
|
||||
|
||||
#### dnVoteItem
|
||||
Down vote for this item.
|
||||
``` js
|
||||
function dnVoteItem(uint256 _item)
|
||||
```
|
||||
|
||||
#### aboutItem
|
||||
Get Item price, up vote and down vote.
|
||||
``` js
|
||||
function aboutItem(uint256 _item) view returns (uint256 _price, uint256 _up, uint256 _down)
|
||||
```
|
||||
|
||||
### Events
|
||||
#### Pay
|
||||
``` js
|
||||
event Pay(address indexed _buyer, uint256 indexed _item, uint256 indexed _value)
|
||||
```
|
||||
|
||||
#### Refund
|
||||
``` js
|
||||
event Refund(address indexed _to, uint256 indexed _item, uint256 indexed _value)
|
||||
```
|
||||
|
||||
#### Item
|
||||
``` js
|
||||
event Item(uint256 indexed _item, uint256 _price)
|
||||
```
|
||||
|
||||
#### Info
|
||||
``` js
|
||||
event Info(bytes _msgPack)
|
||||
```
|
||||
|
||||
#### InfoItem
|
||||
``` js
|
||||
event InfoItem(uint256 indexed _item, bytes _msgPack)
|
||||
```
|
||||
|
||||
## Implementation
|
||||
Sample token contract address is [0x393dd70ce2ae7b30501aec94727968c517f90d52](https://ropsten.etherscan.io/address/0x393dd70ce2ae7b30501aec94727968c517f90d52)
|
||||
|
||||
WalletCenter contract address is [0x1fe0862a4a8287d6c23904d61f02507b5044ea31](https://ropsten.etherscan.io/address/0x1fe0862a4a8287d6c23904d61f02507b5044ea31)
|
||||
|
||||
WalletCenter create shop contract address is [0x59117730D02Ca3796121b7975796d479A5Fe54B0](https://ropsten.etherscan.io/address/0x59117730D02Ca3796121b7975796d479A5Fe54B0)
|
||||
|
||||
WalletCenter create wallet contract address is [0x39da7111844df424e1d0a0226183533dd07bc5c6](https://ropsten.etherscan.io/address/0x39da7111844df424e1d0a0226183533dd07bc5c6)
|
||||
|
||||
|
||||
## Appendix
|
||||
``` js
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract ERC20Interface {
|
||||
function totalSupply() public constant returns (uint);
|
||||
function balanceOf(address tokenOwner) public constant returns (uint balance);
|
||||
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
|
||||
function transfer(address to, uint tokens) public returns (bool success);
|
||||
function approve(address spender, uint tokens) public returns (bool success);
|
||||
function transferFrom(address from, address to, uint tokens) public returns (bool success);
|
||||
|
||||
event Transfer(address indexed from, address indexed to, uint tokens);
|
||||
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
|
||||
}
|
||||
|
||||
contract SafeMath {
|
||||
function safeAdd(uint a, uint b) public pure returns (uint c) {
|
||||
c = a + b;
|
||||
require(c >= a);
|
||||
}
|
||||
function safeSub(uint a, uint b) public pure returns (uint c) {
|
||||
require(b <= a);
|
||||
c = a - b;
|
||||
}
|
||||
function safeMul(uint a, uint b) public pure returns (uint c) {
|
||||
c = a * b;
|
||||
require(a == 0 || c / a == b);
|
||||
}
|
||||
function safeDiv(uint a, uint b) public pure returns (uint c) {
|
||||
require(b > 0);
|
||||
c = a / b;
|
||||
}
|
||||
}
|
||||
|
||||
contract _Base {
|
||||
address internal owner;
|
||||
address internal walletCenter;
|
||||
|
||||
modifier onlyOwner {
|
||||
require(owner == msg.sender);
|
||||
_;
|
||||
}
|
||||
modifier onlyWallet(address _addr) {
|
||||
require(WalletCenter(walletCenter).isWallet(_addr));
|
||||
_;
|
||||
}
|
||||
modifier onlyShop(address _addr) {
|
||||
require(WalletCenter(walletCenter).isShop(_addr));
|
||||
_;
|
||||
}
|
||||
|
||||
function balanceOf(address _erc20) public constant returns (uint256 balance) {
|
||||
if(_erc20==address(0))
|
||||
return address(this).balance;
|
||||
return ERC20Interface(_erc20).balanceOf(this);
|
||||
}
|
||||
|
||||
function transfer(address _to, address _erc20, uint256 _value) internal returns (bool success) {
|
||||
require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value);
|
||||
if(_erc20==address(0))
|
||||
_to.transfer(_value);
|
||||
else
|
||||
ERC20Interface(_erc20).approve(_to,_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function withdrawal(address _erc20, uint256 _value) public returns (bool success);
|
||||
|
||||
event Pay(address indexed _who, uint256 indexed _item, uint256 indexed _value);
|
||||
event Refund(address indexed _who, uint256 indexed _item, uint256 indexed _value);
|
||||
event Prize(address indexed _who, uint256 indexed _item, uint256 indexed _value);
|
||||
}
|
||||
|
||||
contract _Wallet is _Base {
|
||||
constructor(address _who) public {
|
||||
owner = _who;
|
||||
walletCenter = msg.sender;
|
||||
}
|
||||
|
||||
function pay(address _shop, uint256 _item) private {
|
||||
require(_Shop(_shop).canBuy(this,_item));
|
||||
|
||||
address _erc20;
|
||||
uint256 _value;
|
||||
(_erc20,_value) = _Shop(_shop).price(_item);
|
||||
|
||||
transfer(_shop,_erc20,_value);
|
||||
_Shop(_shop).pay(_item);
|
||||
emit Pay(_shop,_item,_value);
|
||||
}
|
||||
|
||||
function paySafe(address _shop, uint256 _item) onlyOwner onlyShop(_shop) public payable returns (bool success) {
|
||||
pay(_shop,_item);
|
||||
return true;
|
||||
}
|
||||
function payUnsafe(address _shop, uint256 _item) onlyOwner public payable returns (bool success) {
|
||||
pay(_shop,_item);
|
||||
return true;
|
||||
}
|
||||
function payCancel(address _shop, uint256 _item) onlyOwner public returns (bool success) {
|
||||
_Shop(_shop).payCancel(_item);
|
||||
return true;
|
||||
}
|
||||
|
||||
function refund(address _erc20, uint256 _item, uint256 _value) public payable returns (bool success) {
|
||||
require((_erc20==address(0)?msg.value:ERC20Interface(_erc20).allowance(msg.sender,this))==_value);
|
||||
if(_erc20!=address(0))
|
||||
ERC20Interface(_erc20).transferFrom(msg.sender,this,_value);
|
||||
emit Refund(msg.sender,_item,_value);
|
||||
return true;
|
||||
}
|
||||
function prize(address _erc20, uint256 _item, uint256 _value) public payable returns (bool success) {
|
||||
require((_erc20==address(0)?msg.value:ERC20Interface(_erc20).allowance(msg.sender,this))==_value);
|
||||
if(_erc20!=address(0))
|
||||
ERC20Interface(_erc20).transferFrom(msg.sender,this,_value);
|
||||
emit Prize(msg.sender,_item,_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success) {
|
||||
require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value);
|
||||
if(_erc20==address(0))
|
||||
owner.transfer(_value);
|
||||
else
|
||||
ERC20Interface(_erc20).transfer(owner,_value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
contract _Shop is _Base, SafeMath{
|
||||
address erc20;
|
||||
constructor(address _who, address _erc20) public {
|
||||
owner = _who;
|
||||
walletCenter = msg.sender;
|
||||
erc20 = _erc20;
|
||||
}
|
||||
|
||||
struct item {
|
||||
uint8 category; // 0 = disable, 1 = non Stock, non Expire, 2 = can Expire (after 1 week), 3 = stackable
|
||||
uint256 price;
|
||||
uint256 stockCount;
|
||||
|
||||
mapping(address=>uint256) customer;
|
||||
}
|
||||
|
||||
uint index;
|
||||
mapping(uint256=>item) items;
|
||||
|
||||
function pay(uint256 _item) onlyWallet(msg.sender) public payable returns (bool success) {
|
||||
require(canBuy(msg.sender, _item));
|
||||
require((erc20==address(0)?msg.value:ERC20Interface(erc20).allowance(msg.sender,this))==items[_item].price);
|
||||
|
||||
if(erc20!=address(0))
|
||||
ERC20Interface(erc20).transferFrom(msg.sender,this,items[_item].price);
|
||||
|
||||
if(items[_item].category==1 || items[_item].category==2 && now > safeAdd(items[_item].customer[msg.sender], 1 weeks))
|
||||
items[_item].customer[msg.sender] = now;
|
||||
else if(items[_item].category==2 && now < safeAdd(items[_item].customer[msg.sender], 1 weeks) )
|
||||
items[_item].customer[msg.sender] = safeAdd(items[_item].customer[msg.sender], 1 weeks);
|
||||
else if(items[_item].category==3) {
|
||||
items[_item].customer[msg.sender] = safeAdd(items[_item].customer[msg.sender],1);
|
||||
items[_item].stockCount = safeSub(items[_item].stockCount,1);
|
||||
}
|
||||
|
||||
emit Pay(msg.sender,_item,items[_item].customer[msg.sender]);
|
||||
return true;
|
||||
}
|
||||
|
||||
function payCancel(uint256 _item) onlyWallet(msg.sender) public returns (bool success) {
|
||||
require (items[_item].category==2&&safeAdd(items[_item].customer[msg.sender],2 weeks)>now&&balanceOf(erc20)>=items[_item].price);
|
||||
|
||||
items[_item].customer[msg.sender] = safeSub(items[_item].customer[msg.sender],1 weeks);
|
||||
transfer(msg.sender, erc20, items[_item].price);
|
||||
_Wallet(msg.sender).refund(erc20,_item,items[_item].price);
|
||||
emit Refund(msg.sender,_item,items[_item].price);
|
||||
|
||||
return true;
|
||||
}
|
||||
function refund(address _to, uint256 _item) onlyWallet(_to) onlyOwner public payable returns (bool success) {
|
||||
require(isBuyer(_to,_item)&&items[_item].category>0&&(items[_item].customer[_to]>0||(items[_item].category==2&&safeAdd(items[_item].customer[_to],2 weeks)>now)));
|
||||
require((erc20==address(0)?address(this).balance:ERC20Interface(erc20).balanceOf(this))>=items[_item].price);
|
||||
|
||||
if(items[_item].category==1)
|
||||
items[_item].customer[_to] = 0;
|
||||
else if(items[_item].category==2)
|
||||
items[_item].customer[_to] = safeSub(items[_item].customer[_to],1 weeks);
|
||||
else
|
||||
items[_item].customer[_to] = safeSub(items[_item].customer[_to],1);
|
||||
|
||||
transfer(_to, erc20, items[_item].price);
|
||||
_Wallet(_to).refund(erc20,_item,items[_item].price);
|
||||
emit Refund(_to,_item,items[_item].price);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
event Item(uint256 indexed _item, uint256 _price);
|
||||
function resister(uint8 _category, uint256 _price, uint256 _stock) onlyOwner public returns (uint256 _itemId) {
|
||||
require(_category>0&&_category<4);
|
||||
require(_price>0);
|
||||
items[index] = item(_category,_price,_stock);
|
||||
index = safeAdd(index,1);
|
||||
emit Item(index,_price);
|
||||
return safeSub(index,1);
|
||||
}
|
||||
function update(uint256 _item, uint256 _price, uint256 _stock) onlyOwner public {
|
||||
require(items[_item].category>0);
|
||||
require(_price>0);
|
||||
uint256 temp = items[_item].price;
|
||||
items[_item].price = _price;
|
||||
items[_item].stockCount = safeAdd(items[_item].stockCount,_stock);
|
||||
|
||||
if(temp!=items[_item].price)
|
||||
emit Item(index,items[_item].price);
|
||||
}
|
||||
|
||||
function price(uint256 _item) public constant returns (address _erc20, uint256 _value) {
|
||||
return (erc20,items[_item].price);
|
||||
}
|
||||
|
||||
function canBuy(address _who, uint256 _item) public constant returns (bool _canBuy) {
|
||||
return (items[_item].category>0) &&
|
||||
!(items[_item].category==1&&items[_item].customer[_who]>0) &&
|
||||
(items[_item].stockCount>0);
|
||||
}
|
||||
|
||||
function isBuyer(address _who, uint256 _item) public constant returns (bool _buyer) {
|
||||
return (items[_item].category==1&&items[_item].customer[_who]>0)||(items[_item].category==2&&safeAdd(items[_item].customer[_who],1 weeks)>now)||(items[_item].category==3&&items[_item].customer[_who]>0);
|
||||
}
|
||||
|
||||
uint lastWithdrawal;
|
||||
function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success) {
|
||||
require(safeAdd(lastWithdrawal,1 weeks)<=now);
|
||||
require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value);
|
||||
if(_erc20==address(0))
|
||||
owner.transfer(_value);
|
||||
else
|
||||
ERC20Interface(_erc20).transfer(owner,_value);
|
||||
lastWithdrawal = now;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
contract WalletCenter {
|
||||
mapping(address=>bool) public wallet;
|
||||
event Wallet(address indexed _owner, address indexed _wallet);
|
||||
function createWallet() public returns (address _wallet) {
|
||||
_wallet = new _Wallet(msg.sender);
|
||||
wallet[_wallet] = true;
|
||||
emit Wallet(msg.sender,_wallet);
|
||||
return _wallet;
|
||||
}
|
||||
function isWallet(address _wallet) public constant returns (bool) {
|
||||
return wallet[_wallet];
|
||||
}
|
||||
mapping(address=>bool) public shop;
|
||||
event Shop(address indexed _owner, address indexed _shop, address indexed _erc20);
|
||||
function createShop(address _erc20) public returns (address _shop) {
|
||||
_shop = new _Shop(msg.sender,_erc20);
|
||||
shop[_shop] = true;
|
||||
emit Shop(msg.sender,_shop,_erc20);
|
||||
return _shop;
|
||||
}
|
||||
function isShop(address _shop) public constant returns (bool) {
|
||||
return shop[_shop];
|
||||
}
|
||||
}
|
||||
```
|
||||
## Copyright
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
@ -14,9 +14,11 @@ title: Home
|
|||
|
||||
<h2>EIP status terms</h2>
|
||||
<ul>
|
||||
<li><strong>Draft</strong> - an EIP that is open for consideration.</li>
|
||||
<li><strong>Accepted</strong> - an EIP that is planned for immediate adoption, i.e. expected to be included in the next hard fork (for Core/Consensus layer EIPs).</li>
|
||||
<li><strong>Final</strong> - an EIP that has been adopted in a previous hard fork (for Core/Consensus layer EIPs).</li>
|
||||
<li><strong>Draft</strong> - an EIP that is open for consideration and is undergoing rapid iteration and changes.</li>
|
||||
<li><strong>Last Call</strong> - an EIP that is done with its initial iteration and ready for review by a wide audience.</li>
|
||||
<li><strong>Accepted</strong> - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. The process for Core Devs to decide whether to encode an EIP into their clients as part of a hard fork is not part of the EIP process. If such a decision is made, the EIP wil move to final. </li>
|
||||
<li><strong>Final (non-Core)</strong> - an EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author.</li>
|
||||
<li><strong>Final (Core)</strong> - an EIP that the Core Devs have decided to implement and release in a future hard fork or has already been released in a hard fork.</li>
|
||||
<li><strong>Deferred</strong> an EIP that is not being considered for immediate adoption. May be reconsidered in the future for a subsequent hard fork.</li>
|
||||
</ul>
|
||||
|
||||
|
|
Loading…
Reference in New Issue