diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index d29e18ad30cf00..8fc28d16cb96f9 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -5,7 +5,8 @@ status: Active type: Meta author: Martin Becze , Hudson Jameson , 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:` +` * updated:` + ` * requires:` ` * replaces:` @@ -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 diff --git a/EIPS/eip-1013.md b/EIPS/eip-1013.md index 2aa87d149b5e26..e4cf68a98a7530 100644 --- a/EIPS/eip-1013.md +++ b/EIPS/eip-1013.md @@ -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 diff --git a/EIPS/eip-1014.md b/EIPS/eip-1014.md index f2c0575c3e375b..0aa0aaea973f3f 100644 --- a/EIPS/eip-1014.md +++ b/EIPS/eip-1014.md @@ -4,7 +4,7 @@ title: Skinny CREATE2 author: Vitalik Buterin (@vbuterin) category: Core type: Standards Track -status: Accepted +status: Final created: 2018-04-20 --- @@ -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. diff --git a/EIPS/eip-1015.md b/EIPS/eip-1015.md index c9e9ba7b82b263..4aecc15a1896e5 100644 --- a/EIPS/eip-1015.md +++ b/EIPS/eip-1015.md @@ -3,7 +3,7 @@ eip: 1015 title: Configurable On Chain Issuance author: Alex Van de Sande 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 diff --git a/EIPS/eip-1052.md b/EIPS/eip-1052.md index 2374eec45f726d..cce394ecd9cd1c 100644 --- a/EIPS/eip-1052.md +++ b/EIPS/eip-1052.md @@ -3,7 +3,7 @@ eip: 1052 title: EXTCODEHASH opcode author: Nick Johnson , Paweł Bylica discussions-to: https://ethereum-magicians.org/t/extcodehash-opcode/262 -status: Accepted +status: Final type: Standards Track category: Core created: 2018-05-02 diff --git a/EIPS/eip-1057.md b/EIPS/eip-1057.md index e85d218e47c0e1..41a27c9de94450 100644 --- a/EIPS/eip-1057.md +++ b/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. +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. -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. +## Motivation -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?” +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. -EIP 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. +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. -## Motivation +### 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. -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. +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. -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. +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. -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. +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 -## Specification +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 -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 SHA algorithm is a sequence of simple math operations - additions, logical ops, and rotates. -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. +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. -In contrast to Ethash, the changes detailed below make ProgPoW dependent on the core compute capabilities in addition to memory bandwidth and size. +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. -**Changes keccak_f1600 (with 64-bit words) to keccak_f800 (with 32-bit words).** +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. -*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.* +#### Scrypt and NeoScrypt +* Potential ASIC efficiency gain ~ 1000X -**Increases mix state.** +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. -*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.* +#### X11 and X16R +* Potential ASIC efficiency gain ~ 1000X -**Adds a random sequence of math in the main loop.** +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. -*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.* +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. -**Adds reads from a small, low-latency cache that supports random addresses.** +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. -*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.* +#### Equihash +* Potential ASIC efficiency gain ~ 100X -**Increases the DRAM read from 128 bytes to 256 bytes.** +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. -*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.* +#### Cuckoo Cycle +* Potential ASIC efficiency gain ~ 100X -The DAG file is generated according to traditional Ethash specifications. +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 + +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. -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. +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) +uint32_t fnv1a(uint32_t h, uint32_t d) { - return h = (h ^ d) * 0x1000193; + 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 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,80 +221,33 @@ 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 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 - -```cpp -bool progpow_search( - 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 -) -{ - uint32_t mix[PROGPOW_LANES][PROGPOW_REGS]; - hash32_t digest; - for (int i = 0; i < 8; i++) - digest.uint32s[i] = 0; - - // keccak(header..nonce) - hash32_t seed_256 = keccak_f800_progpow(header, nonce, digest); - // endian swap so byte 0 of the hash is the MSB of the value - uint64_t seed = bswap(seed_256[0]) << 32 | bswap(seed_256[1]); - - // initialize mix for all lanes - for (int l = 0; l < PROGPOW_LANES; l++) - fill_mix(seed, l, mix[l]); - - // execute the randomly generated inner loop - for (int i = 0; i < PROGPOW_CNT_DAG; i++) - progPowLoop(prog_seed, i, mix, dag); - - // Reduce mix data to a per-lane 32-bit digest - uint32_t digest_lane[PROGPOW_LANES]; - for (int l = 0; l < PROGPOW_LANES; l++) - { - digest_lane[l] = 0x811c9dc5 - for (int i = 0; i < PROGPOW_REGS; i++) - 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; - for (int l = 0; l < PROGPOW_LANES; l++) - fnv1a(digest.uint32s[l%8], digest_lane[l]) +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. - // keccak(header .. keccak(header..nonce) .. digest); - return (keccak_f800_progpow(header, seed, digest) <= target); -} -``` +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. -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. +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_cache[PROGPOW_REGS]) +kiss99_t progPowInit(uint64_t prog_seed, int mix_seq_dst[PROGPOW_REGS], int mix_seq_src[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); + 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 @@ -224,7 +255,7 @@ kiss99_t progPowInit(uint64_t prog_seed, int mix_seq_dst[PROGPOW_REGS], int mix_ for (int i = 0; i < PROGPOW_REGS; i++) { mix_seq_dst[i] = i; - mix_seq_cache[i] = i; + mix_seq_src[i] = i; } for (int i = PROGPOW_REGS - 1; i > 0; i--) { @@ -232,33 +263,37 @@ kiss99_t progPowInit(uint64_t prog_seed, int mix_seq_dst[PROGPOW_REGS], int mix_ 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]); + swap(mix_seq_src[i], mix_seq_src[j]); } return prog_rnd; } ``` -The math operations that merge values into the mix data are ones chosen to maintain entropy. +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) -void merge(uint32_t &a, uint32_t b, uint32_t r) +uint32_t 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; + case 0: return (a * 33) + b; + case 1: return (a ^ b) * 33; // 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; + 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 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 @@ -281,7 +316,19 @@ uint32_t math(uint32_t a, uint32_t b, uint32_t r) } ``` -The main loop: + +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( @@ -290,17 +337,21 @@ void progPowLoop( 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))); + // 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++) { - // 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; + // 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++) - data_g[l][i] = dag[offset_l * PROGPOW_DAG_LOADS + i]; + dag_entry[l][i] = dag[dag_addr_lane * PROGPOW_DAG_LOADS + i]; } // Initialize the program seed and sequences @@ -324,7 +375,7 @@ void progPowLoop( 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); + mix[l][dst] = merge(mix[l][dst], dag[offset], sel); } } if (i < PROGPOW_CNT_MATH) @@ -334,14 +385,14 @@ void progPowLoop( 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 + 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); - merge(mix[l][dst], data, sel2); + mix[l][dst] = merge(mix[l][dst], data, sel2); } } } @@ -352,10 +403,64 @@ void progPowLoop( 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); + 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 is computed +* When mining this final value is compared against a `hash32_t` target + +```cpp +hash32_t progPowHash( + const uint64_t prog_seed, // value is (block_number/PROGPOW_PERIOD) + const uint64_t nonce, + const hash32_t header, + const uint32_t *dag // gigabyte DAG located in framebuffer - the first portion gets cached +) +{ + uint32_t mix[PROGPOW_LANES][PROGPOW_REGS]; + hash32_t digest; + for (int i = 0; i < 8; i++) + digest.uint32s[i] = 0; + + // keccak(header..nonce) + hash32_t seed_256 = keccak_f800_progpow(header, nonce, digest); + // endian swap so byte 0 of the hash is the MSB of the value + uint64_t seed = bswap(seed_256[0]) << 32 | bswap(seed_256[1]); + + // initialize mix for all lanes + for (int l = 0; l < PROGPOW_LANES; l++) + fill_mix(seed, l, mix[l]); + + // execute the randomly generated inner loop + for (int i = 0; i < PROGPOW_CNT_DAG; i++) + progPowLoop(prog_seed, i, mix, dag); + + // Reduce mix data to a per-lane 32-bit digest + uint32_t digest_lane[PROGPOW_LANES]; + for (int l = 0; l < PROGPOW_LANES; l++) + { + digest_lane[l] = FNV_OFFSET_BASIS + for (int i = 0; i < PROGPOW_REGS; 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] = FNV_OFFSET_BASIS; + for (int l = 0; l < PROGPOW_LANES; l++) + digest.uint32s[l%8] = fnv1a(digest.uint32s[l%8], digest_lane[l]) + + // keccak(header .. keccak(header..nonce) .. digest); + keccak_f800_progpow(header, seed, digest); } ``` + ## 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. \ No newline at end of file diff --git a/EIPS/eip-1066.md b/EIPS/eip-1066.md index d7df61af6234e0..bfb15d1d2ac902 100644 --- a/EIPS/eip-1066.md +++ b/EIPS/eip-1066.md @@ -3,10 +3,9 @@ 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: Last Call +status: Draft type: Standards Track category: ERC -review-period-end: 2019-02-25 created: 2018-05-05 version: 1.0.0 --- @@ -47,7 +46,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 diff --git a/EIPS/eip-1081.md b/EIPS/eip-1081.md index 5cc921fda78c21..d5a7556c86db4a 100644 --- a/EIPS/eip-1081.md +++ b/EIPS/eip-1081.md @@ -1,13 +1,13 @@ --- eip: 1081 -Title: Standard Bounties -Authors: Mark Beylin , Kevin Owocki , 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 , Kevin Owocki , 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 diff --git a/EIPS/eip-1123.md b/EIPS/eip-1123.md index 3ef991f57759e6..11605fcfebe02b 100644 --- a/EIPS/eip-1123.md +++ b/EIPS/eip-1123.md @@ -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.

See Also

-

Formalized (JSON-Schema) version of this specification: package.spec.json

+

Formalized (JSON-Schema) version of this specification: package.spec.json

Jump To

@@ -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. @@ -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 `-` ex: `0.4.8-commit.60cc1668`. @@ -1435,7 +1435,7 @@ nightly should be denoted in the form of `-` 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).
@@ -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/) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index ae372b930fe4c5..edda721eb36ca2 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -5,6 +5,7 @@ author: Witek Radomski , Andrew Cooke , Phili type: Standards Track category: ERC status: Draft +review-period-end: 2019-03-28 created: 2018-06-17 discussions-to: https://github.com/ethereum/EIPs/issues/1155 requires: 165 @@ -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); } ``` - -## 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 `{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,7 +211,7 @@ 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 `{id}` exists in any JSON value, it MUST be replaced with the actual token ID, by all client software that follows this standard. @@ -275,14 +275,11 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo } ``` -
-Localization +##### Localization -#### 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. -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 Schema ```json { @@ -331,7 +328,7 @@ Metadata localization should be standardized to increase presentation uniformity } ``` -#### Localized Sample +##### Localized Sample Base URI: ```json @@ -362,213 +359,44 @@ fr.json: } ``` -
- -## Approval - -The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval on a subset of tokens, standardized scoped approval is available as an extension. More complex approval schemes will require the use of an external contract enforcing custom rules. - -### Scoped Approval Extension - -This extension enables restrictions on approval's reach using a standardized method. 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. ERC-1155 implementors can define scopes as needed. - -
-Interface - -```solidity -pragma solidity ^0.5.2; - -/** - Note: The ERC-165 identifier for this interface is 0x30168307. -*/ -interface ERC1155ScopedApproval { - /** - @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 shema is similar to the token metadata schema and also allows localization. `{id}` and `{locale}` should be replaced with the proper values. +### Approval -```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/)." - } - } - } - } -} -``` -
+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 -
- -Metadata Choices +### 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. -
- -
- -Upgrades +### 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. -
- -
- -Design decision: Supporting non-batch +### 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. -
- -
- -Design decision: Safe transfers only +### 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. -
- -
- -Guaranteed log trace +### 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. -
- -
- -Approval - ### 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. However, 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. - -Sample use cases for scopes: +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. -* A company may represent it's fleet of vehicles on the blockchain and it could create a scope for each regional office. -* Game developers could share an ERC-1155 contract where each developer manages tokens under a specified scope. -* Tokens of different value magnitude could be split in separate scopes. 0.01Ξ tokens would be kept separate from -10,000.00Ξ tokens. - -
+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. -
- -Batch Operations - ### 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. @@ -579,24 +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. -
- -
- -Enumeration - ### 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. -
- -
- -Non-Fungible Tokens - ### 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. @@ -615,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 ``` -
- ## 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) @@ -639,4 +454,4 @@ balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible tok - [Beyond Gaming - Exploring the Utility of ERC-1155 Token Standard!](https://blockgeeks.com/erc-1155-token/) ## Copyright -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/EIPS/eip-1167.md b/EIPS/eip-1167.md index e0b39ad6cd27ae..4b35d0462aee2d 100644 --- a/EIPS/eip-1167.md +++ b/EIPS/eip-1167.md @@ -7,6 +7,7 @@ status: Final type: Standards Track category: ERC created: 2018-06-22 +requires: 211 --- diff --git a/EIPS/eip-1191.md b/EIPS/eip-1191.md index 871127b51f56cb..7b0149fe6d3789 100644 --- a/EIPS/eip-1191.md +++ b/EIPS/eip-1191.md @@ -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) | diff --git a/EIPS/eip-1193.md b/EIPS/eip-1193.md index 4302426f6d52a9..26fd23fbf3b5f5 100644 --- a/EIPS/eip-1193.md +++ b/EIPS/eip-1193.md @@ -1,13 +1,12 @@ --- eip: 1193 title: Ethereum Provider JavaScript API -author: Ryan Ghods (@ryanio), Marc Garreau (@marcgarreau), Fabian Vogelsteller (@frozeman), Victor Maia (@MaiaVictor) +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 @@ -42,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). @@ -102,10 +110,11 @@ The event emits with `accounts`, an array of the accounts' addresses. ```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']) @@ -119,6 +128,7 @@ ethereum ); }); + // Example 2: Request accounts ethereum .send('eth_requestAccounts') @@ -136,6 +146,7 @@ ethereum ); }); + // Example 3: Log available accounts ethereum .send('eth_accounts') @@ -149,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; @@ -176,6 +188,7 @@ ethereum Code: ${error.code}. Data: ${error.data}` ); }); + // to unsubscribe ethereum .send('eth_unsubscribe', [subId]) @@ -189,6 +202,7 @@ ethereum ); }); + // Example 5: Log when accounts change const logAccounts = accounts => { console.log(`Accounts:\n${accounts.join('\n')}`); @@ -205,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 @@ -237,7 +245,7 @@ The provider **SHOULD** extend from `EventEmitter` to provide dapps flexibility #### 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 diff --git a/EIPS/eip-1234.md b/EIPS/eip-1234.md index e9767df903ad1e..5cf44307ef3793 100644 --- a/EIPS/eip-1234.md +++ b/EIPS/eip-1234.md @@ -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 --- diff --git a/EIPS/eip-1261.md b/EIPS/eip-1261.md index 85314f24e646eb..5645d025a99fd0 100644 --- a/EIPS/eip-1261.md +++ b/EIPS/eip-1261.md @@ -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 diff --git a/EIPS/eip-1283.md b/EIPS/eip-1283.md index 52838fe7939448..7361bdd89eaf83 100644 --- a/EIPS/eip-1283.md +++ b/EIPS/eip-1283.md @@ -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. diff --git a/EIPS/eip-1319.md b/EIPS/eip-1319.md index 1770712d4b4d6a..21d42440a0fdb4 100644 --- a/EIPS/eip-1319.md +++ b/EIPS/eip-1319.md @@ -1,7 +1,7 @@ --- eip: 1319 title: Smart Contract Package Registry Interface -author: Piper Merriam , Christopher Gewecke , g. nicholas d'andrea +author: Piper Merriam , Christopher Gewecke , g. nicholas d'andrea , Nick Gheorghita 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** diff --git a/EIPS/eip-1328.md b/EIPS/eip-1328.md index 4142fa96cf2424..63d61278f0fafd 100644 --- a/EIPS/eip-1328.md +++ b/EIPS/eip-1328.md @@ -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 diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md new file mode 100644 index 00000000000000..e0b8db3cfc9dd5 --- /dev/null +++ b/EIPS/eip-1344.md @@ -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. diff --git a/EIPS/eip-1355.md b/EIPS/eip-1355.md index 94197b684c3886..3dbd4df3f61d18 100644 --- a/EIPS/eip-1355.md +++ b/EIPS/eip-1355.md @@ -1,7 +1,7 @@ --- eip: 1355 title: Ethash 1a -author: Paweł Bylica , Jean M. Cyr [@jean-m-cyr](https://github.com/jean-m-cyr) +author: Paweł Bylica (@chfast) , Jean M. Cyr (@jean-m-cyr) discussions-to: https://ethereum-magicians.org/t/eip-1355-ethash-1a/1167 status: Draft type: Standards Track diff --git a/EIPS/eip-137.md b/EIPS/eip-137.md index 5b0c7b67607753..cc873744bc4feb 100644 --- a/EIPS/eip-137.md +++ b/EIPS/eip-137.md @@ -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:
<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/)
 
-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. diff --git a/EIPS/eip-1418.md b/EIPS/eip-1418.md new file mode 100644 index 00000000000000..6289137a625509 --- /dev/null +++ b/EIPS/eip-1418.md @@ -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. diff --git a/EIPS/eip-1444.md b/EIPS/eip-1444.md index ac3a05a05d138c..b46d4f58e7dcae 100644 --- a/EIPS/eip-1444.md +++ b/EIPS/eip-1444.md @@ -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 diff --git a/EIPS/eip-145.md b/EIPS/eip-145.md index 2fd4657437e504..e3cc659122ac53 100644 --- a/EIPS/eip-145.md +++ b/EIPS/eip-145.md @@ -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 --- diff --git a/EIPS/eip-1474.md b/EIPS/eip-1474.md new file mode 100644 index 00000000000000..8eefc1bf5d0f12 --- /dev/null +++ b/EIPS/eip-1474.md @@ -0,0 +1,2314 @@ +--- +eip: 1474 +title: Remote procedure call specification +author: Paul Bouchon +discussions-to: https://ethereum-magicians.org/t/eip-remote-procedure-call-specification/1537 +status: Draft +type: Standards Track +category: Interface +created: 2018-10-02 +--- + +## Simple Summary + +This proposal defines a standard set of remote procedure call methods that an Ethereum node should implement. + +## Abstract + +Nodes created by the current generation of Ethereum clients expose inconsistent and incompatible remote procedure call (RPC) methods because no formal Ethereum RPC specification exists. This proposal standardizes such a specification to provide developers with a predictable Ethereum RPC interface regardless of underlying node implementation. + +## Specification + +### Concepts + +#### RFC-2119 + +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](https://www.ietf.org/rfc/rfc2119.txt). + +#### JSON-RPC + +Communication with Ethereum nodes is accomplished using [JSON-RPC](https://www.jsonrpc.org/specification), a stateless, lightweight [remote procedure call](https://en.wikipedia.org/wiki/Remote_procedure_call) protocol that uses [JSON](http://www.json.org/) as its data format. Ethereum RPC methods **MUST** be called using [JSON-RPC request objects](https://www.jsonrpc.org/specification#request_object) and **MUST** respond with [JSON-RPC response objects](https://www.jsonrpc.org/specification#response_object). + +#### Error codes + +If an Ethereum RPC method encounters an error, the `error` member included on the response object **MUST** be an object containing a `code` member and descriptive `message` member. The following list contains all possible error codes and associated messages: + +|Code|Message|Meaning|Category| +|-|-|-|-| +|-32700|Parse error|Invalid JSON|standard| +|-32600|Invalid request|JSON is not a valid request object|standard| +|-32601|Method not found|Method does not exist|standard| +|-32602|Invalid params|Invalid method parameters|standard| +|-32603|Internal error|Internal JSON-RPC error|standard| +|-32000|Invalid input|Missing or invalid parameters|non-standard| +|-32001|Resource not found|Requested resource not found|non-standard| +|-32002|Resource unavailable|Requested resource not available|non-standard| +|-32003|Transaction rejected|Transaction creation failed|non-standard| +|-32004|Method not supported|Method is not implemented|non-standard| + +Example error response: + +```sh +{ + "id": 1337 + "jsonrpc": "2.0", + "error": { + "code": -32003, + "message": "Transaction rejected" + } +} +``` + +#### Value encoding + +Specific types of values passed to and returned from Ethereum RPC methods require special encoding: + +##### `Quantity` + +- A `Quantity` value **MUST** be hex-encoded. +- A `Quantity` value **MUST** be "0x"-prefixed. +- A `Quantity` value **MUST** be expressed using the fewest possible hex digits per byte. +- A `Quantity` value **MUST** express zero as "0x0". + +Examples `Quantity` values: + +|Value|Valid|Reason| +|-|-|-| +|0x|`invalid`|empty not a valid quantity| +|0x0|`valid`|interpreted as a quantity of zero| +|0x00|`invalid`|leading zeroes not allowed| +|0x41|`valid`|interpreted as a quantity of 65| +|0x400|`valid`|interpreted as a quantity of 1024| +|0x0400|`invalid`|leading zeroes not allowed| +|ff|`invalid`|values must be prefixed| + + +##### `Data` + +- A `Data` value **MUST** be hex-encoded. +- A `Data` value **MUST** be "0x"-prefixed. +- A `Data` value **MUST** be expressed using two hex digits per byte. + +Examples `Data` values: + +|Value|Valid|Reason| +|-|-|-| +|0x|`valid`|interpreted as empty data| +|0x0|`invalid`|each byte must be represented using two hex digits| +|0x00|`valid`|interpreted as a single zero byte| +|0x41|`true`|interpreted as a data value of 65| +|0x004200|`true`|interpreted as a data value of 16896| +|0xf0f0f|`false`|bytes require two hex digits| +|004200|`false`|values must be prefixed| + +##### Proposing changes + +New Ethereum RPC methods and changes to existing methods **MUST** be proposed via the traditional EIP process. This allows for community consensus around new method implementations and proposed method modifications. RPC method proposals **MUST** reach "draft" status before being added to this proposal and the official Ethereum RPC specification defined herein. + +### Methods + +
+web3_clientVersion + +#### Description + +Returns the version of the current client + +#### Parameters + +_(none)_ + +#### Returns + +{`string`} - client version + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "web3_clientVersion", + "params": [], +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "Mist/v0.9.3/darwin/go1.4.1" +} +``` +--- +
+ +
+web3_sha3 + +#### Description + +Hashes data using the Keccak-256 algorithm + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|data to hash| + +#### Returns + +{[`Data`](#data)} - Keccak-256 hash of the given data + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "web3_sha3", + "params": ["0x68656c6c6f20776f726c64"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc94770007dda54cF92009BFF0dE90c06F603a09f" +} +``` +--- +
+ +
+net_listening + +#### Description + +Determines if this client is listening for new network connections + +#### Parameters + +_(none)_ + +#### Returns + +{`boolean`} - `true` if listening is active or `false` if listening is not active + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "net_listening", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ +
+net_peerCount + +#### Description + +Returns the number of peers currently connected to this client + +#### Parameters + +_(none)_ + +#### Returns + +{[`Quantity`](#quantity)} - number of connected peers + +#### Example +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "net_peerCount", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x2" +} +``` +--- +
+ +
+net_version + +#### Description + +Returns the chain ID associated with the current network + +#### Parameters + +_(none)_ + +#### Returns + +{`string`} - chain ID associated with the current network + +Common chain IDs: + +- `"1"` - Ethereum mainnet +- `"3"` - Ropsten testnet +- `"4"` - Rinkeby testnet +- `"42"` - Kovan testnet + +**Note:** See EIP-155 for a [complete list](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#list-of-chain-ids) of possible chain IDs. + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "net_version", + "params": [], +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "3" +} +``` +--- +
+ +
+eth_accounts + +#### Description + +Returns a list of addresses owned by this client + +#### Parameters + +_(none)_ + +#### Returns + +{[`Data[]`](#data)} - array of addresses + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_accounts", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f"] +} +``` +--- +
+ +
+eth_blockNumber + +#### Description + +Returns the number of the most recent block seen by this client + +#### Parameters + +_(none)_ + +#### Returns + +{[`Quantity`](#quantity)} - number of the latest block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_blockNumber", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc94" +} +``` +--- +
+ +
+eth_call + +#### Description + +Executes a new message call immediately without submitting a transaction to the network + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Data`](#data)} `[from]` - transaction sender
@property {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract
@property {[`Quantity`](#quantity)} `[gas]` - gas provided for transaction execution
@property {[`Quantity`](#quantity)} `[gasPrice]` - price in wei of each gas used
@property {[`Quantity`](#quantity)} `[value]` - value in wei sent with this transaction
@property {[`Data`](#data)} `[data]` - contract code or a hashed method call with encoded args| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Data`](#data)} - return value of executed contract + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_call", + "params": [{ + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x" +} +``` +--- +
+ +
+eth_coinbase + +#### Description + +Returns the coinbase address for this client + +#### Parameters + +_(none)_ + +#### Returns + +{[`Data`](#data)} - coinbase address + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_coinbase", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc94770007dda54cF92009BFF0dE90c06F603a09f" +} +``` +--- +
+ +
+eth_estimateGas + +#### Description + +Estimates the gas necessary to complete a transaction without submitting it to the network + +**Note:** The resulting gas estimation may be significantly more than the amount of gas actually used by the transaction. This is due to a variety of reasons including EVM mechanics and node performance. + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Data`](#data)} `[from]` - transaction sender
@property {[`Data`](#data)} `[to]` - transaction recipient
@property {[`Quantity`](#quantity)} `[gas]` - gas provided for transaction execution
@property {[`Quantity`](#quantity)} `[gasPrice]` - price in wei of each gas used
@property {[`Quantity`](#quantity)} `[value]` - value in wei sent with this transaction
@property {[`Data`](#data)} `[data]` - contract code or a hashed method call with encoded args| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - amount of gas required by transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_estimateGas", + "params": [{ + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x5208" +} +``` +--- +
+ +
+eth_gasPrice + +#### Description + +Returns the current price of gas expressed in wei + +#### Parameters + +_(none)_ + +#### Returns + +{[`Quantity`](#quantity)} - current gas price in wei + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_gasPrice", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x09184e72a000" +} +``` +--- +
+ +
+eth_getBalance + +#### Description + +Returns the balance of an address in wei + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to query for balance| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - balance of the provided account in wei + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x0234c8a3397aab58" +} +``` +--- +
+ +
+eth_getBlockByHash + +#### Description + +Returns information about a block specified by hash + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| +|2|{`boolean`}|`true` will pull full transaction objects, `false` will pull transaction hashes| + +#### Returns + +{`null|object`} - `null` if no block is found, otherwise a block object with the following members: + +- {[`Data`](#data)} `extraData` - "extra data" field of this block +- {[`Data`](#data)} `hash` - block hash or `null` if pending +- {[`Data`](#data)} `logsBloom` - logs bloom filter or `null` if pending +- {[`Data`](#data)} `miner` - address that received this block's mining rewards +- {[`Data`](#data)} `nonce` - proof-of-work hash or `null` if pending +- {[`Data`](#data)} `parentHash` - parent block hash +- {[`Data`](#data)} `receiptsRoot` -root of the this block's receipts trie +- {[`Data`](#data)} `sha3Uncles` - SHA3 of the uncles data in this block +- {[`Data`](#data)} `stateRoot` - root of this block's final state trie +- {[`Data`](#data)} `transactionsRoot` - root of this block's transaction trie +- {[`Quantity`](#quantity)} `difficulty` - difficulty for this block +- {[`Quantity`](#quantity)} `gasLimit` - maximum gas allowed in this block +- {[`Quantity`](#quantity)} `gasUsed` - total used gas by all transactions in this block +- {[`Quantity`](#quantity)} `number` - block number or `null` if pending +- {[`Quantity`](#quantity)} `size` - size of this block in bytes +- {[`Quantity`](#quantity)} `timestamp` - unix timestamp of when this block was collated +- {[`Quantity`](#quantity)} `totalDifficulty` - total difficulty of the chain until this block +- {`Array`} `transactions` - list of transaction objects or hashes +- {`Array`} `uncles` - list of uncle hashes + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBlockByHash", + "params":["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "difficulty": "0x027f07", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x9f759", + "gasUsed": "0x9f759", + "hash": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", + "logsBloom": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", + "miner": "0x4e65fda2159562a496f9f3522f89122a3088497a", + "nonce": "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2", + "number": "0x1b4", + "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": "0x027f07", + "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff", + "timestamp": "0x54e34e8e" + "totalDifficulty": "0x027f07", + "transactions": [] + "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncles": ["0x1606e5...", "0xd5145a9..."] + } +} +``` +--- +
+ +
+eth_getBlockByNumber + +#### Description + +Returns information about a block specified by number + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| +|2|{`boolean`}|`true` will pull full transaction objects, `false` will pull transaction hashes| + +#### Returns + +{`null|object`} - `null` if no block is found, otherwise a block object with the following members: + +- {[`Data`](#data)} `extraData` - "extra data" field of this block +- {[`Data`](#data)} `hash` - block hash or `null` if pending +- {[`Data`](#data)} `logsBloom` - logs bloom filter or `null` if pending +- {[`Data`](#data)} `miner` - address that received this block's mining rewards +- {[`Data`](#data)} `nonce` - proof-of-work hash or `null` if pending +- {[`Data`](#data)} `parentHash` - parent block hash +- {[`Data`](#data)} `receiptsRoot` -root of the this block's receipts trie +- {[`Data`](#data)} `sha3Uncles` - SHA3 of the uncles data in this block +- {[`Data`](#data)} `stateRoot` - root of this block's final state trie +- {[`Data`](#data)} `transactionsRoot` - root of this block's transaction trie +- {[`Quantity`](#quantity)} `difficulty` - difficulty for this block +- {[`Quantity`](#quantity)} `gasLimit` - maximum gas allowed in this block +- {[`Quantity`](#quantity)} `gasUsed` - total used gas by all transactions in this block +- {[`Quantity`](#quantity)} `number` - block number or `null` if pending +- {[`Quantity`](#quantity)} `size` - size of this block in bytes +- {[`Quantity`](#quantity)} `timestamp` - unix timestamp of when this block was collated +- {[`Quantity`](#quantity)} `totalDifficulty` - total difficulty of the chain until this block +- {`Array`} `transactions` - list of transaction objects or hashes +- {`Array`} `uncles` - list of uncle hashes + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params":["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "difficulty": "0x027f07", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x9f759", + "gasUsed": "0x9f759", + "hash": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", + "logsBloom": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", + "miner": "0x4e65fda2159562a496f9f3522f89122a3088497a", + "nonce": "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2", + "number": "0x1b4", + "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": "0x027f07", + "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff", + "timestamp": "0x54e34e8e" + "totalDifficulty": "0x027f07", + "transactions": [] + "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncles": ["0x1606e5...", "0xd5145a9..."] + } +} +``` +--- +
+ +
+eth_getBlockTransactionCountByHash + +#### Description + +Returns the number of transactions in a block specified by block hash + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| + +#### Returns + +{[`Quantity`](#quantity)} - number of transactions in the specified block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByHash", + "params": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc" +} +``` +--- +
+ +
+eth_getBlockTransactionCountByNumber + +#### Description + +Returns the number of transactions in a block specified by block number + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - number of transactions in the specified block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByNumber", + "params": ["0xe8"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xa" +} +``` +--- +
+ +
+eth_getCode + +#### Description + +Returns the contract code stored at a given address + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to query for code| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Data`](#data)} - code from the specified address + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getCode", + "params": ["0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x2"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x600160008035811a818181146012578301005b601b6001356025565b8060005260206000f25b600060078202905091905056" +} +``` +--- +
+ +
+eth_getFilterChanges + +#### Description + +Returns a list of all logs based on filter ID since the last log retrieval + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)}|ID of the filter| + +#### Returns + +{`Array`} - array of log objects with the following members: + +- {[`Data`](#data)} `address` - address from which this log originated +- {[`Data`](#data)} `blockHash` - hash of block containing this log or `null` if pending +- {[`Data`](#data)} `data` - contains the non-indexed arguments of the log +- {[`Data`](#data)} `transactionHash` - hash of the transaction that created this log or `null` if pending +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this log or `null` if pending +- {[`Quantity`](#quantity)} `logIndex` - index of this log within its block or `null` if pending +- {[`Quantity`](#quantity)} `transactionIndex` - index of the transaction that created this log or `null` if pending +- {[`Data[]`](#data)} `topics` - list of order-dependent topics +- {`boolean`} `removed` - `true` if this filter has been destroyed and is invalid + +**Note:** The return value of `eth_getFilterChanges` when retrieving logs from `eth_newBlockFilter` and `eth_newPendingTransactionFilter` filters will be an array of hashes, not an array of Log objects. + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getFilterChanges", + "params": ["0x16"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": [{ + "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockNumber":"0x1b4", + "data":"0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x1", + "topics": [], + "transactionHash": "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf", + "transactionIndex": "0x0" + }] +} +``` +--- +
+ +
+eth_getFilterLogs + +#### Description + +Returns a list of all logs based on filter ID + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)}|ID of the filter| + +#### Returns + +{`Array`} - array of log objects with the following members: + +- {[`Data`](#data)} address - address from which this log originated +- {[`Data`](#data)} blockHash - hash of block containing this log or `null` if pending +- {[`Data`](#data)} data - contains the non-indexed arguments of the log +- {[`Data`](#data)} transactionHash - hash of the transaction that created this log or `null` if pending +- {[`Quantity`](#quantity)} blockNumber - number of block containing this log or `null` if pending +- {[`Quantity`](#quantity)} logIndex - index of this log within its block or `null` if pending +- {[`Quantity`](#quantity)} transactionIndex - index of the transaction that created this log or `null` if pending +- {`Array`} topics - list of order-dependent topics +- {`boolean`} removed - `true` if this filter has been destroyed and is invalid + +**Note:** The return value of `eth_getFilterLogs` when retrieving logs from `eth_newBlockFilter` and `eth_newPendingTransactionFilter` filters will be an array of hashes, not an array of Log objects. + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getFilterLogs", + "params": ["0x16"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": [{ + "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockNumber":"0x1b4", + "data":"0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x1", + "topics": [], + "transactionHash": "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf", + "transactionIndex": "0x0" + }] +} +``` +--- +
+ +
+eth_getLogs + +#### Description + +Returns a list of all logs based on a filter object + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Quantity`](#quantity)\|`string`} `[fromBlock]` - block number, or one of `"latest"`, `"earliest"` or `"pending"`
@property {[`Quantity`](#quantity)\|`string`} `[toBlock]` - block number, or one of `"latest"`, `"earliest"` or `"pending"`
@property {[`Data`](#data)\|[`Data[]`](#data)} `[address]` - contract address or a list of addresses from which logs should originate
@property {[`Data[]`](#data)} `[topics]` - list of order-dependent topics
@property {[`Data`](#data)} `[blockhash]` - restrict logs to a block by hash| + +**Note:** If `blockhash` is passed, neither `fromBlock` nor `toBlock` are allowed or respected. + +#### Returns + +{`Array`} - array of log objects with the following members: + +- {[`Data`](#data)} `address` - address from which this log originated +- {[`Data`](#data)} `blockHash` - hash of block containing this log or `null` if pending +- {[`Data`](#data)} `data` - contains the non-indexed arguments of the log +- {[`Data`](#data)} `transactionHash` - hash of the transaction that created this log or `null` if pending +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this log or `null` if pending +- {[`Quantity`](#quantity)} `logIndex` - index of this log within its block or `null` if pending +- {[`Quantity`](#quantity)} `transactionIndex` - index of the transaction that created this log or `null` if pending +- {[`Data`](#data)} `topics` - list of order-dependent topics +- {`boolean`} `removed` - `true` if this filter has been destroyed and is invalid + +**Note:** The return value of `eth_getLogs` when retrieving logs from `eth_newBlockFilter` and `eth_newPendingTransactionFilter` filters will be an array of hashes, not an array of Log objects. + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getLogs", + "params": [{ + "topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"] + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": [{ + "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockNumber":"0x1b4", + "data":"0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x1", + "topics": [], + "transactionHash": "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf", + "transactionIndex": "0x0" + }] +} +``` +--- +
+ +
+eth_getStorageAt + +#### Description + +Returns the value from a storage position at an address + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address of stored data| +|2|{[`Quantity`](#quantity)}|index into stored data| +|3|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Data`](#data)} - value stored at the given address and data index + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getStorageAt", + "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0", "latest"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x00000000000000000000000000000000000000000000000000000000000004d2" +} +``` +--- +
+ +
+eth_getTransactionByBlockHashAndIndex + +#### Description + +Returns information about a transaction specified by block hash and transaction index + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| +|2|{[`Quantity`](#quantity)}|index of a transaction in the specified block| + +#### Returns + +{`null|object`} - `null` if no transaction is found, otherwise a transaction object with the following members: + +- {[`Data`](#data)} `r` - ECDSA signature r +- {[`Data`](#data)} `s` - ECDSA signature s +- {[`Data`](#data)} `blockHash` - hash of block containing this transaction or `null` if pending +- {[`Data`](#data)} `from` - transaction sender +- {[`Data`](#data)} `hash` - hash of this transaction +- {[`Data`](#data)} `input` - contract code or a hashed method call +- {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract +- {[`Quantity`](#quantity)} `v` - ECDSA recovery ID +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this transaction or `null` if pending +- {[`Quantity`](#quantity)} `gas` - gas provided for transaction execution +- {[`Quantity`](#quantity)} `gasPrice` - price in wei of each gas used +- {[`Quantity`](#quantity)} `nonce` - unique number identifying this transaction +- {[`Quantity`](#quantity)} `transactionIndex` - index of this transaction in the block or `null` if pending +- {[`Quantity`](#quantity)} `value` - value in wei sent with this transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionByBlockHashAndIndex", + "params":["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", "0x0"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", + "blockNumber": "0x5daf3b", + "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d", + "gas": "0xc350", + "gasPrice": "0x4a817c800", + "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", + "input": "0x68656c6c6f21", + "nonce": "0x15", + "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", + "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", + "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb", + "transactionIndex": "0x41", + "v": "0x25", + "value": "0xf3dbb76162000" + } +} +``` +--- +
+ +
+eth_getTransactionByBlockNumberAndIndex + +#### Description + +Returns information about a transaction specified by block number and transaction index + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| +|2|{[`Quantity`](#quantity)}|index of a transaction in the specified block| + +#### Returns + +{`null|object`} - `null` if no transaction is found, otherwise a transaction object with the following members: + +- {[`Data`](#data)} `r` - ECDSA signature r +- {[`Data`](#data)} `s` - ECDSA signature s +- {[`Data`](#data)} `blockHash` - hash of block containing this transaction or `null` if pending +- {[`Data`](#data)} `from` - transaction sender +- {[`Data`](#data)} `hash` - hash of this transaction +- {[`Data`](#data)} `input` - contract code or a hashed method call +- {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract +- {[`Quantity`](#quantity)} `v` - ECDSA recovery ID +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this transaction or `null` if pending +- {[`Quantity`](#quantity)} `gas` - gas provided for transaction execution +- {[`Quantity`](#quantity)} `gasPrice` - price in wei of each gas used +- {[`Quantity`](#quantity)} `nonce` - unique number identifying this transaction +- {[`Quantity`](#quantity)} `transactionIndex` - index of this transaction in the block or `null` if pending +- {[`Quantity`](#quantity)} `value` - value in wei sent with this transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionByBlockNumberAndIndex", + "params":["0x29c", "0x0"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", + "blockNumber": "0x5daf3b", + "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d", + "gas": "0xc350", + "gasPrice": "0x4a817c800", + "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", + "input": "0x68656c6c6f21", + "nonce": "0x15", + "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", + "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", + "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb", + "transactionIndex": "0x41", + "v": "0x25", + "value": "0xf3dbb76162000" + } +} +``` +--- +
+ +
+eth_getTransactionByHash + +#### Description + +Returns information about a transaction specified by hash + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a transaction| + +#### Returns + +{`null|object`} - `null` if no transaction is found, otherwise a transaction object with the following members: + +- {[`Data`](#data)} `r` - ECDSA signature r +- {[`Data`](#data)} `s` - ECDSA signature s +- {[`Data`](#data)} `blockHash` - hash of block containing this transaction or `null` if pending +- {[`Data`](#data)} `from` - transaction sender +- {[`Data`](#data)} `hash` - hash of this transaction +- {[`Data`](#data)} `input` - contract code or a hashed method call +- {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract +- {[`Quantity`](#quantity)} `v` - ECDSA recovery ID +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this transaction or `null` if pending +- {[`Quantity`](#quantity)} `gas` - gas provided for transaction execution +- {[`Quantity`](#quantity)} `gasPrice` - price in wei of each gas used +- {[`Quantity`](#quantity)} `nonce` - unique number identifying this transaction +- {[`Quantity`](#quantity)} `transactionIndex` - index of this transaction in the block or `null` if pending +- {[`Quantity`](#quantity)} `value` - value in wei sent with this transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionByHash", + "params": ["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", + "blockNumber": "0x5daf3b", + "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d", + "gas": "0xc350", + "gasPrice": "0x4a817c800", + "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", + "input": "0x68656c6c6f21", + "nonce": "0x15", + "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", + "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", + "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb", + "transactionIndex": "0x41", + "v": "0x25", + "value": "0xf3dbb76162000" + } +} +``` +--- +
+ +
+eth_getTransactionCount + +#### Description + +Returns the number of transactions sent from an address + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to query for sent transactions| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - number of transactions sent from the specified address + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_getTransactionReceipt + +#### Description + +Returns the receipt of a transaction specified by hash + +**Note:** Transaction receipts are unavailable for pending transactions. + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a transaction| + +#### Returns + +{`null|object`} - `null` if no transaction is found, otherwise a transaction receipt object with the following members: + +- {[`Data`](#data)} `blockHash` - hash of block containing this transaction +- {[`Data`](#data)} `contractAddress` - address of new contract or `null` if no contract was created +- {[`Data`](#data)} `from` - transaction sender +- {[`Data`](#data)} `logsBloom` - logs bloom filter +- {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract +- {[`Data`](#data)} `transactionHash` - hash of this transaction +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this transaction +- {[`Quantity`](#quantity)} `cumulativeGasUsed` - gas used by this and all preceding transactions in this block +- {[`Quantity`](#quantity)} `gasUsed` - gas used by this transaction +- {[`Quantity`](#quantity)} `status` - `1` if this transaction was successful or `0` if it failed +- {[`Quantity`](#quantity)} `transactionIndex` - index of this transaction in the block +- {`Array`} `logs` - list of log objects generated by this transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b', + "blockNumber": '0xb', + "contractAddress": '0xb60e8dd61c5d32be8058bb8eb970870f07233155', + "cumulativeGasUsed": '0x33bc', + "gasUsed": '0x4dc', + "logs": [], + "logsBloom": "0x00...0", + "status": "0x1", + "transactionHash": '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238', + "transactionIndex": '0x1' + } +} +``` +--- +
+ +
+eth_getUncleByBlockHashAndIndex + +#### Description + +Returns information about an uncle specified by block hash and uncle index position + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| +|2|{[`Quantity`](#quantity)}|index of uncle| + +#### Returns + +{`null|object`} - `null` if no block or uncle is found, otherwise an uncle object with the following members: + +- {[`Data`](#data)} `extraData` - "extra data" field of this block +- {[`Data`](#data)} `hash` - block hash or `null` if pending +- {[`Data`](#data)} `logsBloom` - logs bloom filter or `null` if pending +- {[`Data`](#data)} `miner` - address that received this block's mining rewards +- {[`Data`](#data)} `nonce` - proof-of-work hash or `null` if pending +- {[`Data`](#data)} `parentHash` - parent block hash +- {[`Data`](#data)} `receiptsRoot` -root of the this block's receipts trie +- {[`Data`](#data)} `sha3Uncles` - SHA3 of the uncles data in this block +- {[`Data`](#data)} `stateRoot` - root of this block's final state trie +- {[`Data`](#data)} `transactionsRoot` - root of this block's transaction trie +- {[`Quantity`](#quantity)} `difficulty` - difficulty for this block +- {[`Quantity`](#quantity)} `gasLimit` - maximum gas allowed in this block +- {[`Quantity`](#quantity)} `gasUsed` - total used gas by all transactions in this block +- {[`Quantity`](#quantity)} `number` - block number or `null` if pending +- {[`Quantity`](#quantity)} `size` - size of this block in bytes +- {[`Quantity`](#quantity)} `timestamp` - unix timestamp of when this block was collated +- {[`Quantity`](#quantity)} `totalDifficulty` - total difficulty of the chain until this block +- {`Array`} `uncles` - list of uncle hashes + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getUncleByBlockHashAndIndex", + "params": ["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "0x0"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b', + "blockNumber": '0xb', + "contractAddress": '0xb60e8dd61c5d32be8058bb8eb970870f07233155', + "cumulativeGasUsed": '0x33bc', + "gasUsed": '0x4dc', + "logs": [], + "logsBloom": "0x00...0", + "status": "0x1", + "transactionHash": '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238', + "transactionIndex": '0x1' + } +} +``` +--- +
+ +
+eth_getUncleByBlockNumberAndIndex + +#### Description + +Returns information about an uncle specified by block number and uncle index position + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| +|2|{[`Quantity`](#quantity)}|index of uncle| + +#### Returns + +{`null|object`} - `null` if no block or uncle is found, otherwise an uncle object with the following members: + +- {[`Data`](#data)} `extraData` - "extra data" field of this block +- {[`Data`](#data)} `hash` - block hash or `null` if pending +- {[`Data`](#data)} `logsBloom` - logs bloom filter or `null` if pending +- {[`Data`](#data)} `miner` - address that received this block's mining rewards +- {[`Data`](#data)} `nonce` - proof-of-work hash or `null` if pending +- {[`Data`](#data)} `parentHash` - parent block hash +- {[`Data`](#data)} `receiptsRoot` -root of the this block's receipts trie +- {[`Data`](#data)} `sha3Uncles` - SHA3 of the uncles data in this block +- {[`Data`](#data)} `stateRoot` - root of this block's final state trie +- {[`Data`](#data)} `transactionsRoot` - root of this block's transaction trie +- {[`Quantity`](#quantity)} `difficulty` - difficulty for this block +- {[`Quantity`](#quantity)} `gasLimit` - maximum gas allowed in this block +- {[`Quantity`](#quantity)} `gasUsed` - total used gas by all transactions in this block +- {[`Quantity`](#quantity)} `number` - block number or `null` if pending +- {[`Quantity`](#quantity)} `size` - size of this block in bytes +- {[`Quantity`](#quantity)} `timestamp` - unix timestamp of when this block was collated +- {[`Quantity`](#quantity)} `totalDifficulty` - total difficulty of the chain until this block +- {`Array`} `uncles` - list of uncle hashes + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getUncleByBlockNumberAndIndex", + "params": ["0x29c", "0x0"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b', + "blockNumber": '0xb', + "contractAddress": '0xb60e8dd61c5d32be8058bb8eb970870f07233155', + "cumulativeGasUsed": '0x33bc', + "gasUsed": '0x4dc', + "logs": [], + "logsBloom": "0x00...0", + "status": "0x1", + "transactionHash": '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238', + "transactionIndex": '0x1' + } +} +``` +--- +
+ +
+eth_getUncleCountByBlockHash + +#### Description + +Returns the number of uncles in a block specified by block hash + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| + +#### Returns + +{[`Quantity`](#quantity)} - number of uncles in the specified block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockHash", + "params": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc" +} +``` +--- +
+ +
+eth_getUncleCountByBlockNumber + +#### Description + +Returns the number of uncles in a block specified by block number + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - number of uncles in the specified block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockNumber", + "params": ["0xe8"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_getWork + +#### Description + +Returns a list containing relevant information for proof-of-work + +#### Parameters + +_none_ + +#### Returns + +{[`Data[]`](#data)} - array with the following items: + +1. {[`Data`](#data)} - current block header pow-hash +1. {[`Data`](#data)} - seed hash used for the DAG +1. {[`Data`](#data)} - boundary condition ("target"), 2^256 / difficulty + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getWork", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": [ + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + "0x5EED00000000000000000000000000005EED0000000000000000000000000000", + "0xd1ff1c01710000000000000000000000d1ff1c01710000000000000000000000" + ] +} +``` +--- +
+ +
+eth_hashrate + +#### Description + +Returns the number of hashes-per-second this node is mining at + +#### Parameters + +_(none)_ + +#### Returns + +{[`Quantity`](#quantity)} - number of hashes-per-second + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_hashrate", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x38a" +} +``` +--- +
+ +
+eth_mining + +#### Description + +Determines if this client is mining new blocks + +#### Parameters + +_(none)_ + +#### Returns + +{`boolean`} - `true` if this client is mining or `false` if it is not mining + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_mining", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ +
+eth_newBlockFilter + +#### Description + +Creates a filter to listen for new blocks that can be used with `eth_getFilterChanges` + +#### Parameters + +_none_ + +#### Returns + +{[`Quantity`](#quantity)} - ID of the newly-created filter that can be used with `eth_getFilterChanges` + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "eth_newBlockFilter", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_newFilter + +#### Description + +Creates a filter to listen for specific state changes that can then be used with `eth_getFilterChanges` + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Quantity`](#quantity)\|`string`} `[fromBlock]` - block number, or one of `"latest"`, `"earliest"` or `"pending"`
@property {[`Quantity`](#quantity)\|`string`} `[toBlock]` - block number, or one of `"latest"`, `"earliest"` or `"pending"`
@property {[`Data`](#data)\|[`Data[]`](#data)} `[address]` - contract address or a list of addresses from which logs should originate
@property {[`Data[]`](#data)} `[topics]` - list of order-dependent topics| + +**Note:** Topics are order-dependent. A transaction with a log with topics `[A, B]` will be matched by the following topic filters: +- `[]` - "anything" +- `[A]` - "A in first position (and anything after)" +- `[null, B]` - "anything in first position AND B in second position (and anything after)" +- `[A, B]` - "A in first position AND B in second position (and anything after)" +- `[[A, B], [A, B]]` - "(A OR B) in first position AND (A OR B) in second position (and anything after)" + +#### Returns + +{[`Quantity`](#quantity)} - ID of the newly-created filter that can be used with `eth_getFilterChanges` + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "eth_newFilter", + "params": [{ + "topics": ["0x0000000000000000000000000000000000000000000000000000000012341234"] + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_newPendingTransactionFilter + +#### Description + +Creates a filter to listen for new pending transactions that can be used with `eth_getFilterChanges` + +#### Parameters + +_none_ + +#### Returns + +{[`Quantity`](#quantity)} - ID of the newly-created filter that can be used with `eth_getFilterChanges` + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "eth_newPendingTransactionFilter", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_protocolVersion + +#### Description + +Returns the current Ethereum protocol version + +#### Parameters + +_(none)_ + +#### Returns + +{`string`} - current Ethereum protocol version + +#### Example +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_protocolVersion", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "54" +} +``` +--- +
+ +
+eth_sendRawTransaction + +#### Description + +Sends and already-signed transaction to the network + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|signed transaction data| + +#### Returns + +{[`Data`](#data)} - transaction hash, or the zero hash if the transaction is not yet available + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_sendRawTransaction", + "params": ["0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" +} +``` +--- +
+ +
+eth_sendTransaction + +#### Description + +Creates, signs, and sends a new transaction to the network + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Data`](#data)} `from` - transaction sender
@property {[`Data`](#data)} `[to]` - transaction recipient
@property {[`Quantity`](#quantity)} `[gas="0x15f90"]` - gas provided for transaction execution
@property {[`Quantity`](#quantity)} `[gasPrice]` - price in wei of each gas used
@property {[`Quantity`](#quantity)} `[value]` - value in wei sent with this transaction
@property {[`Data`](#data)} `[data]` - contract code or a hashed method call with encoded args
@property {[`Quantity`](#quantity)} `[nonce]` - unique number identifying this transaction| + +#### Returns + +{[`Data`](#data)} - transaction hash, or the zero hash if the transaction is not yet available + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_sendTransaction", + "params": [{ + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" +} +``` +--- +
+ +
+eth_sign + +#### Description + +Calculates an Ethereum-specific signature in the form of `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))` + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to use for signing| +|2|{[`Data`](#data)}|data to sign| + +#### Returns + +{[`Data`](#data)} - signature hash of the provided data + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_sign", + "params": ["0x9b2055d370f73ec7d8a03e965129118dc8f5bf83", "0xdeadbeaf"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b" +} +``` +--- +
+ +
+eth_signTransaction + +#### Description + +Signs a transaction that can be submitted to the network at a later time using with `eth_sendRawTransaction` + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Data`](#data)} `from` - transaction sender
@property {[`Data`](#data)} `[to]` - transaction recipient
@property {[`Quantity`](#quantity)} `[gas="0x15f90"]` - gas provided for transaction execution
@property {[`Quantity`](#quantity)} `[gasPrice]` - price in wei of each gas used
@property {[`Quantity`](#quantity)} `[value]` - value in wei sent with this transaction
@property {[`Data`](#data)} `[data]` - contract code or a hashed method call with encoded args
@property {[`Quantity`](#quantity)} `[nonce]` - unique number identifying this transaction| + +#### Returns + +{[`Data`](#data)} - signature hash of the transaction object + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_signTransaction", + "params": [{ + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b" +} +``` +--- +
+ +
+eth_signTypedData + +#### Description + +Calculates an Ethereum-specific signature in the form of `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))` + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to use for signing| +|2|{[`Data`](#data)}|message to sign containing type information, a domain separator, and data| + +**Note:** Client developers should refer to EIP-712 for complete semantics around [encoding and signing data](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#specification). Dapp developers should refer to EIP-712 for the expected structure of [RPC method input parameters](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#parameters). + +#### Returns + +{[`Data`](#data)} - signature hash of the provided message + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "eth_signTypedData", + "params": ["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", { + "types": { + "EIP712Domain": [{ + "name": "name", + "type": "string" + }, { + "name": "version", + "type": "string" + }, { + "name": "chainId", + "type": "uint256" + }, { + "name": "verifyingContract", + "type": "address" + }], + "Person": [{ + "name": "name", + "type": "string" + }, { + "name": "wallet", + "type": "address" + }], + "Mail": [{ + "name": "from", + "type": "Person" + }, { + "name": "to", + "type": "Person" + }, { + "name": "contents", + "type": "string" + }] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c" +} +``` +--- +
+ +
+eth_submitHashrate + +#### Description + +Submit a mining hashrate + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash rate| +|2|{[`Data`](#data)}|random ID identifying this node| + +#### Returns + +{`boolean`} - `true` if submitting went through successfully, `false` otherwise + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_submitHashrate", + "params": [ + "0x0000000000000000000000000000000000000000000000000000000000500000", + "0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c" + ] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ +
+eth_submitWork + +#### Description + +Submit a proof-of-work solution + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|nonce found| +|2|{[`Data`](#data)}|header's pow-hash| +|3|{[`Data`](#data)}|mix digest| + +#### Returns + +{`boolean`} - `true` if the provided solution is valid, `false` otherwise + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_submitWork", + "params": [ + "0x0000000000000001", + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + "0xD1GE5700000000000000000000000000D1GE5700000000000000000000000000" + ] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ + +
+eth_syncing + +#### Description + +Returns information about the status of this client's network synchronization + +#### Parameters + +_(none)_ + +#### Returns + +{`boolean|object`} - `false` if this client is not syncing with the network, otherwise an object with the following members: + +- {[`Quantity`](#quantity)} `currentBlock` - number of the most-recent block synced +- {[`Quantity`](#quantity)} `highestBlock` - number of latest block on the network +- {[`Quantity`](#quantity)} `startingBlock` - block number at which syncing started + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_syncing", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "currentBlock": '0x386', + "highestBlock": '0x454', + "startingBlock": '0x384' + } +} +``` +--- +
+ +
+eth_uninstallFilter + +#### Description + +Destroys a filter based on filter ID + +**Note:** This should only be called if a filter and its notifications are no longer needed. This will also be called automatically on a filter if its notifications are not retrieved using `eth_getFilterChanges` for a period of time. + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)}|ID of the filter to destroy| + +#### Returns + +{`boolean`} - `true` if the filter is found and successfully destroyed or `false` if it is not + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_uninstallFilter", + "params": ["0xb"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ +## Rationale + +Much of Ethereum's effectiveness as an enterprise-grade application platform depends on its ability to provide a reliable and predictable developer experience. Nodes created by the current generation of Ethereum clients expose RPC endpoints with differing method signatures; this forces applications to work around method inconsistencies to maintain compatibility with various Ethereum RPC implementations. + +Both Ethereum client developers and downstream dapp developers lack a formal Ethereum RPC specification. This proposal standardizes such a specification in a way that's versionable and modifiable through the traditional EIP process. + +## Backwards compatibility + +This proposal impacts Ethereum client developers by requiring that any exposed RPC interface adheres to this specification. This proposal impacts dapp developers by requiring that any RPC calls currently used in applications are made according to this specification. + +## Implementation + +The current generation of Ethereum clients includes several implementations that attempt to expose this RPC specification: + +|Client Name|Language|Homepage| +|-|-|-| +|Geth|Go|[geth.ethereum.org](https://geth.ethereum.org)| +|Parity|Rust|[parity.io/ethereum](https://parity.io/ethereum)| +|Aleth|C++|[cpp-ethereum.org](https://cpp-ethereum.org)| + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/EIPS/eip-1485.md b/EIPS/eip-1485.md new file mode 100644 index 00000000000000..716455caf8eca6 --- /dev/null +++ b/EIPS/eip-1485.md @@ -0,0 +1,200 @@ +--- +eip: 1485 +title: TEthashV1 +author: trustfarm (KT Ahn - 안씨아저씨) , , +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/). diff --git a/EIPS/eip-1538.md b/EIPS/eip-1538.md new file mode 100644 index 00000000000000..d3d895a5613f83 --- /dev/null +++ b/EIPS/eip-1538.md @@ -0,0 +1,474 @@ +--- +eip: 1538 +title: Transparent Contract Standard +author: Nick Mudge +discussions-to: https://github.com/ethereum/EIPs/issues/1538 +status: Draft +type: Standards Track +category: ERC +created: 2018-10-31 +--- + + +## Simple Summary + +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 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 + +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 + + +> **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. + + +### 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 + + +### 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 + +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 + +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/). diff --git a/EIPS/eip-155.md b/EIPS/eip-155.md index 495fb7cd2941dc..52324ad10820a8 100644 --- a/EIPS/eip-155.md +++ b/EIPS/eip-155.md @@ -60,15 +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 | -| 43568 | Gangnam | -| 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). \ No newline at end of file diff --git a/EIPS/eip-1613.md b/EIPS/eip-1613.md index 0dd558e345740b..7ed7b64c2a6dbb 100644 --- a/EIPS/eip-1613.md +++ b/EIPS/eip-1613.md @@ -87,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`: diff --git a/EIPS/eip-162.md b/EIPS/eip-162.md index 02f6b13f4aade1..60cec465991f91 100644 --- a/EIPS/eip-162.md +++ b/EIPS/eip-162.md @@ -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 diff --git a/EIPS/eip-1620.md b/EIPS/eip-1620.md new file mode 100644 index 00000000000000..fc127e91266fca --- /dev/null +++ b/EIPS/eip-1620.md @@ -0,0 +1,308 @@ +--- +eip: 1620 +title: ERC-1620 Money Streaming +author: Paul Berg (@PaulRBerg) +discussions-to: https://github.com/ethereum/EIPs/issues/1620 +status: Draft +type: Standards Track +category: ERC +created: 2018-11-24 +--- + + + +## Simple Summary + +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 + +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 + +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 + + +
Expand + +### 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) +``` + +
+ +## Rationale + + +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 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 + + +- [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/). \ No newline at end of file diff --git a/EIPS/eip-165.md b/EIPS/eip-165.md index 666c3bb2719137..5d333aab4f91e7 100644 --- a/EIPS/eip-165.md +++ b/EIPS/eip-165.md @@ -30,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: diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index a76073d22f0f0d..5236fb84073286 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -5,6 +5,7 @@ author: Alex Beregszaszi (@axic), Afri Schoedon (@5chdn) type: Meta status: Draft created: 2019-01-04 +requires: 1716 --- ## Abstract @@ -17,6 +18,10 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - Activation: TBD - Included EIPs: TBD +## References + +TBA + ## Copyright Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/EIPS/eip-1681.md b/EIPS/eip-1681.md new file mode 100644 index 00000000000000..2e557f28cbf73a --- /dev/null +++ b/EIPS/eip-1681.md @@ -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/). + diff --git a/EIPS/eip-1702.md b/EIPS/eip-1702.md new file mode 100644 index 00000000000000..1dc088d2a76f97 --- /dev/null +++ b/EIPS/eip-1702.md @@ -0,0 +1,188 @@ +--- +eip: 1702 +title: Generalized Account Versioning Scheme +author: Wei Tang (@sorpaas) +discussions-to: https://github.com/sorpaas/EIPs/issues/2 +status: Draft +type: Standards Track +category: Core +created: 2017-12-30 +--- + +## Simple Summary + +Introduce account versioning for smart contracts so upgrading the VM +or introducing new VMs can be easier. + +## Abstract + +This defines a method of hard forking while maintaining the exact +functionality of existing account by allowing multiple versions of the +virtual machines to execute in the same block. This is also useful to +define future account state structures when we introduce the on-chain +WebAssembly virtual machine. + +## Motivation + +By allowing account versioning, we can execute different virtual +machine for contracts created at different times. This allows breaking +features to be implemented while making sure existing contracts work +as expected. + +Note that this specification might not apply to all hard forks. We +have emergency hard forks in the past due to network attacks. Whether +they should maintain existing account compatibility should be +evaluated in individual basis. If the attack can only be executed once +against some particular contracts, then the scheme defined here might +still be applicable. Otherwise, having a plain emergency hard fork +might still be a good idea. + +## Specification + +### Account State + +Re-define account state stored in the world state trie to have 5 +items: `nonce`, `balance`, `storageRoot`, `codeHash`, and +`version`. The newly added field `version` is a 256-bit integer. When +`version` is zero, the account is RLP-encoded with the first 4 +items. When `version` is not zero, the account is RLP-encoded with 5 +items. + +### Contract Deployment + +In Ethereum, a contract has a deployment method, either by a contract +creation transaction, or by another contract. If we regard this +deployment method a contract's *parent*, then we find them forming a +family of contracts, with the *root* being a contract creation +transaction. + +We let a family of contracts to always have the same `version`. That +is, `CREATE` and `CREATE2` will always deploy contract that has the +same `version` as the calling `address`. + +#### Alternative Design + +This provides an alternative design that allows `CREATE`, `CREATE2` +and contract creation transaction to deploy contract whose version are +different. + +The client maintains a mapping `V` of currently supported version +prefix (for example, `\0asm`) to `version` number. All version +prefixes have the invariant that given any prefix in mapping `a` and +`b`, `a` is not `b`'s prefix. Version numbers in `V` cannot be zero. + +Apply the following cause on contract deployment for all `CREATE`, +`CREATE2` and contract deployment transaction. + +* If the `version` of caller (determined by `I_a`) is zero, then + `CREATE` and `CREATE2` will always deploy contract with version zero. +* If the `version` of caller (determined by `I_a`) is not zero, do the + following checks and operations, and return out-of-gas if any of it + fails: + * Check that the code starts with an prefix in `V`, with `version` + number. + * Use `version`'s validation procedure to validate the *whole* code + (with prefix). + * Deploy the contract with `version`. + +### Validation + +A new phrase, *validation* is added to contract deployment (by +`CREATE` / `CREATE2` opcodes, or by contract creation +transaction). When `version` is `0`, the phrase does nothing and +always succeeds. Future VM versions can define additional validation +that has to be passed. + +If the validation phrase fails, deployment does not proceed and return +out-of-gas. + +### Contract Execution + +VM version used in contract execution is determined via calling +`address` (`I_a` in yellow paper). + +### Contract Creation Transaction + +Define `LATEST_VERSION` in a hard fork to be the latest supported VM +version. A contract creation transaction is always executed in +`LATEST_VERSION`. Before a contract creation transaction is executed, +run *validation* on the contract creation code. If it does not pass, +return out-of-gas. + +#### Alternative Design + +This provides an alternative design that allows contract to be created +in multiple versions. + +Add an additional field `version` (256-bit integer) in contract +creation transaction. So it becomes `nonce`, `gasprice`, `startgas`, +`to`, `value`, `data`, `v`, `r`, `s`, `version`. When signing or +recovering, sign ten items, with `v`, `r`, `s` as defined by EIP-155. + +The transaction would be executed in `version` supplied. If `version` +is not supported or *validation* does not pass, return out-of-gas. + +### Precompiled Contract and Externally-owned Address + +Precompiled contracts and externally-owned addresses do not have +`version`. If a message-call transaction or `CALL` / `CALLCODE` / +`STATICCALL` / `DELEGATECALL` touches a new externally-owned address +or a non-existing precompiled contract address, it is always created +with `version` field being `0`. + +## Rationale + +This introduces account versioning via a new RLP item in account +state. The first design above gets account versioning by making the +contract *family* always have the same version. In this way, versions +are only needed to be provided by contract creation transaction, and +there is no restrictions on formats of code for any version. If we +want to support multiple newest VMs (for example, EVM and WebAssembly +running together), then this requires alternative design in contract +creation transaction section + +The second design above requires new versions of VMs follow a +formatting -- that it always has a prefix. In this way, the version +can be derived from the prefix, thus allowing a contract *family* to +have multiple versions. It also makes it so that we can pin contract +creation transaction using only one VM version, and it can deploy +other VM versions. + +Alternatively, account versioning can also be done through: + +* **EIP-1707** and **EIP-1712**: This makes an account's versioning + soly dependent on its code header prefix. If with only EIP-1707, it + is not possible to certify any code is valid, because current VM + allows treating code as data. This can be fixed by EIP-1712, but the + drawback is that it's potentially backward incompatible. +* **EIP-1891**: Instead of writing version field into account RLP + state, we write it in a separate contract. This can accomplish the + same thing as this EIP and potentially reduces code complexity, but + the drawback is that every code execution will require an additional + trie traversal, which impacts performance. + +## Backwards Compatibility + +Account versioning is fully backwards compatible, and it does not +change how current contracts are executed. + +## Discussions + +### Performance + +Currently nearly all full node implementations uses config parameters +to decide which virtual machine version to use. Switching vitual +machine version is simply an operation that changes a pointer using a +different set of config parameters. As a result, this scheme has +nearly zero impact to performance. + +### WebAssembly + +This scheme can also be helpful when we deploy on-chain WebAssembly +virtual machine. In that case, WASM contracts and EVM contracts can +co-exist and the execution boundary and interaction model are clearly +defined as above. + +## Test Cases and Implementations + +To be added. diff --git a/EIPS/eip-1706.md b/EIPS/eip-1706.md index affd8195670530..7d8ec43c9ae328 100644 --- a/EIPS/eip-1706.md +++ b/EIPS/eip-1706.md @@ -1,13 +1,13 @@ --- eip: 1706 title: Disable SSTORE with gasleft lower than call stipend -author: Alex Forshtat (alex@tabookey.com), Yoav Weiss (yoav@tabookey.com) +author: Alex Forshtat , Yoav Weiss discussions-to: https://github.com/alex-forshtat-tbk/EIPs/issues/1 status: Draft -type: Standards Track (Core, Networking, Interface, ERC) -category (*only required for Standard Track): Core +type: Standards Track +category: Core created: 2019-01-15 -requires (*optional): 1283 +requires: 1283 --- diff --git a/EIPS/eip-1716.md b/EIPS/eip-1716.md new file mode 100644 index 00000000000000..adda1b4e4f7571 --- /dev/null +++ b/EIPS/eip-1716.md @@ -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/). diff --git a/EIPS/eip-1761.md b/EIPS/eip-1761.md new file mode 100644 index 00000000000000..7b4057e16eae76 --- /dev/null +++ b/EIPS/eip-1761.md @@ -0,0 +1,175 @@ +--- +eip: 1761 +title: ERC-1761 Scoped Approval Interface +author: Witek Radomski , Andrew Cooke , James Therien , Eric Binet +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/). diff --git a/EIPS/eip-1767.md b/EIPS/eip-1767.md index 21f5f195e67805..02a9246ee3e9ec 100644 --- a/EIPS/eip-1767.md +++ b/EIPS/eip-1767.md @@ -219,6 +219,13 @@ type Block { 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. @@ -289,25 +296,32 @@ type SyncState{ 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 { - # Account fetches an Ethereum account at the specified block number. - # If blockNumber is not provided, it defaults to the most recent block. - account(address: Address!, blockNumber: Long): Account! # 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 - # Call executes a local call operation. If blockNumber is not specified, - # it defaults to the most recent known block. - call(data: CallData!, blockNumber: Long): CallResult - # EstimateGas estimates the amount of gas that will be required for - # successful execution of a transaction. If blockNumber is not specified, - # it defaults to the most recent known block. - estimateGas(data: CallData!, blockNumber: Long): Long! # Logs returns log entries matching the provided filter. logs(filter: FilterCriteria!): [Log!]! # GasPrice returns the node's estimate of a gas price sufficient to diff --git a/EIPS/eip-1812.md b/EIPS/eip-1812.md new file mode 100644 index 00000000000000..11d4bd4790875f --- /dev/null +++ b/EIPS/eip-1812.md @@ -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/_). diff --git a/EIPS/eip-1820.md b/EIPS/eip-1820.md new file mode 100644 index 00000000000000..055bae9c1d3f3a --- /dev/null +++ b/EIPS/eip-1820.md @@ -0,0 +1,928 @@ +--- +eip: 1820 +title: Pseudo-introspection Registry Contract +author: Jordi Baylina , Jacques Dafflon +discussions-to: https://github.com/ethereum/EIPs/pulls/1820 +status: Final +type: Standards Track +category: ERC +requires: 165, 214 +created: 2019-03-04 +replaces: 820 +--- + +> :information_source: **[ERC1820] has superseded [ERC820].** :information_source: +> [ERC1820] fixes the incompatibility in the [ERC165] logic which was introduced by the Solidty 0.5 update. +> Have a look at the [official announcement][erc1820-annoucement], and the comments about the [bug][erc820-bug] and the [fix][erc820-fix]. +> Apart from this fix, [ERC1820] is functionally equivalent to [ERC820]. +> +> :warning: [ERC1820] MUST be used in lieu of [ERC820]. :warning: + +## Simple Summary + +This standard defines a universal registry smart contract where any address (contract or regular account) can register which interface it supports and which smart contract is responsible for its implementation. + +This standard keeps backward compatibility with [ERC165]. + +## Abstract + +This standard defines a registry where smart contracts and regular accounts can publish which functionality they implement---either directly or through a proxy contract. + +Anyone can query this registry to ask if a specific address implements a given interface and which smart contract handles its implementation. + +This registry MAY be deployed on any chain and shares the same address on all chains. + +Interfaces with zeroes (`0`) as the last 28 bytes are considered [ERC165] interfaces, +and this registry SHALL forward the call to the contract to see if it implements the interface. + +This contract also acts as an [ERC165] cache to reduce gas consumption. + +## Motivation + +There have been different approaches to define pseudo-introspection in Ethereum. +The first is [ERC165] which has the limitation that it cannot be used by regular accounts. +The second attempt is [ERC672] which uses reverse [ENS]. Using reverse [ENS] has two issues. +First, it is unnecessarily complicated, and second, [ENS] is still a centralized contract controlled by a multisig. +This multisig theoretically would be able to modify the system. + +This standard is much simpler than [ERC672], and it is *fully* decentralized. + +This standard also provides a *unique* address for all chains. +Thus solving the problem of resolving the correct registry address for different chains. + +## Specification + +### [ERC1820] Registry Smart Contract + +> This is an exact copy of the code of the [ERC1820 registry smart contract]. + +``` solidity +/* ERC1820 Pseudo-introspection Registry Contract + * This standard defines a universal registry smart contract where any address (contract or regular account) can + * register which interface it supports and which smart contract is responsible for its implementation. + * + * Written in 2019 by Jordi Baylina and Jacques Dafflon + * + * To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to + * this software to the public domain worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see + * . + * + * ███████╗██████╗ ██████╗ ██╗ █████╗ ██████╗ ██████╗ + * ██╔════╝██╔══██╗██╔════╝███║██╔══██╗╚════██╗██╔═████╗ + * █████╗ ██████╔╝██║ ╚██║╚█████╔╝ █████╔╝██║██╔██║ + * ██╔══╝ ██╔══██╗██║ ██║██╔══██╗██╔═══╝ ████╔╝██║ + * ███████╗██║ ██║╚██████╗ ██║╚█████╔╝███████╗╚██████╔╝ + * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ ╚═════╝ + * + * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗ + * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝ + * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝ + * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝ + * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║ + * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ + * + */ +pragma solidity 0.5.3; +// IV is value needed to have a vanity address starting with '0x1820'. +// IV: 53759 + +/// @dev The interface a contract MUST implement if it is the implementer of +/// some (other) interface for any address other than itself. +interface ERC1820ImplementerInterface { + /// @notice Indicates whether the contract implements the interface 'interfaceHash' for the address 'addr' or not. + /// @param interfaceHash keccak256 hash of the name of the interface + /// @param addr Address for which the contract will implement the interface + /// @return ERC1820_ACCEPT_MAGIC only if the contract implements 'interfaceHash' for the address 'addr'. + function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32); +} + + +/// @title ERC1820 Pseudo-introspection Registry Contract +/// @author Jordi Baylina and Jacques Dafflon +/// @notice This contract is the official implementation of the ERC1820 Registry. +/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820 +contract ERC1820Registry { + /// @notice ERC165 Invalid ID. + bytes4 constant internal INVALID_ID = 0xffffffff; + /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`). + bytes4 constant internal ERC165ID = 0x01ffc9a7; + /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address. + bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC")); + + /// @notice mapping from addresses and interface hashes to their implementers. + mapping(address => mapping(bytes32 => address)) internal interfaces; + /// @notice mapping from addresses to their manager. + mapping(address => address) internal managers; + /// @notice flag for each address and erc165 interface to indicate if it is cached. + mapping(address => mapping(bytes4 => bool)) internal erc165Cached; + + /// @notice Indicates a contract is the 'implementer' of 'interfaceHash' for 'addr'. + event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer); + /// @notice Indicates 'newManager' is the address of the new manager for 'addr'. + event ManagerChanged(address indexed addr, address indexed newManager); + + /// @notice Query if an address implements an interface and through which contract. + /// @param _addr Address being queried for the implementer of an interface. + /// (If '_addr' is the zero address then 'msg.sender' is assumed.) + /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. + /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. + /// @return The address of the contract which implements the interface '_interfaceHash' for '_addr' + /// or '0' if '_addr' did not register an implementer for this interface. + function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) { + address addr = _addr == address(0) ? msg.sender : _addr; + if (isERC165Interface(_interfaceHash)) { + bytes4 erc165InterfaceHash = bytes4(_interfaceHash); + return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : address(0); + } + return interfaces[addr][_interfaceHash]; + } + + /// @notice Sets the contract which implements a specific interface for an address. + /// Only the manager defined for that address can set it. + /// (Each address is the manager for itself until it sets a new manager.) + /// @param _addr Address for which to set the interface. + /// (If '_addr' is the zero address then 'msg.sender' is assumed.) + /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. + /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. + /// @param _implementer Contract address implementing '_interfaceHash' for '_addr'. + function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external { + address addr = _addr == address(0) ? msg.sender : _addr; + require(getManager(addr) == msg.sender, "Not the manager"); + + require(!isERC165Interface(_interfaceHash), "Must not be an ERC165 hash"); + if (_implementer != address(0) && _implementer != msg.sender) { + require( + ERC1820ImplementerInterface(_implementer) + .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC1820_ACCEPT_MAGIC, + "Does not implement the interface" + ); + } + interfaces[addr][_interfaceHash] = _implementer; + emit InterfaceImplementerSet(addr, _interfaceHash, _implementer); + } + + /// @notice Sets '_newManager' as manager for '_addr'. + /// The new manager will be able to call 'setInterfaceImplementer' for '_addr'. + /// @param _addr Address for which to set the new manager. + /// @param _newManager Address of the new manager for 'addr'. (Pass '0x0' to reset the manager to '_addr'.) + function setManager(address _addr, address _newManager) external { + require(getManager(_addr) == msg.sender, "Not the manager"); + managers[_addr] = _newManager == _addr ? address(0) : _newManager; + emit ManagerChanged(_addr, _newManager); + } + + /// @notice Get the manager of an address. + /// @param _addr Address for which to return the manager. + /// @return Address of the manager for a given address. + function getManager(address _addr) public view returns(address) { + // By default the manager of an address is the same address + if (managers[_addr] == address(0)) { + return _addr; + } else { + return managers[_addr]; + } + } + + /// @notice Compute the keccak256 hash of an interface given its name. + /// @param _interfaceName Name of the interface. + /// @return The keccak256 hash of an interface name. + function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) { + return keccak256(abi.encodePacked(_interfaceName)); + } + + /* --- ERC165 Related Functions --- */ + /* --- Developed in collaboration with William Entriken. --- */ + + /// @notice Updates the cache with whether the contract implements an ERC165 interface or not. + /// @param _contract Address of the contract for which to update the cache. + /// @param _interfaceId ERC165 interface for which to update the cache. + function updateERC165Cache(address _contract, bytes4 _interfaceId) external { + interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache( + _contract, _interfaceId) ? _contract : address(0); + erc165Cached[_contract][_interfaceId] = true; + } + + /// @notice Checks whether a contract implements an ERC165 interface or not. + // If the result is not cached a direct lookup on the contract address is performed. + // If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling + // 'updateERC165Cache' with the contract address. + /// @param _contract Address of the contract to check. + /// @param _interfaceId ERC165 interface to check. + /// @return True if '_contract' implements '_interfaceId', false otherwise. + function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) { + if (!erc165Cached[_contract][_interfaceId]) { + return implementsERC165InterfaceNoCache(_contract, _interfaceId); + } + return interfaces[_contract][_interfaceId] == _contract; + } + + /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. + /// @param _contract Address of the contract to check. + /// @param _interfaceId ERC165 interface to check. + /// @return True if '_contract' implements '_interfaceId', false otherwise. + function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) { + uint256 success; + uint256 result; + + (success, result) = noThrowCall(_contract, ERC165ID); + if (success == 0 || result == 0) { + return false; + } + + (success, result) = noThrowCall(_contract, INVALID_ID); + if (success == 0 || result != 0) { + return false; + } + + (success, result) = noThrowCall(_contract, _interfaceId); + if (success == 1 && result == 1) { + return true; + } + return false; + } + + /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not. + /// @param _interfaceHash The hash to check. + /// @return True if '_interfaceHash' is an ERC165 interface (ending with 28 zeroes), false otherwise. + function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) { + return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0; + } + + /// @dev Make a call on a contract without throwing if the function does not exist. + function noThrowCall(address _contract, bytes4 _interfaceId) + internal view returns (uint256 success, uint256 result) + { + bytes4 erc165ID = ERC165ID; + + assembly { + let x := mload(0x40) // Find empty storage location using "free memory pointer" + mstore(x, erc165ID) // Place signature at beginning of empty storage + mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature + + success := staticcall( + 30000, // 30k gas + _contract, // To addr + x, // Inputs are stored at location x + 0x24, // Inputs are 36 (4 + 32) bytes long + x, // Store output over input (saves space) + 0x20 // Outputs are 32 bytes long + ) + + result := mload(x) // Load the result + } + } +} + +``` + +### Deployment Transaction + +Below is the raw transaction which MUST be used to deploy the smart contract on any chain. + +``` +0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a72305820377f4a2d4301ede9949f163f319021a6e9c687c292a5e2b2c4734c126b524e6c00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820 +``` + +The strings of `1820`'s at the end of the transaction are the `r` and `s` of the signature. +From this deterministic pattern (generated by a human), anyone can deduce that no one knows the private key for the deployment account. + +### Deployment Method + +This contract is going to be deployed using the keyless deployment method---also known as [Nick]'s method---which relies on a single-use address. +(See [Nick's article] for more details). This method works as follows: + +1. Generate a transaction which deploys the contract from a new random account. + - This transaction MUST NOT use [EIP155] in order to work on any chain. + - This transaction MUST have a relatively high gas price to be deployed on any chain. In this case, it is going to be 100 Gwei. + +2. Set the `v`, `r`, `s` of the transaction signature to the following values: + + ``` + v: 27, + r: 0x1820182018201820182018201820182018201820182018201820182018201820' + s: 0x1820182018201820182018201820182018201820182018201820182018201820' + ``` + + Those `r` and `s` values---made of a repeating pattern of `1820`'s---are predictable "random numbers" generated deterministically by a human. + +3. We recover the sender of this transaction, i.e., the single-use deployment account. + + > Thus we obtain an account that can broadcast that transaction, but we also have the warranty that nobody knows the private key of that account. + +4. Send exactly 0.08 ether to this single-use deployment account. + +5. Broadcast the deployment transaction. + +This operation can be done on any chain, guaranteeing that the contract address is always the same and nobody can use that address with a different contract. + + +### Single-use Registry Deployment Account + +``` +0xa990077c3205cbDf861e17Fa532eeB069cE9fF96 +``` + +This account is generated by reverse engineering it from its signature for the transaction. +This way no one knows the private key, but it is known that it is the valid signer of the deployment transaction. + +> To deploy the registry, 0.08 ether MUST be sent to this account *first*. + +### Registry Contract Address + +``` +0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 +``` + +The contract has the address above for every chain on which it is deployed. + +
+Raw metadata of ./contracts/ERC1820Registry.sol +
+{
+        "compiler": {
+          "version": "0.5.3+commit.10d17f24"
+        },
+        "language": "Solidity",
+        "output": {
+          "abi": [
+            {
+              "constant": false,
+              "inputs": [
+                {
+                  "name": "_addr",
+                  "type": "address"
+                },
+                {
+                  "name": "_interfaceHash",
+                  "type": "bytes32"
+                },
+                {
+                  "name": "_implementer",
+                  "type": "address"
+                }
+              ],
+              "name": "setInterfaceImplementer",
+              "outputs": [],
+              "payable": false,
+              "stateMutability": "nonpayable",
+              "type": "function"
+            },
+            {
+              "constant": true,
+              "inputs": [
+                {
+                  "name": "_addr",
+                  "type": "address"
+                }
+              ],
+              "name": "getManager",
+              "outputs": [
+                {
+                  "name": "",
+                  "type": "address"
+                }
+              ],
+              "payable": false,
+              "stateMutability": "view",
+              "type": "function"
+            },
+            {
+              "constant": false,
+              "inputs": [
+                {
+                  "name": "_addr",
+                  "type": "address"
+                },
+                {
+                  "name": "_newManager",
+                  "type": "address"
+                }
+              ],
+              "name": "setManager",
+              "outputs": [],
+              "payable": false,
+              "stateMutability": "nonpayable",
+              "type": "function"
+            },
+            {
+              "constant": true,
+              "inputs": [
+                {
+                  "name": "_interfaceName",
+                  "type": "string"
+                }
+              ],
+              "name": "interfaceHash",
+              "outputs": [
+                {
+                  "name": "",
+                  "type": "bytes32"
+                }
+              ],
+              "payable": false,
+              "stateMutability": "pure",
+              "type": "function"
+            },
+            {
+              "constant": false,
+              "inputs": [
+                {
+                  "name": "_contract",
+                  "type": "address"
+                },
+                {
+                  "name": "_interfaceId",
+                  "type": "bytes4"
+                }
+              ],
+              "name": "updateERC165Cache",
+              "outputs": [],
+              "payable": false,
+              "stateMutability": "nonpayable",
+              "type": "function"
+            },
+            {
+              "constant": true,
+              "inputs": [
+                {
+                  "name": "_addr",
+                  "type": "address"
+                },
+                {
+                  "name": "_interfaceHash",
+                  "type": "bytes32"
+                }
+              ],
+              "name": "getInterfaceImplementer",
+              "outputs": [
+                {
+                  "name": "",
+                  "type": "address"
+                }
+              ],
+              "payable": false,
+              "stateMutability": "view",
+              "type": "function"
+            },
+            {
+              "constant": true,
+              "inputs": [
+                {
+                  "name": "_contract",
+                  "type": "address"
+                },
+                {
+                  "name": "_interfaceId",
+                  "type": "bytes4"
+                }
+              ],
+              "name": "implementsERC165InterfaceNoCache",
+              "outputs": [
+                {
+                  "name": "",
+                  "type": "bool"
+                }
+              ],
+              "payable": false,
+              "stateMutability": "view",
+              "type": "function"
+            },
+            {
+              "constant": true,
+              "inputs": [
+                {
+                  "name": "_contract",
+                  "type": "address"
+                },
+                {
+                  "name": "_interfaceId",
+                  "type": "bytes4"
+                }
+              ],
+              "name": "implementsERC165Interface",
+              "outputs": [
+                {
+                  "name": "",
+                  "type": "bool"
+                }
+              ],
+              "payable": false,
+              "stateMutability": "view",
+              "type": "function"
+            },
+            {
+              "anonymous": false,
+              "inputs": [
+                {
+                  "indexed": true,
+                  "name": "addr",
+                  "type": "address"
+                },
+                {
+                  "indexed": true,
+                  "name": "interfaceHash",
+                  "type": "bytes32"
+                },
+                {
+                  "indexed": true,
+                  "name": "implementer",
+                  "type": "address"
+                }
+              ],
+              "name": "InterfaceImplementerSet",
+              "type": "event"
+            },
+            {
+              "anonymous": false,
+              "inputs": [
+                {
+                  "indexed": true,
+                  "name": "addr",
+                  "type": "address"
+                },
+                {
+                  "indexed": true,
+                  "name": "newManager",
+                  "type": "address"
+                }
+              ],
+              "name": "ManagerChanged",
+              "type": "event"
+            }
+          ],
+          "devdoc": {
+            "author": "Jordi Baylina and Jacques Dafflon",
+            "methods": {
+              "getInterfaceImplementer(address,bytes32)": {
+                "params": {
+                  "_addr": "Address being queried for the implementer of an interface. (If '_addr' is the zero address then 'msg.sender' is assumed.)",
+                  "_interfaceHash": "Keccak256 hash of the name of the interface as a string. E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface."
+                },
+                "return": "The address of the contract which implements the interface '_interfaceHash' for '_addr' or '0' if '_addr' did not register an implementer for this interface."
+              },
+              "getManager(address)": {
+                "params": {
+                  "_addr": "Address for which to return the manager."
+                },
+                "return": "Address of the manager for a given address."
+              },
+              "implementsERC165Interface(address,bytes4)": {
+                "params": {
+                  "_contract": "Address of the contract to check.",
+                  "_interfaceId": "ERC165 interface to check."
+                },
+                "return": "True if '_contract' implements '_interfaceId', false otherwise."
+              },
+              "implementsERC165InterfaceNoCache(address,bytes4)": {
+                "params": {
+                  "_contract": "Address of the contract to check.",
+                  "_interfaceId": "ERC165 interface to check."
+                },
+                "return": "True if '_contract' implements '_interfaceId', false otherwise."
+              },
+              "interfaceHash(string)": {
+                "params": {
+                  "_interfaceName": "Name of the interface."
+                },
+                "return": "The keccak256 hash of an interface name."
+              },
+              "setInterfaceImplementer(address,bytes32,address)": {
+                "params": {
+                  "_addr": "Address for which to set the interface. (If '_addr' is the zero address then 'msg.sender' is assumed.)",
+                  "_implementer": "Contract address implementing '_interfaceHash' for '_addr'.",
+                  "_interfaceHash": "Keccak256 hash of the name of the interface as a string. E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface."
+                }
+              },
+              "setManager(address,address)": {
+                "params": {
+                  "_addr": "Address for which to set the new manager.",
+                  "_newManager": "Address of the new manager for 'addr'. (Pass '0x0' to reset the manager to '_addr'.)"
+                }
+              },
+              "updateERC165Cache(address,bytes4)": {
+                "params": {
+                  "_contract": "Address of the contract for which to update the cache.",
+                  "_interfaceId": "ERC165 interface for which to update the cache."
+                }
+              }
+            },
+            "title": "ERC1820 Pseudo-introspection Registry Contract"
+          },
+          "userdoc": {
+            "methods": {
+              "getInterfaceImplementer(address,bytes32)": {
+                "notice": "Query if an address implements an interface and through which contract."
+              },
+              "getManager(address)": {
+                "notice": "Get the manager of an address."
+              },
+              "implementsERC165InterfaceNoCache(address,bytes4)": {
+                "notice": "Checks whether a contract implements an ERC165 interface or not without using nor updating the cache."
+              },
+              "interfaceHash(string)": {
+                "notice": "Compute the keccak256 hash of an interface given its name."
+              },
+              "setInterfaceImplementer(address,bytes32,address)": {
+                "notice": "Sets the contract which implements a specific interface for an address. Only the manager defined for that address can set it. (Each address is the manager for itself until it sets a new manager.)"
+              },
+              "setManager(address,address)": {
+                "notice": "Sets '_newManager' as manager for '_addr'. The new manager will be able to call 'setInterfaceImplementer' for '_addr'."
+              },
+              "updateERC165Cache(address,bytes4)": {
+                "notice": "Updates the cache with whether the contract implements an ERC165 interface or not."
+              }
+            },
+            "notice": "This contract is the official implementation of the ERC1820 Registry.For more details, see https://eips.ethereum.org/EIPS/eip-1820"
+          }
+        },
+        "settings": {
+          "compilationTarget": {
+            "./contracts/ERC1820Registry.sol": "ERC1820Registry"
+          },
+          "evmVersion": "byzantium",
+          "libraries": {},
+          "optimizer": {
+            "enabled": true,
+            "runs": 200
+          },
+          "remappings": []
+        },
+        "sources": {
+          "./contracts/ERC1820Registry.sol": {
+            "content": "/* ERC1820 Pseudo-introspection Registry Contract\n * This standard defines a universal registry smart contract where any address (contract or regular account) can\n * register which interface it supports and which smart contract is responsible for its implementation.\n *\n * Written in 2019 by Jordi Baylina and Jacques Dafflon\n *\n * To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to\n * this software to the public domain worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see\n * .\n *\n *    ███████╗██████╗  ██████╗ ██╗ █████╗ ██████╗  ██████╗\n *    ██╔════╝██╔══██╗██╔════╝███║██╔══██╗╚════██╗██╔═████╗\n *    █████╗  ██████╔╝██║     ╚██║╚█████╔╝ █████╔╝██║██╔██║\n *    ██╔══╝  ██╔══██╗██║      ██║██╔══██╗██╔═══╝ ████╔╝██║\n *    ███████╗██║  ██║╚██████╗ ██║╚█████╔╝███████╗╚██████╔╝\n *    ╚══════╝╚═╝  ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ ╚═════╝\n *\n *    ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗   ██╗\n *    ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝\n *    ██████╔╝█████╗  ██║  ███╗██║███████╗   ██║   ██████╔╝ ╚████╔╝\n *    ██╔══██╗██╔══╝  ██║   ██║██║╚════██║   ██║   ██╔══██╗  ╚██╔╝\n *    ██║  ██║███████╗╚██████╔╝██║███████║   ██║   ██║  ██║   ██║\n *    ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝   ╚═╝\n *\n */\npragma solidity 0.5.3;\n// IV is value needed to have a vanity address starting with '0x1820'.\n// IV: 53759\n\n/// @dev The interface a contract MUST implement if it is the implementer of\n/// some (other) interface for any address other than itself.\ninterface ERC1820ImplementerInterface {\n    /// @notice Indicates whether the contract implements the interface 'interfaceHash' for the address 'addr' or not.\n    /// @param interfaceHash keccak256 hash of the name of the interface\n    /// @param addr Address for which the contract will implement the interface\n    /// @return ERC1820_ACCEPT_MAGIC only if the contract implements 'interfaceHash' for the address 'addr'.\n    function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32);\n}\n\n\n/// @title ERC1820 Pseudo-introspection Registry Contract\n/// @author Jordi Baylina and Jacques Dafflon\n/// @notice This contract is the official implementation of the ERC1820 Registry.\n/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820\ncontract ERC1820Registry {\n    /// @notice ERC165 Invalid ID.\n    bytes4 constant internal INVALID_ID = 0xffffffff;\n    /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`).\n    bytes4 constant internal ERC165ID = 0x01ffc9a7;\n    /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address.\n    bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC1820_ACCEPT_MAGIC\"));\n\n    /// @notice mapping from addresses and interface hashes to their implementers.\n    mapping(address => mapping(bytes32 => address)) internal interfaces;\n    /// @notice mapping from addresses to their manager.\n    mapping(address => address) internal managers;\n    /// @notice flag for each address and erc165 interface to indicate if it is cached.\n    mapping(address => mapping(bytes4 => bool)) internal erc165Cached;\n\n    /// @notice Indicates a contract is the 'implementer' of 'interfaceHash' for 'addr'.\n    event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);\n    /// @notice Indicates 'newManager' is the address of the new manager for 'addr'.\n    event ManagerChanged(address indexed addr, address indexed newManager);\n\n    /// @notice Query if an address implements an interface and through which contract.\n    /// @param _addr Address being queried for the implementer of an interface.\n    /// (If '_addr' is the zero address then 'msg.sender' is assumed.)\n    /// @param _interfaceHash Keccak256 hash of the name of the interface as a string.\n    /// E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface.\n    /// @return The address of the contract which implements the interface '_interfaceHash' for '_addr'\n    /// or '0' if '_addr' did not register an implementer for this interface.\n    function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) {\n        address addr = _addr == address(0) ? msg.sender : _addr;\n        if (isERC165Interface(_interfaceHash)) {\n            bytes4 erc165InterfaceHash = bytes4(_interfaceHash);\n            return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : address(0);\n        }\n        return interfaces[addr][_interfaceHash];\n    }\n\n    /// @notice Sets the contract which implements a specific interface for an address.\n    /// Only the manager defined for that address can set it.\n    /// (Each address is the manager for itself until it sets a new manager.)\n    /// @param _addr Address for which to set the interface.\n    /// (If '_addr' is the zero address then 'msg.sender' is assumed.)\n    /// @param _interfaceHash Keccak256 hash of the name of the interface as a string.\n    /// E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface.\n    /// @param _implementer Contract address implementing '_interfaceHash' for '_addr'.\n    function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external {\n        address addr = _addr == address(0) ? msg.sender : _addr;\n        require(getManager(addr) == msg.sender, \"Not the manager\");\n\n        require(!isERC165Interface(_interfaceHash), \"Must not be an ERC165 hash\");\n        if (_implementer != address(0) && _implementer != msg.sender) {\n            require(\n                ERC1820ImplementerInterface(_implementer)\n                    .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC1820_ACCEPT_MAGIC,\n                \"Does not implement the interface\"\n            );\n        }\n        interfaces[addr][_interfaceHash] = _implementer;\n        emit InterfaceImplementerSet(addr, _interfaceHash, _implementer);\n    }\n\n    /// @notice Sets '_newManager' as manager for '_addr'.\n    /// The new manager will be able to call 'setInterfaceImplementer' for '_addr'.\n    /// @param _addr Address for which to set the new manager.\n    /// @param _newManager Address of the new manager for 'addr'. (Pass '0x0' to reset the manager to '_addr'.)\n    function setManager(address _addr, address _newManager) external {\n        require(getManager(_addr) == msg.sender, \"Not the manager\");\n        managers[_addr] = _newManager == _addr ? address(0) : _newManager;\n        emit ManagerChanged(_addr, _newManager);\n    }\n\n    /// @notice Get the manager of an address.\n    /// @param _addr Address for which to return the manager.\n    /// @return Address of the manager for a given address.\n    function getManager(address _addr) public view returns(address) {\n        // By default the manager of an address is the same address\n        if (managers[_addr] == address(0)) {\n            return _addr;\n        } else {\n            return managers[_addr];\n        }\n    }\n\n    /// @notice Compute the keccak256 hash of an interface given its name.\n    /// @param _interfaceName Name of the interface.\n    /// @return The keccak256 hash of an interface name.\n    function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) {\n        return keccak256(abi.encodePacked(_interfaceName));\n    }\n\n    /* --- ERC165 Related Functions --- */\n    /* --- Developed in collaboration with William Entriken. --- */\n\n    /// @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n    /// @param _contract Address of the contract for which to update the cache.\n    /// @param _interfaceId ERC165 interface for which to update the cache.\n    function updateERC165Cache(address _contract, bytes4 _interfaceId) external {\n        interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache(\n            _contract, _interfaceId) ? _contract : address(0);\n        erc165Cached[_contract][_interfaceId] = true;\n    }\n\n    /// @notice Checks whether a contract implements an ERC165 interface or not.\n    //  If the result is not cached a direct lookup on the contract address is performed.\n    //  If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n    //  'updateERC165Cache' with the contract address.\n    /// @param _contract Address of the contract to check.\n    /// @param _interfaceId ERC165 interface to check.\n    /// @return True if '_contract' implements '_interfaceId', false otherwise.\n    function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) {\n        if (!erc165Cached[_contract][_interfaceId]) {\n            return implementsERC165InterfaceNoCache(_contract, _interfaceId);\n        }\n        return interfaces[_contract][_interfaceId] == _contract;\n    }\n\n    /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n    /// @param _contract Address of the contract to check.\n    /// @param _interfaceId ERC165 interface to check.\n    /// @return True if '_contract' implements '_interfaceId', false otherwise.\n    function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) {\n        uint256 success;\n        uint256 result;\n\n        (success, result) = noThrowCall(_contract, ERC165ID);\n        if (success == 0 || result == 0) {\n            return false;\n        }\n\n        (success, result) = noThrowCall(_contract, INVALID_ID);\n        if (success == 0 || result != 0) {\n            return false;\n        }\n\n        (success, result) = noThrowCall(_contract, _interfaceId);\n        if (success == 1 && result == 1) {\n            return true;\n        }\n        return false;\n    }\n\n    /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not.\n    /// @param _interfaceHash The hash to check.\n    /// @return True if '_interfaceHash' is an ERC165 interface (ending with 28 zeroes), false otherwise.\n    function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) {\n        return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;\n    }\n\n    /// @dev Make a call on a contract without throwing if the function does not exist.\n    function noThrowCall(address _contract, bytes4 _interfaceId)\n        internal view returns (uint256 success, uint256 result)\n    {\n        bytes4 erc165ID = ERC165ID;\n\n        assembly {\n            let x := mload(0x40)               // Find empty storage location using \"free memory pointer\"\n            mstore(x, erc165ID)                // Place signature at beginning of empty storage\n            mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature\n\n            success := staticcall(\n                30000,                         // 30k gas\n                _contract,                     // To addr\n                x,                             // Inputs are stored at location x\n                0x24,                          // Inputs are 36 (4 + 32) bytes long\n                x,                             // Store output over input (saves space)\n                0x20                           // Outputs are 32 bytes long\n            )\n\n            result := mload(x)                 // Load the result\n        }\n    }\n}\n",
+            "keccak256": "0x64025ecebddb6e126a5075c1fd6c01de2840492668e2909cef7157040a9d1945"
+          }
+        },
+        "version": 1
+      }
+
+
+ +### Interface Name + +Any interface name is hashed using `keccak256` and sent to `getInterfaceImplementer()`. + +If the interface is part of a standard, it is best practice to explicitly state the interface name and link to this published [ERC1820] such that other people don't have to come here to look up these rules. + +For convenience, the registry provides a function to compute the hash on-chain: + +``` solidity +function interfaceHash(string _interfaceName) public pure returns(bytes32) +``` + +Compute the keccak256 hash of an interface given its name. + +> **identifier:** `65ba36c1` +> **parameters** +> `_interfaceName`: Name of the interface. +> **returns:** The `keccak256` hash of an interface name. + +#### **Approved ERCs** + +If the interface is part of an approved ERC, it MUST be named `ERC###XXXXX` where `###` is the number of the ERC and XXXXX should be the name of the interface in CamelCase. +The meaning of this interface SHOULD be defined in the specified ERC. + +Examples: + +- `keccak256("ERC20Token")` +- `keccak256("ERC777Token")` +- `keccak256("ERC777TokensSender")` +- `keccak256("ERC777TokensRecipient")` + +#### **[ERC165] Compatible Interfaces** + +> The compatibility with [ERC165], including the [ERC165 Cache], has been designed and developed with [William Entriken]. + +Any interface where the last 28 bytes are zeroes (`0`) SHALL be considered an [ERC165] interface. + +**[ERC165] Lookup** + +Anyone can explicitly check if a contract implements an [ERC165] interface using the registry by calling one of the two functions below: + +``` solidity +function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) +``` + +Checks whether a contract implements an [ERC165] interface or not. + +If the result is not cached a direct lookup on the contract address is performed. + +*NOTE*: If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling `updateERC165Cache` with the contract address. +(See [ERC165 Cache] for more details.) + +> **identifier:** `f712f3e8` +> **parameters** +> `_contract`: Address of the contract to check. +> `_interfaceId`: [ERC165] interface to check. +> **returns:** `true` if `_contract` implements `_interfaceId`, `false` otherwise. + +``` solidity +function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) +``` + +Checks whether a contract implements an [ERC165] interface or not without using nor updating the cache. + +> **identifier:** `b7056765` +> **parameters** +> `_contract`: Address of the contract to check. +> `_interfaceId`: [ERC165] interface to check. +> **returns:** `true` if `_contract` implements `_interfaceId`, false otherwise. + +**[ERC165] Cache** + +Whether a contract implements an [ERC165] interface or not can be cached manually to save gas. + +If a contract dynamically changes its interface and relies on the [ERC165] cache of the [ERC1820] registry, the cache MUST be updated manually---there is no automatic cache invalidation or cache update. +Ideally the contract SHOULD automatically update the cache when changing its interface. +However anyone MAY update the cache on the contract's behalf. + +The cache update MUST be done using the `updateERC165Cache` function: + +``` solidity +function updateERC165Cache(address _contract, bytes4 _interfaceId) external +``` + +> **identifier:** `a41e7d51` +> **parameters** +> `_contract`: Address of the contract for which to update the cache. +> `_interfaceId`: [ERC165] interface for which to update the cache. + +#### **Private User-defined Interfaces** + +This scheme is extensible. +You MAY make up your own interface name and raise awareness to get other people to implement it and then check for those implementations. +Have fun but please, you MUST not conflict with the reserved designations above. + +### Set An Interface For An Address + +For any address to set a contract as the interface implementation, it must call the following function of the [ERC1820] registry: + +``` solidity +function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external +``` + +Sets the contract which implements a specific interface for an address. + +Only the `manager` defined for that address can set it. +(Each address is the manager for itself, see the [manager] section for more details.) + +*NOTE*: If `_addr` and `_implementer` are two different addresses, then: + +- The `_implementer` MUST implement the `ERC1820ImplementerInterface` (detailed below). +- Calling `canImplementInterfaceForAddress` on `_implementer` with the given `_addr` and `_interfaceHash` MUST return the `ERC1820_ACCEPT_MAGIC` value. + +*NOTE*: The `_interfaceHash` MUST NOT be an [ERC165] interface---it MUST NOT end with 28 zeroes (`0`). + +*NOTE*: The `_addr` MAY be `0`, then `msg.sender` is assumed. +This default value simplifies interactions via multisigs where the data of the transaction to sign is constant regardless of the address of the multisig instance. + +> **identifier:** `29965a1d` +> **parameters** +> `_addr`: Address for which to set the interface. (If `_addr` is the zero address then `msg.sender` is assumed.) +> `_interfaceHash`: Keccak256 hash of the name of the interface as a string, for example `web3.utils.keccak256('ERC777TokensRecipient')` for the ERC777TokensRecipient interface. +> `_implementer`: Contract implementing `_interfaceHash` for `_addr`. + +### Get An Implementation Of An Interface For An Address + +Anyone MAY query the [ERC1820] Registry to obtain the address of a contract implementing an interface on behalf of some address using the `getInterfaceImplementer` function. + +``` solidity +function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) +``` + +Query if an address implements an interface and through which contract. + +*NOTE*: If the last 28 bytes of the `_interfaceHash` are zeroes (`0`), then the first 4 bytes are considered an [ERC165] interface and the registry SHALL forward the call to the contract at `_addr` to see if it implements the [ERC165] interface (the first 4 bytes of `_interfaceHash`). +The registry SHALL also cache [ERC165] queries to reduce gas consumption. Anyone MAY call the `erc165UpdateCache` function to update whether a contract implements an interface or not. + +*NOTE*: The `_addr` MAY be `0`, then `msg.sender` is assumed. +This default value is consistent with the behavior of the `setInterfaceImplementer` function and simplifies interactions via multisigs where the data of the transaction to sign is constant regardless of the address of the multisig instance. + +> **identifier:** `aabbb8ca` +> **parameters** +> `_addr`: Address being queried for the implementer of an interface. (If `_addr` is the zero address then `msg.sender` is assumed.) +> `_interfaceHash`: keccak256 hash of the name of the interface as a string. E.g. `web3.utils.keccak256('ERC777Token')` +> **returns:** The address of the contract which implements the interface `_interfaceHash` for `_addr` or `0` if `_addr` did not register an implementer for this interface. + + +### Interface Implementation (`ERC1820ImplementerInterface`) + +``` solidity +interface ERC1820ImplementerInterface { + /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not. + /// @param interfaceHash keccak256 hash of the name of the interface + /// @param addr Address for which the contract will implement the interface + /// @return ERC1820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`. + function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32); +} +``` + +Any contract being registered as the implementation of an interface for a given address MUST implement said interface. +In addition if it implements an interface on behalf of a different address, the contract MUST implement the `ERC1820ImplementerInterface` shown above. + +``` solidity +function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32) +``` + +Indicates whether a contract implements an interface (`interfaceHash`) for a given address (`addr`). + +If a contract implements the interface (`interfaceHash`) for a given address (`addr`), it MUST return `ERC1820_ACCEPT_MAGIC` when called with the `addr` and the `interfaceHash`. +If it does not implement the `interfaceHash` for a given address (`addr`), it MUST NOT return `ERC1820_ACCEPT_MAGIC`. + +> **identifier:** `f0083250` +> **parameters** +> `interfaceHash`: Hash of the interface which is implemented +> `addr`: Address for which the interface is implemented +> **returns:** `ERC1820_ACCEPT_MAGIC` only if the contract implements `ìnterfaceHash` for the address `addr`. + +The special value `ERC1820_ACCEPT_MAGIC` is defined as the `keccka256` hash of the string `"ERC1820_ACCEPT_MAGIC"`. + +``` solidity +bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC")); +``` + +> The reason to return `ERC1820_ACCEPT_MAGIC` instead of a boolean is to prevent cases where a contract fails to implement the `canImplementInterfaceForAddress` but implements a fallback function which does not throw. In this case, since `canImplementInterfaceForAddress` does not exist, the fallback function is called instead, executed without throwing and returns `1`. Thus making it appear as if `canImplementInterfaceForAddress` returned `true`. + +### Manager + +The manager of an address (regular account or a contract) is the only entity allowed to register implementations of interfaces for the address. +By default, any address is its own manager. + +The manager can transfer its role to another address by calling `setManager` on the registry contract with the address for which to transfer the manager and the address of the new manager. + +**`setManager` Function** + +``` solidity +function setManager(address _addr, address _newManager) external +``` + +Sets `_newManager` as manager for `_addr`. + +The new manager will be able to call `setInterfaceImplementer` for `_addr`. + +If `_newManager` is `0x0`, the manager is reset to `_addr` itself as the manager. + +> **identifier:** `5df8122f` +> **parameters** +> `_addr`: Address for which to set the new manager. +> `_newManager`: The address of the new manager for `_addr`. (Pass `0x0` to reset the manager to `_addr`.) + +**`getManager` Function** + +``` solidity +function getManager(address _addr) public view returns(address) +``` + +Get the manager of an address. + +> **identifier:** `3d584063` +> **parameters** +> `_addr`: Address for which to return the manager. +> **returns:** Address of the manager for a given address. + +## Rationale + +This standards offers a way for any type of address (externally owned and contracts) to implement an interface and potentially delegate the implementation of the interface to a proxy contract. +This delegation to a proxy contract is necessary for externally owned accounts and useful to avoid redeploying existing contracts such as multisigs and DAOs. + +The registry can also act as a [ERC165] cache in order to save gas when looking up if a contract implements a specific [ERC165] interface. +This cache is intentionally kept simple, without automatic cache update or invalidation. +Anyone can easily and safely update the cache for any interface and any contract by calling the `updateERC165Cache` function. + +The registry is deployed using a keyless deployment method relying on a single-use deployment address to ensure no one controls the registry, thereby ensuring trust. + +## Backward Compatibility + +This standard is backward compatible with [ERC165], as both methods MAY be implemented without conflicting with each other. + +## Test Cases + +Please check the [0xjac/ERC1820] repository for the full test suite. + +## Implementation + +The implementation is available in the repo: [0xjac/ERC1820]. + +## Copyright +Copyright and related rights waived via [CC0]. + +[EIP155]: https://eips.ethereum.org/EIPS/eip-155 +[ERC165]: https://eips.ethereum.org/EIPS/eip-165 +[ERC672]: https://github.com/ethereum/EIPs/issues/672 +[ERC820]: https://eips.ethereum.org/EIPS/eip-820 +[ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 +[ERC1820 registry smart contract]: https://github.com/0xjac/ERC1820/blob/master/contracts/ERC1820Registry.sol +[erc1820-annoucement]: https://github.com/ethereum/EIPs/issues/820#issuecomment-464109166 +[erc820-bug]: https://github.com/ethereum/EIPs/issues/820#issuecomment-452465748 +[erc820-fix]: https://github.com/ethereum/EIPs/issues/820#issuecomment-454021564 +[manager]: #manager +[lookup]: #get-an-implementation-of-an-interface-for-an-address +[ERC165 Cache]: #erc165-cache +[Nick's article]: https://medium.com/@weka/how-to-send-ether-to-11-440-people-187e332566b7 +[0xjac/ERC1820]: https://github.com/0xjac/ERC1820 +[CC0]: https://creativecommons.org/publicdomain/zero/1.0/ +[Nick]: https://github.com/Arachnid/ +[William Entriken]: https://github.com/fulldecent +[ENS]: https://ens.domains/ diff --git a/EIPS/eip-1822.md b/EIPS/eip-1822.md new file mode 100644 index 00000000000000..40daeaf975a4a5 --- /dev/null +++ b/EIPS/eip-1822.md @@ -0,0 +1,349 @@ +--- +eip: 1822 +title: Universal Upgradeable Proxy Standard (UUPS) +author: Gabriel Barros , Patrick Gallagher +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 + + + +- [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) + + +## 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 + +

diagram

+ +## 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 diff --git a/EIPS/eip-1829.md b/EIPS/eip-1829.md new file mode 100644 index 00000000000000..c19892e6d551d0 --- /dev/null +++ b/EIPS/eip-1829.md @@ -0,0 +1,158 @@ +--- +eip: 1829 +title: Precompile for Elliptic Curve Linear Combinations +author: Remco Bloemen +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 + + +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 precompile that takes a curve and computes a linear combination of curve points. + +## Motivation + + +## Specification + + +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 + + +**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 + + +## Test Cases + + +## Implementation + + +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/). + diff --git a/EIPS/eip-1844.md b/EIPS/eip-1844.md new file mode 100644 index 00000000000000..5bb1c2d73ade41 --- /dev/null +++ b/EIPS/eip-1844.md @@ -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/). diff --git a/EIPS/eip-1872.md b/EIPS/eip-1872.md new file mode 100644 index 00000000000000..8ef9e265f4ab6f --- /dev/null +++ b/EIPS/eip-1872.md @@ -0,0 +1,217 @@ +--- +eip: 1872 +title: Ethereum Network Upgrade Windows +author: Danno Ferrin (@shemnon) +discussions-to: https://ethereum-magicians.org/t/eip-ethereum-network-upgrade-windows/ +status: Draft +type: Meta +created: 2018-03-25 +--- + +## Simple Summary + +A proposal to define a limited number of annual time windows in which network +upgrades (aka hard forks) should be performed within. Policies for scheduling +network upgrades outside these windows are also described. + +## Abstract + +Four different weeks, spaced roughly evenly throughout the year, are targeted +for network upgrades to be launched. Regular network upgrades should announce +their intention to launch in a particular window early in their process and +choose a block number four to six weeks prior to that window. If a network +upgrade is cancelled then it would be rescheduled for the next window. Not all +windows will be used. Priority upgrades outside the roadmap may be scheduled in +the third week of any month, but such use is discouraged. Critical upgrades are +scheduled as needed. + +## Motivation + +The aim of this EIP is to provide some level of regularity and predictability to +the Ethereum network upgrade/hard fork process. This will allow service +providers such as exchanges and node operators a predictable framework to +schedule activities around. This also provides a framework to regularize the +delivery of network upgrades. + +## Specification + +Scheduling is defined for three categories of network upgrades. First are +`Roadmap` network upgrades that include deliberate protocol improvements. Next +are `Priority` network updates, where there are technical reasons that +necessitate a prompt protocol change but these reasons do not present a systemic +risk to the protocol or the ecosystem. Finally, `Critical` network upgrades are +to address issues that present a systemic risk to the protocol or the ecosystem. + +### Roadmap Network Upgrades + +Roadmap network upgrades are network upgrades that are deliberate and measured +to improve the protocol and ecosystem. Historical examples are Homestead, +Byzantium, and Constantinople. + +Roadmap network upgrades should be scheduled in one of four windows: the week +with the third Wednesday in January, April, July, and October. When initiating a +network upgrade or early in the planning process a particular window should be +targeted. + +> **Note to reviewers:** The months and week chosen are to provide an initial +> recommendation and are easily modifiable prior to final call. They thread the +> needle between many third quarter and fourth quarter holidays. + +Implementors are expected to have software for a Roadmap network upgrade ready +two to four weeks prior to the upgrade. Hence a block number for the network +upgrade should be chosen four to six weeks prior to the network upgrade window. +Scheduling details such as whether this choice is made prior to or after testnet +deployment are out of scope of this EIP. + +Depending on the release cadence of Roadmap network upgrades some windows will +not be used. For example if a six month release cadence is chosen a roadmap +upgrade would not occur in adjacent upgrade windows. Hence for a six month +cadence if a roadmap upgrade occurred in April then the July window would not be +used for network upgrades. + +If a planned roadmap upgrade needs to be rescheduled then strong consideration +should be given to rescheduling the upgrade for the next window in three months +time. For the case of a six month cadence this may cause releases to be in +adjacent release windows. For a three month cadence the next network upgrade +would be merged with the current upgrade or the next network upgrade would be +delayed. + +To be compatible with the scheduled release windows the cadence of the Roadmap +Network Upgrades should be a multiple of three months. Whether it is three, six, +nine, or more month cadence is out of scope of this EIP. + +### Priority Network Upgrades + +Priority network upgrades are reserved for upgrades that require more urgency +than a roadmap network upgrade yet do not present a systemic risk to the network +or the ecosystem. To date there have been no examples of a priority upgrade. +Possible examples may include roadmap upgrades that need to occur in multiple +upgrades or for security risks that have a existing mitigation in place that +would be better served by a network upgrade. Another possible reason may be to +defuse the difficulty bomb due to postponed roadmap upgrades. + +Priority network upgrades are best launched in unused roadmap launch windows, +namely the third week of January, April, July, and October. If necessary they +may be launched in the third week of any month, but strong consideration and +preference should be given to unused roadmap launch windows. + +Priority network upgrades should be announced and a block chosen far enough in +advance so major clients implementors can release software with the needed block +number in a timely fashion. These releases should occur at least a week before +the launch window. Hence priority launch windows should be chosen two to four +weeks in advance. + +### Critical Network Upgrades + +Critical network upgrades are network upgrades that are designed to address +systemic risks to the protocol or to the ecosystem. Historical examples include +Dao Fork, Tangerine Whistle, and Spurious Dragon. + +This EIP provides neither guidance nor restrictions to the development and +deployment of these emergency hard forks. These upgrades are typically launched +promptly after a solution to the systemic risk is agreed upon between the client +implementors. + +It is recommended that such upgrades perform the minimum amount of changes +needed to address the issues that caused the need for the Critical network +upgrade and that other changes be integrated into subsequent Priority and +Roadmap network upgrades. + +### Network Upgrade Block Number Choice + +When choosing an activation block the number can be used to communicate the role +of a particular network in the Ethereum Ecosystem. Networks that serve as a +value store or are otherwise production grade have different stability concerns +than networks that serve as technology demonstration or are explicitly +designated for testing. + +To date all Mainnet activation blocks have ended in three or more zeros, +including Critical Network Upgrades. Ropsten and Kovan initially started with +three zeros but switched to palindromic numbers. Rinkeby has always had +palindromic activation blocks. Goerli has yet to perform a network upgrade. + +To continue this pattern network upgrade activation block numbers for mainnet +deployments and production grade networks should chose a number whose base 10 +representation ends with three or more zeros. + +For testnet and testing or development grades network operators are encouraged +to choose a block activation number that is a palindrome in base 10. + +Block numbers for Roadmap and Priority network upgrades should be chosen so that +it is forecast to occur relatively close to Wednesday at 12:00 UTC+0 during the +launch window. This should result in an actual block production occurring +sometime between Monday and Friday of the chosen week. + +## Rationale + +The rationale for defining launch windows is to give business running Ethereum +infrastructure a predictable schedule for when upgrades may or may not occur. +Knowing when a upgrade is not going to occur gives the businesses a clear time +frame within which to perform internal upgrades free from external changes. It +also provides a timetable for developers and IT professionals to schedule time +off against. + +## Backwards Compatibility + +Except for the specific launch windows the previous network upgrades would have +complied with these policies. Homestead, Byzantium, and Constantinople would +have been Roadmap Network Upgrades. There were no Priority Network Upgrades, +although Spurious Dragon would have been a good candidate. Dao Fork was a +Critical Network Upgrade in response to TheDao. Tangerine Whistle and Spurious +Dragon were critical upgrades in response to the Shanghai Spam Attacks. +Constantinople Fix (as it is termed in the reference tests) was in response to +the EIP-1283 security issues. + +If this policy were in place prior to Constantinople then the initial 2018 +launch would likely have been bumped to the next window after the Ropsten +testnet consensus failures. The EIP-1283 issues likely would have resulted in an +out of window upgrade because of the impact of the difficulty bomb. + + + + +## Implementation + +The windows in this EIP are expected to start after the Istanbul Network +upgrade, which is the next planned Roadmap upgrade. Istanbul is currently slated +for mainnet launch on 2019-10-16, which is compatible with the schedule in this +EIP. + +The Roadmap Upgrade windows starting with Istanbul would be as follows: + +| Block Target | Launch Week Range | +| ------------ | ------------------------ | +| 2019-10-16 | 2019-10-14 to 2019-10-18 | +| 2020-01-15 | 2020-01-13 to 2020-01-17 | +| 2020-04-15 | 2020-04-13 to 2020-04-17 | +| 2020-07-15 | 2020-07-13 to 2020-07-17 | +| 2020-10-21 | 2020-10-19 to 2020-10-23 | +| 2021-01-20 | 2021-01-18 to 2021-01-22 | +| 2021-04-21 | 2021-04-19 to 2021-04-23 | +| 2021-07-21 | 2021-07-19 to 2021-07-23 | +| 2021-10-20 | 2021-10-18 to 2021-10-22 | +| 2022-01-19 | 2022-01-17 to 2022-01-21 | +| 2022-04-20 | 2022-04-18 to 2022-04-22 | +| 2022-07-20 | 2022-07-18 to 2022-07-22 | +| 2022-10-19 | 2022-10-17 to 2022-10-21 | + +The Priority windows through next year, excluding Roadmap windows, are as +follows: + +| Block Target | Launch Week Range | +| ------------ | ------------------------ | +| 2019-11-20 | 2019-11-18 to 2019-11-22 | +| 2019-12-18 | 2019-12-16 to 2019-12-20 | +| 2020-02-19 | 2020-02-17 to 2020-02-21 | +| 2020-03-18 | 2020-03-16 to 2020-03-20 | +| 2020-05-20 | 2020-05-18 to 2020-05-22 | +| 2020-06-17 | 2020-06-15 to 2020-06-19 | +| 2020-08-19 | 2020-08-18 to 2020-08-21 | +| 2020-09-16 | 2020-09-14 to 2020-09-18 | +| 2020-11-18 | 2020-11-16 to 2020-11-20 | +| 2020-12-16 | 2020-12-14 to 2020-12-18 | + +## Copyright + +Copyright and related rights waived via +[CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/EIPS/eip-1884.md b/EIPS/eip-1884.md new file mode 100644 index 00000000000000..1a1f64dae9a9e7 --- /dev/null +++ b/EIPS/eip-1884.md @@ -0,0 +1,135 @@ +--- +eip: 1884 +title: Repricing for trie-size-dependent opcodes +author: Martin Holst Swende (@holiman) +type: Standards Track +category: Core +discussions-to: https://ethereum-magicians.org/t/opcode-repricing/3024 +status: Draft +created: 2019-03-28 +--- + + +## Simple Summary + +This EIP proposes repricing certain opcodes, to obtain a good balance between gas expenditure and resource consumption. + +## Abstract + +The growth of the Ethereum state has caused certain opcodes to be more resource-intensive at this point than +they were previously. This EIP proposes to raise the `gasCost` for those opcodes. + +## Motivation + +An imbalance between the price of an operation and the resource consumption (CPU time, memory etc) +has several drawbacks: + +- It could be used for attacks, by filling blocks with underpriced operations which causes excessive block processing time. +- Underpriced opcodes cause a skewed block gas limit, where sometimes blocks finish quickly but other blocks with similar gas use finish slowly. + +If operations are well-balanced, we can maximise the block gaslimit and have a more stable processing time. + +## Specification + +At block `N`, + +- The `SLOAD` operation changes from `200` to `800` gas, +- The `BALANCE` operation changes from `400` to `700` gas, +- A new opcode, `SELFBALANCE` is introduced at `0x46`. + - `SELFBALANCE` pops `0` arguments off the stack, + - `SELFBALANCE` pushes the `balance` of the current address to the stack, + - `SELFBALANCE` is priced as `GasFastStep`, at `5` gas. + +## Rationale + +Here are two charts, taken from a full sync using Geth. The execution time was measured for every opcode, and aggregated for 10K blocks. These bar charts show the top 25 'heavy' opcodes in the ranges 5M to 6M and 6M to 7M: + +![bars1](../assets/eip-1884/run3.total-bars-5.png) +![bars2](../assets/eip-1884/run3.total-bars-6.png) + +Note: It can also be seen that the `SLOAD` moves towards the top position. The `GASPRICE` opcode has position one which I believe can be optimized away within the client -- which is not the case with `SLOAD`/`BALANCE`. + +Here is another chart, showing a full sync with Geth. It represents the blocks `0` to `5.7M`, and highlights what the block processing time is spent on. + +![geth](../assets/eip-1884/geth_processing.png) + +It can be seen that `storage_reads` and `account_reads` are the two most significant factors contributing to the block processing time. + +### `SLOAD` + +`SLOAD` was repriced at [EIP-150][eip-150], from `50` to `200`. +The following graph shows a go-ethereum full sync, where each data point represents + 10K blocks. During those 10K blocks, the execution time for the opcode was aggregated. + +![graph](../assets/eip-1884/SLOAD-run3.png) + +It can be seen that the repricing at [EIP-150][eip-150] caused a steep drop, from around `67` to `23`. +Around block `5M`, it started reaching pre-[EIP-150][eip-150] levels, and at block `7M` +it was averaging on around `150` - more than double pre-eip-150 levels. + +Increasing the cost of `SLOAD` by `4` would bring it back down to around `40`. +It is to be expected that it will rise again in the future, and may need future repricing, unless +state clearing efforts are implemented before that happens. + +### `BALANCE` + +`BALANCE` (a.k.a `EXTBALANCE`) is an operation which fetches data from the state trie. It was repriced at [EIP-150][eip-150] from `20` to `400`. + +![graph](../assets/eip-1884/BALANCE-run3.png) + +It is comparable to `EXTCODESIZE` and `EXTCODEHASH`, which are priced at `700` already. + +It has a built-in high variance, since it is often used for checking the balance of `this`, +which is a inherently cheap operation, however, it can be used to lookup the balance of arbitrary account which often require trie (disk) access. + +In hindsight, it might have been a better choice to have two +opcodes: `EXTBALANCE(address)` and `SELFBALANCE`, and have two different prices. + +* This EIP proposes to extend the current opcode set. + * Unfortunately, the opcode span `0x3X` is already full, hence the suggestion to place `SELFBALANCE` in the `0x4X` range. + * As for why it is priced at `5` (`GasFastStep`) instead of `2` (`GasQuickStep`), like other similar operations: the EVM execution engine still needs a lookup into the (cached) trie, and `balance`, unlike `gasPrice` or `timeStamp`, is not constant during the execution, so it has a bit more inherent overhead. + + +## Backwards Compatibility + +The changes require a hardfork. The changes have the following consequences: + +- Certain calls will become more expensive. +- Default-functions which access the storage and may in some cases require more than`2300` gas (the minimum gas that is always available in calls). +- Contracts that assume a certain fixed gas cost for calls (or internal sections) may cease to function. + - However, these operations have already been repriced earlier, so there is a historical precedent that 'the gascost for these operations may change', which should have prevented such fixed-gas-cost assumptions from being implemented. + +I expect that certain patterns will be less used, for example the use of multiple modifiers which `SLOAD`s the same opcode will be merged into one. It may also lead to less `log` operations containing `SLOAD`ed values that are not strictly necessary. + +## Test Cases + +No test cases are implemented as of yet. + +## Implementation + +This EIP has not yet been implemented in any client. +Both these opcodes have been repriced before, and the client internals for managing reprices are already in place. + +### `SELFBALANCE` + +This is the implementation for the new opcode in go-ethereum: + +```golang + +func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address()) + return nil, nil +} + +``` + +## Security considerations + +- See backwards compatibility section. +- There are no special edgecases regarding `SELFBALANCE`, if we define it as `BALANCE` with `address` instead of popping an address from the stack -- since `BALANCE` is already well-defined. +- It should be investigated if Solidity contains any hardcoded expectations on the gas cost of these operations. + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +[eip-150]: https://eips.ethereum.org/EIPS/eip-150 diff --git a/EIPS/eip-1898.md b/EIPS/eip-1898.md new file mode 100644 index 00000000000000..7ea8da1acb231c --- /dev/null +++ b/EIPS/eip-1898.md @@ -0,0 +1,70 @@ +--- +eip: 1898 +title: Add `blockHash` to JSON-RPC methods which accept a default block parameter. +author: Charles Cooper (@charles-cooper) +type: Standards Track +category: Interface +status: Draft +created: 2019-04-01 +requires: 234 +--- + +## Simple Summary + +For JSON-RPC methods which currently accept a default block parameter, additionally allow the parameter to be a block hash. + +## Abstract + +This EIP can be considered a generalization of [EIP-234](https://github.com/ethereum/EIPs/blob/d053eb66921c5915f3e16d72c7566289e2d7c151/EIPS/eip-234.md). It would enable clients to unambiguously specify the block they want to query for certain JSON-RPC methods, even if the block is not in the canonical chain. This allows clients to maintain a coherent picture of blockchain state that they are interested in, even in the presence of reorgs, without requiring that the node maintain a persistent connection with the client or store any client-specific state. + +## Specification + +The following JSON-RPC methods are affected: +- `eth_getBalance` +- `eth_getStorageAt` +- `eth_getTransactionCount` +- `eth_getCode` +- `eth_call` +- `eth_getProof` + +The following options, quoted from the [JSON-RPC spec](https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter), are currently possible for the defaultBlock parameter: +> - HEX String - an integer block number +> - String "earliest" for the earliest/genesis block +> - String "latest" - for the latest mined block +> - String "pending" - for the pending state/transactions + +Since there is no way to clearly distinguish between a DATA parameter and a QUANTITY parameter, this EIP proposes a new scheme for the block parameter. The following option is additionally allowed: +- OBJECT + - `blockNumber`: QUANTITY - a block number + - `blockHash`: DATA - a block hash + +To maintain backwards compatibility, the block number may be specified either as a hex string or using the new block parameter scheme. In other words, the following are equivalent for the default block parameter: +- `"earliest"` +- `"0x0"` +- `{ "blockNumber": "0x0" }` +- `{ "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" }` (hash of the genesis block on the Ethereum main chain) + +## Rationale + +Currently, the state-querying JSON-RPC methods specified above have no option to unambiguously specify which block to query the state for. This can cause issues for applications which need to make multiple calls to the RPC. For instance, a wallet which just executed a transfer may want to display the balances of both the sender and recipient. If there is a re-org in between when the balance of the sender is queried via `eth_getBalance` and when the balance of the recipient is queried, the balances may not reconcile. As a slightly more complicated example, the UI for a decentralized exchange (which hosts orders on-chain) may walk a list of orders by calling `eth_call` for each of them to get the order data. Another type of use case is where an application needs to make a decision based on multiple pieces of state, e.g. a payout predicated on simultaneous ownership of two NFTs. + +In order to ensure that the state is coherent (i.e., `eth_call` was called with exactly the same block for every call), the application may currently use one of several strategies: +- Decide on a block number to use (e.g., the latest block number known to the application). After each `eth_call` using that block number, call `eth_getBlockByNumber`, also with that block number. If the block hash does not match the known hash for that block number, rollback the current activity and retry from the beginning. This adds `O(n)` invocations as baseline overhead and another `O(n)` invocations for every retry needed. Moreover, there is no way to detect the (unlikely but possible) case that the relevant block was reorged out before `eth_call`, and then reorged back in before `eth_getBlockByNumber`. +- Rely on logs, which *can* be queried unambiguously thanks to the `blockHash` parameter. However, this requires semantic support from the smart contract; if the smart contract does not emit appropriate events, the client will not be able to reconstruct the specific state it is interested in. +- Rely on non-standard extensions like `parity_subscribe`. This requires a persistent connection between the client and node (via IPC or websockets), increases coupling between the client and the node, and cannot handle use cases where there are dependencies between invocations of `eth_call`, for example, walking a linked list. + +Allowing `eth_call` and friends to unambiguously specify the block to be queried give the application developer a robust and intuitive way to solve these problems. Multiple sequential queries will query the same state, enabling the application developer to not worry about inconsistencies in their view of the blockchain state. + +## Backwards Compatibility + +Backwards compatible. + +## Test Cases + +## Implementation + +None yet. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/EIPS/eip-190.md b/EIPS/eip-190.md index 6e5d924733f1bc..a56bc332cf5877 100644 --- a/EIPS/eip-190.md +++ b/EIPS/eip-190.md @@ -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) diff --git a/EIPS/eip-191.md b/EIPS/eip-191.md index 63b53ea58c874d..f3b79ae5ba8bb3 100644 --- a/EIPS/eip-191.md +++ b/EIPS/eip-191.md @@ -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 diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 40d593157e1781..a84396df6856f1 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -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. diff --git a/EIPS/eip-225.md b/EIPS/eip-225.md new file mode 100644 index 00000000000000..2404a73bd4fa6e --- /dev/null +++ b/EIPS/eip-225.md @@ -0,0 +1,475 @@ +--- +eip: 225 +title: Clique proof-of-authority consensus protocol +author: Péter Szilágyi +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/). diff --git a/EIPS/eip-55.md b/EIPS/eip-55.md index f57bb693f9d0ae..3ef0eff3d1c5fd 100644 --- a/EIPS/eip-55.md +++ b/EIPS/eip-55.md @@ -1,7 +1,7 @@ --- eip: 55 title: Mixed-case checksum address encoding -author: Vitalik Buterin +author: Vitalik Buterin , Alex Van de Sande type: Standards Track category: ERC status: Final diff --git a/EIPS/eip-600.md b/EIPS/eip-600.md new file mode 100644 index 00000000000000..07d9519a00631d --- /dev/null +++ b/EIPS/eip-600.md @@ -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: + +
+m / purpose' / subpurpose' / EIP'
+
+ +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/). diff --git a/EIPS/eip-601.md b/EIPS/eip-601.md new file mode 100644 index 00000000000000..4768679ab2305a --- /dev/null +++ b/EIPS/eip-601.md @@ -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: + +
+m / purpose' / subpurpose' / EIP' / wallet'
+
+ +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/). diff --git a/EIPS/eip-606.md b/EIPS/eip-606.md index 9273e9eb0f4ac5..74920a856e019c 100644 --- a/EIPS/eip-606.md +++ b/EIPS/eip-606.md @@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic) type: Meta status: Final created: 2017-04-23 -requires: 2, 7 +requires: 2, 7, 8 --- ## Abstract diff --git a/EIPS/eip-607.md b/EIPS/eip-607.md index 5c524c37de37dc..fe11ea7aac832f 100644 --- a/EIPS/eip-607.md +++ b/EIPS/eip-607.md @@ -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 diff --git a/EIPS/eip-608.md b/EIPS/eip-608.md index 5c5060d8cb1088..2b300b4fe6f72d 100644 --- a/EIPS/eip-608.md +++ b/EIPS/eip-608.md @@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic) type: Meta status: Final created: 2017-04-23 -requires: 150 +requires: 150, 779 --- ## Abstract diff --git a/EIPS/eip-609.md b/EIPS/eip-609.md index 94a708c4214206..daa5c6099e045c 100644 --- a/EIPS/eip-609.md +++ b/EIPS/eip-609.md @@ -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 diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 18213d3bed35c2..b870dd1ea885a1 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -4,10 +4,9 @@ title: Subroutines and Static Jumps for the EVM status: Draft type: Standards Track category: Core -author: Greg Colvin , Brooklyn Zelenka , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) -discussion to: https://github.com/ethereum/EIPs/issues/615 +author: Greg Colvin , 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: 2019-18-2 --- ## Simple Summary @@ -16,22 +15,23 @@ In the 21st century, on a blockchain circulating billions of ETH, formal specifi ## Abstract -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 the EVM possible. +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. -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. +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. ## Motivation -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. Many of these cases are undecidable at deployment time, further inhibiting static and formal analyses. +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. 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—languages with an LLVM backend include C, C++, Common Lisp, D, Fortran, Haskell, Java, Javascript, Kotlin, Lua, Objective-C, Pony, Pure, Python, Ruby, Rust, Scala, Scheme, and Swift. +* 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 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 exception halting conditions can be validated. -* The maximum use of resources can be sometimes be calculated. +* 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. @@ -42,76 +42,95 @@ Note that near-linear `(n log n)` time complexity is essential. Otherwise, spec ### Proposal -We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and propose new instructions to support their legitimate uses. +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. + +Especially important is efficient translation to and from eWasm. To that end we maintain a close correspondence between eWasm instructions and proposed EVM instructions. + +| 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 | #### Preliminaries These forms -* `INSTRUCTION x,` -* `INSTRUCTION n,` -* `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. 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.) +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 (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` 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. 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. +> `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. -* `RETURNSUB` -returns from the current subroutine to the instruction following the JUMPSUB that entered it. +> `JUMPSUB jump_target` +> +> jumps to an immediate subroutine address. -These five simple instructions form the primitives of the proposal. +> `RETURNSUB` +> +>returns from the current subroutine to the instruction following the JUMPSUB that entered it. -#### Data +#### Switches, Callbacks, and Virtual Functions -In order to validate subroutines in linear time, EVM bytecode must be sequentially scanned matching jumps to their destinations. Since creation code must 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. There needs to be a way to place data into the bytecode that will be skipped over and not validated. Such data may prove useful for other purposes as well. +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. -* `BEGINDATA` -specifies that all of the following bytes to the end of the bytecode are data, and not reachable code. +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. -#### Indirect Jumps +> `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. -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. +Dynamic jumps to a `BEGINSUB` are used to implement `O(1)` virtual functions and callbacks, which take just two pointer dereferences on most CPUs. -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. +> `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. -* `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. +#### 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. +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. -* `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. +> `PUTLOCAL n` +> +> Pops the stack to the local variable `n`. -`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. +> `GETLOCAL n` +> +> Pushes the local variable `n` onto the stack. -#### Variable Access +Local variable `n` is the nth stack item below the frame pointer, `FP[-n]`, as defined below. -These operations provide convenient access to subroutine parameters and other variables at fixed stack offsets within a subroutine. +#### Data -* `PUTLOCAL n` -Pops the top value on the stack and copies it to local variable `n`[^putlocal_n]. -[^putlocal_n]: The `n` of stack items below the frame pointer to put a value at. - -* `GETLOCAL n` -Pushes the value of local variable `n`[^getlocal_n] on the stack. -[^getlocal_n]: The `n` of stack items below the frame pointer to get a value from. +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 the nth stack item below the frame pointer—`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 @@ -123,11 +142,12 @@ Jumps to and returns from subroutines are described here in terms of 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 [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf)'s substate `s` of the machine state. - * The _stack pointer_ addresses the current top of the stack of data values, where new items are pushed. + * `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. @@ -142,33 +162,71 @@ Execution of a subroutine begins with `JUMPSUB` or `JUMPSUBV`, which * 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 + * thus beginning execution of the new subroutine. -Execution of a subroutine is suspended during and resumed after execution of nested subroutines, and ends upon encountering a `RETURNSUB`, which +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. +thus resuming execution of the enclosing subroutine or _main_ program. A `STOP` or `RETURN` also ends the execution of a subroutine. -For example, after a `JUMPSUB` to a `BEGINSUB 2, 0` like this +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_ -PUSH 12 -PUSH 13 +JUMPSUB beginsub +``` +and initializing three local variables +``` +PUSH 99 +PUSH 98 +PUSH 97 ``` the stack looks like this ``` -10 <- FP -11 -12 -13 - <- SP + 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 ``` ### Validity @@ -186,7 +244,7 @@ _Execution_ is as defined in the [Yellow Paper](https://ethereum.github.io/yello >**5** Invalid instruction -We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. +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. @@ -243,7 +301,7 @@ These changes would need to be implemented in phases at decent intervals: >**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. +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 @@ -255,7 +313,7 @@ As described above, the approach was simply to deprecate the problematic dynamic 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 +## Appendix A ### Validation Validation comprises two tasks: @@ -272,7 +330,7 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_sub[code_size] // is there a BEGINSUB at PC? is_dest[code_size] // is there a JUMPDEST at PC? sub_for_pc[code_size] // which BEGINSUB is PC in? - + bool validate_jumps(PC) { current_sub = PC @@ -292,7 +350,7 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_dest[PC] = true sub_for_pc[PC] = current_sub } - + // check that targets are in subroutine for (PC = 0; instruction = bytecode[PC]; PC = advance_pc(PC)) { @@ -316,9 +374,7 @@ Note that code like this is already run by EVMs to check dynamic jumps, includin #### 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(|E|+|V|)`[^subroutine_complexity]. - -[^subroutine_complexity]: The sum of the number of edges and number of verticies in the graph. +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. @@ -368,7 +424,7 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t return false if instruction is STOP, RETURN, or SUICIDE - return true + return true // violates single entry if instruction is BEGINSUB @@ -391,10 +447,10 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t if instruction is JUMPTO { PC = jump_target(PC) - continue + continue } - // recurse to jump to code to validate + // recurse to jump to code to validate if instruction is JUMPIF { if not validate_subroutine(jump_target(PC), return_pc, SP) @@ -411,6 +467,38 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t return true } ``` +## Appendix B +### EVM Analysis + +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. + +#### Some Tools + +* [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/) + +#### Some Papers + +* [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) + ## Copyright diff --git a/EIPS/eip-616.md b/EIPS/eip-616.md index d780108627105b..d428964215da4c 100644 --- a/EIPS/eip-616.md +++ b/EIPS/eip-616.md @@ -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 -|-|-|-|- diff --git a/EIPS/eip-663.md b/EIPS/eip-663.md new file mode 100644 index 00000000000000..47786a1d24a3a8 --- /dev/null +++ b/EIPS/eip-663.md @@ -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/). diff --git a/EIPS/eip-665.md b/EIPS/eip-665.md index a3527c30c6c968..a6dbcd716296cb 100644 --- a/EIPS/eip-665.md +++ b/EIPS/eip-665.md @@ -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 diff --git a/EIPS/eip-698.md b/EIPS/eip-698.md new file mode 100644 index 00000000000000..1235c5c9bba317 --- /dev/null +++ b/EIPS/eip-698.md @@ -0,0 +1,85 @@ +--- +eip: 698 +title: OPCODE 0x46 BLOCKREWARD +author: Cody Burns +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: `Gbase` + +Where:`µ's[0] ≡ IHR` + + +## 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/). diff --git a/EIPS/eip-712.md b/EIPS/eip-712.md index 9637275fb8cf48..f7e8f893fc12f6 100644 --- a/EIPS/eip-712.md +++ b/EIPS/eip-712.md @@ -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 diff --git a/EIPS/eip-721.md b/EIPS/eip-721.md index a1fd57808b260d..3cb20230102c36 100644 --- a/EIPS/eip-721.md +++ b/EIPS/eip-721.md @@ -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** diff --git a/EIPS/eip-725.md b/EIPS/eip-725.md index 94d6f5a650f517..c69731a5b90b48 100644 --- a/EIPS/eip-725.md +++ b/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. -## 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) +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 +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 - -Keys are cryptographic public keys, or contract addresses associated with this identity. -The structure should be as follows: +### Methods -- `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); -``` - -#### keyHasPurpose - -Returns `TRUE` if a key is present and has the given purpose. If the key is not present it returns `FALSE`. - -``` js -function keyHasPurpose(bytes32 _key, uint256 purpose) constant returns(bool exists); -``` - - -#### getKeysByPurpose - -Returns an array of public key bytes32 held by this identity. - -``` js -function getKeysByPurpose(uint256 _purpose) constant returns(bytes32[] keys); +```js +function changeOwner(address _owner); ``` +**Triggers Event:** [OwnerChanged](#ownerchanged) -#### addKey +#### getData -Adds a `_key` to the identity. The `_purpose` specifies the purpose of the key. Initially, we propose four purposes: +Returns the data at the specified key. -- `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) +```js +function getData(bytes32 _key) external view returns (bytes _value); ``` +#### setData -#### removeKey - -Removes `_key` from the identity. +Sets the data at a specific key. MUST only be called by the current owner of the contract. -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:** [DataChanged](#datachanged) -**Triggers Event:** [KeyRemoved](#keyremoved) - -``` js -function removeKey(bytes32 _key, uint256 _purpose) returns (bool success) +```js +function setData(bytes32 _key, bytes _value) external; ``` - --------------------------------------------------------- - -### 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. - -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) -``` - - -#### approve +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. -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) +```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` --------------------------------------------------------- - - -### 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 - -MUST be triggered when `addKey` was successfully called. - -``` js -event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType) -``` - - -#### KeyRemoved +#### DataChanged -MUST be triggered when `removeKey` was successfully called. +MUST be triggered when `setData` was successfully called. -``` js -event KeyRemoved(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`. -#### ExecutionRequested - -MUST be triggered when `execute` was successfully called. - -``` js -event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data) +```js +event ContractCreated(address indexed contractAddress); ``` +#### OwnerChanged -#### Executed +MUST be triggered when `changeOwner` was successfully called. -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) +```js +event OwnerChanged(address indexed ownerAddress); ``` -#### Approved +### Ownership -MUST be triggered when `approve` was successfully called. +This contract is controlled by the owner. The owner can be a smart contract or an address, or itself. -``` js -event Approved(uint256 indexed executionId, bool approved) -``` - -##### The following changes to [ERC 735](https://github.com/ethereum/EIPs/issues/735) are REQUIRED: - -#### ClaimRequested +### Data keys -MUST be triggered when `addClaim` was successfully called. +Data keys, should be the keccak256 hash of a type name. +e.g. `myNewKeyType` is `0xa94996022594f93c34a730df0ae89d1ecd69dff98c17d0387e69ce58346323a4` +#### Multiple keys of the same type -#### ClaimAdded +Multiple keys for the same key type must add a `keyTypeName-1` at the end of the key type. -MUST be triggered when `approve` was called and the claim was successfully added. +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. -## Constraints +| 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` | -- A claim can only be one type per type per issuer. +## Rationale +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. +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. -## 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. +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. -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 rationale of this standard is to function as an open and very flexible container for identity. +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; - -contract ERC725 { - - uint256 constant MANAGEMENT_KEY = 1; - uint256 constant ACTION_KEY = 2; - uint256 constant CLAIM_SIGNER_KEY = 3; - uint256 constant ENCRYPTION_KEY = 4; - - 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); +pragma solidity ^0.5.4; + +interface ERC725 { + event DataChanged(bytes32 indexed key, bytes32 indexed value); + event OwnerChanged(address indexed ownerAddress); + event ContractCreated(address indexed contractAddress); + + // address public owner; + + 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 diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 49ccbeccd1f030..7f77b0419d75d9 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -1,13 +1,13 @@ --- eip: 777 title: A New Advanced Token Standard -author: Jacques Dafflon , Jordi Baylina , Thomas Shababi +author: Jacques Dafflon , Jordi Baylina , Thomas Shababi discussions-to: https://github.com/ethereum/EIPs/issues/777 status: Draft type: Standards Track category: ERC created: 2017-11-20 -requires: 820 +requires: 1820 --- ## Simple Summary @@ -18,21 +18,40 @@ This EIP defines standard interfaces and behaviors for token contracts. This standard defines a new way to interact with a token contract while remaining backward compatible with [ERC20]. -It defines advanced features to interact with tokens. Namely, *operators* to send tokens on behalf of another address—contract or regular account—and send/receive *hooks* to offer token holders more control over their tokens. +It defines advanced features to interact with tokens. +Namely, *operators* to send tokens on behalf of another address—contract or regular account—and +send/receive *hooks* to offer token holders more control over their tokens. -It takes advantage of [ERC820] to find out whether and where to notify contracts and regular addresses when they receive tokens as well as to allow compatibility with already-deployed contracts. +It takes advantage of [ERC1820] to find out whether and where to notify contracts and regular addresses +when they receive tokens as well as to allow compatibility with already-deployed contracts. ## Motivation -This standard tries to improve the widely used [ERC20] token standard. The main advantages of this standard are: +This standard tries to improve the widely used [ERC20] token standard. +The main advantages of this standard are: 1. Uses the same philosophy as Ether in that tokens are sent with `send(dest, value, data)`. -2. Both contracts and regular addresses can control and reject which token they send by registering a `tokensToSend` hook. (Rejection is done by `revert`ing in the hook function.) -3. Both contracts and regular addresses can control and reject which token they receive by registering a `tokensReceived` hook. (Rejection is done by `revert`ing in the hook function.) -4. The `tokensReceived` hook allows to send tokens to a contract and notify it in a single transaction, unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this. -5. The token holder can "authorize" and "revoke" operators which can send tokens on their behalf. These operators are intended to be verified contracts such as an exchange, a cheque processor or an automatic charging system. -6. Every token transaction contains a `data` bytes field and a similar `operatorData` to be used freely to pass data to the recipient. -7. It is backward compatible with wallets that do not contain the `tokensReceived` hook function by deploying a proxy contract implementing the `tokensReceived` hook for the wallet. + +2. Both contracts and regular addresses can control and reject which token they send + by registering a `tokensToSend` hook. + (Rejection is done by `revert`ing in the hook function.) + +3. Both contracts and regular addresses can control and reject which token they receive + by registering a `tokensReceived` hook. + (Rejection is done by `revert`ing in the hook function.) + +4. The `tokensReceived` hook allows to send tokens to a contract and notify it in a single transaction, + unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this. + +5. The holder can "authorize" and "revoke" operators which can send tokens on their behalf. + These operators are intended to be verified contracts + such as an exchange, a cheque processor or an automatic charging system. + +6. Every token transaction contains `data` and `operatorData` bytes fields + to be used freely to pass data from the holder and the operator, respectively. + +7. It is backward compatible with wallets that do not contain the `tokensReceived` hook function + by deploying a proxy contract implementing the `tokensReceived` hook for the wallet. ## Specification @@ -40,22 +59,28 @@ This standard tries to improve the widely used [ERC20] token standard. The main ``` solidity interface ERC777Token { - function name() public view returns (string); - function symbol() public view returns (string); - function totalSupply() public view returns (uint256); - function balanceOf(address owner) public view returns (uint256); - function granularity() public view returns (uint256); - - function defaultOperators() public view returns (address[]); - function authorizeOperator(address operator) public; - function revokeOperator(address operator) public; - function isOperatorFor(address operator, address tokenHolder) public view returns (bool); - - function send(address to, uint256 amount, bytes data) public; - function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) public; + function name() external view returns (string memory); + function symbol() external view returns (string memory); + function totalSupply() external view returns (uint256); + function balanceOf(address holder) external view returns (uint256); + function granularity() external view returns (uint256); + + function defaultOperators() external view returns (address[] memory); + function isOperatorFor(address operator, address holder) external view returns (bool); + function authorizeOperator(address operator) external; + function revokeOperator(address operator) external; + + function send(address to, uint256 amount, bytes calldata data) external; + function operatorSend( + address from, + address to, + uint256 amount, + bytes calldata data, + bytes calldata operatorData + ) external; - function burn(uint256 amount, bytes data) public; - function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public; + function burn(uint256 amount, bytes calldata data) external; + function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external; event Sent( address indexed operator, @@ -66,18 +91,41 @@ interface ERC777Token { bytes operatorData ); event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); - event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData); - event AuthorizedOperator(address indexed operator, address indexed tokenHolder); - event RevokedOperator(address indexed operator, address indexed tokenHolder); + event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); + event AuthorizedOperator(address indexed operator, address indexed holder); + event RevokedOperator(address indexed operator, address indexed holder); } ``` -The token contract MUST implement the above interface. The implementation MUST follow the specifications described below. - -The token contract MUST register the `ERC777Token` interface with its own address via [ERC820]. If the contract has a switch to enable or disable [ERC777] functions, every time the switch is triggered, the token MUST register or unregister the `ERC777Token` interface for its own address accordingly via [ERC820]. (Unregistering implies setting the address to `0x0`.) - -The smallest unit—for all interactions with the token contract—MUST be `1`. I.e. all amounts and balances MUST be unsigned integers. The display denomination—to display any amount to the end user—MUST be 1018 of the smallest. - -In other words the technical denomination is similar to a wei and the display denomination is similar to an ether. It is equivalent to an [ERC20]'s `decimals` function returning `18`. E.g. if a token contract holds a balance of `500,000,000,000,000,000` (0.5×1018) for a user, the user interface SHOULD show `0.5` tokens to the user. If the user wishes to send `0.3` tokens, the contract MUST be called with an amount of `300,000,000,000,000,000` (0.3×1018). +The token contract MUST implement the above interface. +The implementation MUST follow the specifications described below. + +The token contract MUST register the `ERC777Token` interface with its own address via [ERC1820]. +This is done by calling the `setInterfaceImplementer` function on the ERC1820 registry +with the token contract address as both the address and the implementer +and the `keccak256` hash of `ERC777Token` as the interface hash. + +If the contract has a switch to enable or disable ERC777 functions, every time the switch is triggered, +the token MUST register or unregister the `ERC777Token` interface for its own address accordingly via ERC1820. +Unregistering implies calling the `setInterfaceImplementer` with the token contract address as the address, +the `keccak256` hash of `ERC777Token` as the interface hash and `0x0` as the implementer. +(See [Set An Interface For An Address][erc1820-set] in [ERC1820] for more details.) + +When interacting with the token contract, all amounts and balances MUST be unsigned integers. +I.e. Internally, all values are stored as a denomination of 1E-18 of a token. +The display denomination—to display any amount to the end user—MUST +be 1018 of the internal denomination. + +In other words, the internal denomination is similar to a wei +and the display denomination is similar to an ether. +It is equivalent to an [ERC20]'s `decimals` function returning `18`. +E.g. if a token contract returns a balance of `500,000,000,000,000,000` (0.5×1018) for a user, +the user interface MUST show `0.5` tokens to the user. +If the user wishes to send `0.3` tokens, +the contract MUST be called with an amount of `300,000,000,000,000,000` (0.3×1018). + +User Interfaces which are generated programmatically from the ABI of the token contract +MAY use and display the internal denomination. +But this MUST be made clear, for example by displaying the `uint256` type. #### **View Functions** @@ -86,243 +134,333 @@ The `view` functions detailed below MUST be implemented. **`name` function** ``` solidity - function name() public view returns (string) +function name() external view returns (string memory) ``` -Returns the name of the token, e.g., `"MyToken"`. +Get the name of the token, e.g., `"MyToken"`. +> **identifier:** `06fdde03` > **returns:** Name of the token. **`symbol` function** ``` solidity -function symbol() public view returns (string) +function symbol() external view returns (string memory) ``` -Returns the symbol of the token, e.g., `"MYT"`. +Get the symbol of the token, e.g., `"MYT"`. +> **identifier:** `95d89b41` > **returns:** Symbol of the token. **`totalSupply` function** ``` solidity -function totalSupply() public view returns (uint256) +function totalSupply() external view returns (uint256) ``` Get the total number of minted tokens. -*NOTE*: The total supply MUST be equal to the sum of the balances of all addresses—as returned by the `balanceOf` function. - -*NOTE*: The total supply MUST be equal to the sum of all the minted tokens as defined in all the `Minted` events minus the sum of all the burned tokens as defined in all the `Burned` events. (This applies as well to [tokens minted when the token contract is created][initial supply].) +*NOTE*: The total supply MUST be equal to the sum of the balances of all addresses—as +returned by the `balanceOf` function. +*NOTE*: The total supply MUST be equal to the sum of all the minted tokens +as defined in all the `Minted` events minus the sum of all the burned tokens as defined in all the `Burned` events. +> **identifier:** `18160ddd` > **returns:** Total supply of tokens currently in circulation. **`balanceOf` function** ``` solidity -function balanceOf(address tokenHolder) public view returns (uint256) +function balanceOf(address holder) external view returns (uint256) ``` -Get the balance of the account with address `tokenHolder`. +Get the balance of the account with address `holder`. The balance MUST be zero (`0`) or higher. +> **identifier:** `70a08231` > **parameters** -> `tokenHolder`: Address for which the balance is returned. +> `holder`: Address for which the balance is returned. > -> **returns:** Amount of token held by `tokenHolder` in the token contract. +> **returns:** Amount of tokens held by `holder` in the token contract. **`granularity` function** ``` solidity -function granularity() public view returns (uint256) +function granularity() external view returns (uint256) ``` Get the smallest part of the token that's not divisible. -In other words, the granularity is the smallest number of tokens (in the basic unit) which MAY be minted, sent or burned at any time. +In other words, the granularity is the smallest number of tokens (in the internal denomination) +which MAY be minted, sent or burned at any time. The following rules MUST be applied regarding the *granularity*: - The *granularity* value MUST be set at creation time. -- The *granularity* value MUST NOT be changed ever. + +- The *granularity* value MUST NOT be changed, ever. + - The *granularity* value MUST be greater or equal to `1`. -- Any minting, send or burning of tokens MUST be a multiple of the *granularity* value. -- Any operation that would result in a balance that's not a multiple of the *granularity* value MUST be considered invalid, and the transaction MUST `revert`. -*NOTE*: Most of the tokens SHOULD be fully partitionable. I.e., this function SHOULD return `1` unless there is a good reason for not allowing any fraction of the token. +- Any amount of tokens (in the internal denomination) minted, sent or burnt + MUST be a multiple of the *granularity* value. -> **returns:** The smallest non-divisible part of the token. +- Any operation that would result in a balance that's not a multiple of the *granularity* value + MUST be considered invalid, and the transaction MUST `revert`. -*NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions, defined under the [operators] for consistency. +*NOTE*: Most of the tokens SHOULD be fully partition-able. +I.e., this function SHOULD return `1` unless there is a good reason for not allowing any fraction of the token. -*[ERC20] compatibility requirement*: -The decimals of the token MUST always be `18`. For a *pure* ERC777 token the [ERC20] `decimal` function is OPTIONAL, and its existence SHALL NOT be relied upon when interacting with the token contract. (The decimal value of `18` is implied.) For an [ERC20] compatible token, the `decimal` function is REQUIRED and MUST return `18`. (In [ERC20], the `decimals` function is OPTIONAL. If the function is not present, the `decimals` value is not clearly defined and may be assumed to be `0`. Hence for compatibility reasons, `decimals` MUST be implemented for [ERC20] compatible tokens.) +> **identifier:** `556f0dc7` +> **returns:** The smallest non-divisible part of the token. + +*NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions, +defined under the [operators] for consistency. *[ERC20] compatibility requirement*: -The `name`, `symbol`, `totalSupply`, and `balanceOf` `view` functions MUST be backward compatible with [ERC20]. +The decimals of the token MUST always be `18`. +For a *pure* ERC777 token the [ERC20] `decimals` function is OPTIONAL, +and its existence SHALL NOT be relied upon when interacting with the token contract. +(The decimal value of `18` is implied.) +For an [ERC20] compatible token, the `decimals` function is REQUIRED and MUST return `18`. +(In [ERC20], the `decimals` function is OPTIONAL. +If the function is not present, the `decimals` value is not clearly defined and may be assumed to be `0`. +Hence for compatibility reasons, `decimals` MUST be implemented for [ERC20] compatible tokens.) #### **Operators** -An `operator` is an address which is allowed to send and burn tokens on behalf of another address. +An `operator` is an address which is allowed to send and burn tokens on behalf of some *holder*. -When an address becomes an *operator* for a *token holder*, an `AuthorizedOperator` event MUST be emitted. The `AuthorizedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively. +When an address becomes an *operator* for a *holder*, an `AuthorizedOperator` event MUST be emitted. +The `AuthorizedOperator`'s `operator` (topic 1) and `holder` (topic 2) +MUST be the addresses of the *operator* and the *holder* respectively. -When a *token holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted. The `RevokedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively. +When a *holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted. +The `RevokedOperator`'s `operator` (topic 1) and `holder` (topic 2) +MUST be the addresses of the *operator* and the *holder* respectively. -*NOTE*: A *token holder* MAY have multiple *operators* at the same time. +*NOTE*: A *holder* MAY have multiple *operators* at the same time. -The token MAY define *default operators*. A *default operator* is an implicitly authorized *operator* for all *token holders*. `AuthorizedOperator` events MUST NOT be emitted when defining the *default operators*. The rules below apply to *default operators*: +The token MAY define *default operators*. +A *default operator* is an implicitly authorized *operator* for all *holders*. +`AuthorizedOperator` events MUST NOT be emitted when defining the *default operators*. +The rules below apply to *default operators*: - The token contract MUST define *default operators* at creation time. + - The *default operators* MUST be invariants. I.e., the token contract MUST NOT add or remove *default operators* ever. + - `AuthorizedOperator` events MUST NOT be emitted when defining *default operators*. -- A *token holder* MUST be allowed revoke a *default operator* (unless the *token holder* is the *default operator* in question). -- A *token holder* MUST be allowed to re-authorize a previously revoked *default operator*. -- When a *default operator* is explicitly authorized or revoked for a specific *token holder*, an `AuthorizedOperator` or `RevokedOperator` event (respectively) MUST be emitted. + +- A *holder* MUST be allowed revoke a *default operator* + (unless the *holder* is the *default operator* in question). + +- A *holder* MUST be allowed to re-authorize a previously revoked *default operator*. + +- When a *default operator* is explicitly authorized or revoked for a specific *holder*, + an `AuthorizedOperator` or `RevokedOperator` event (respectively) MUST be emitted. The following rules apply to any *operator*: - An address MUST always be an *operator* for itself. Hence an address MUST NOT ever be revoked as its own *operator*. -- If an address is an *operator* for a *token holder*, `isOperatorFor` MUST return `true`. -- If an address is not an *operator* for a *token holder*, `isOperatorFor` MUST return `false`. -- The token contract MUST emit an `AuthorizedOperator` event with the correct values when a *token holder* authorizes an address as its *operator* as defined in the [`AuthorizedOperator` Event][authorizedoperator]. -- The token contract MUST emit a `RevokedOperator` event with the correct values when a *token holder* revokes an address as its *operator* as defined in the [`RevokedOperator` Event][revokedoperator]. -*NOTE*: A *token holder* MAY authorize an already authorized *operator*. An `AuthorizedOperator` MUST be emitted each time. +- If an address is an *operator* for a *holder*, `isOperatorFor` MUST return `true`. + +- If an address is not an *operator* for a *holder*, `isOperatorFor` MUST return `false`. + +- The token contract MUST emit an `AuthorizedOperator` event with the correct values + when a *holder* authorizes an address as its *operator* as defined in the + [`AuthorizedOperator` Event][authorizedoperator]. + +- The token contract MUST emit a `RevokedOperator` event with the correct values + when a *holder* revokes an address as its *operator* as defined in the + [`RevokedOperator` Event][revokedoperator]. -*NOTE*: A *token holder* MAY revoke an already revoked *operator*. A `RevokedOperator` MUST be emitted each time. +*NOTE*: A *holder* MAY authorize an already authorized *operator*. +An `AuthorizedOperator` MUST be emitted each time. -*NOTE*: A token holder MAY have multiple *operators* at the same time. +*NOTE*: A *holder* MAY revoke an already revoked *operator*. +A `RevokedOperator` MUST be emitted each time. **`AuthorizedOperator` event** ``` solidity -event AuthorizedOperator(address indexed operator, address indexed tokenHolder) +event AuthorizedOperator(address indexed operator, address indexed holder) ``` -Indicates the authorization of `operator` as an *operator* for `tokenHolder`. +Indicates the authorization of `operator` as an *operator* for `holder`. *NOTE*: This event MUST NOT be emitted outside of an *operator* authorization process. > **parameters** -> `operator`: Address which became an *operator* of `tokenHolder`. -> `tokenHolder`: Address of a token holder which authorized the `operator` address as an *operator*. - +> `operator`: Address which became an *operator* of `holder`. +> `holder`: Address of a *holder* which authorized the `operator` address as an *operator*. **`RevokedOperator` event** ``` solidity -event RevokedOperator(address indexed operator, address indexed tokenHolder) +event RevokedOperator(address indexed operator, address indexed holder) ``` -Indicates the revocation of `operator` as an *operator* for `tokenHolder`. +Indicates the revocation of `operator` as an *operator* for `holder`. *NOTE*: This event MUST NOT be emitted outside of an *operator* revocation process. > **parameters** -> `operator`: Address which was revoked as an *operator* of `tokenHolder`. -> `tokenHolder`: Address of a token holder which revoked the `operator` address as an *operator*. +> `operator`: Address which was revoked as an *operator* of `holder`. +> `holder`: Address of a *holder* which revoked the `operator` address as an *operator*. -The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below MUST be implemented to manage *operators*. +The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below +MUST be implemented to manage *operators*. Token contracts MAY implement other functions to manage *operators*. **`defaultOperators` function** ``` solidity -function defaultOperators() public view returns (address[]) +function defaultOperators() external view returns (address[] memory) ``` Get the list of *default operators* as defined by the token contract. *NOTE*: If the token contract does not have any *default operators*, this function MUST return an empty list. +> **identifier:** `06e48538` > **returns:** List of addresses of all the *default operators*. **`authorizeOperator` function** ``` solidity -function authorizeOperator(address operator) public +function authorizeOperator(address operator) external ``` Set a third party `operator` address as an *operator* of `msg.sender` to send and burn tokens on its behalf. -*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. Hence this function MUST `revert` if it is called to authorize the token holder (`msg.sender`) as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`). +*NOTE*: The *holder* (`msg.sender`) is always an *operator* for itself. +This right SHALL NOT be revoked. +Hence this function MUST `revert` if it is called to authorize the holder (`msg.sender`) +as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`). +> **identifier:** `959b8c3f` > **parameters** > `operator`: Address to set as an *operator* for `msg.sender`. **`revokeOperator` function** ``` solidity -function revokeOperator(address operator) public +function revokeOperator(address operator) external ``` -Remove the right of the `operator` address to be an *operator* for `msg.sender` and to send and burn tokens on its behalf. +Remove the right of the `operator` address to be an *operator* for `msg.sender` +and to send and burn tokens on its behalf. -*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. Hence this function MUST `revert` if it is called to revoke the token holder (`msg.sender`) as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`). +*NOTE*: The *holder* (`msg.sender`) is always an *operator* for itself. +This right SHALL NOT be revoked. +Hence this function MUST `revert` if it is called to revoke the holder (`msg.sender`) +as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`). +> **identifier:** `fad8b32a` > **parameters** > `operator`: Address to rescind as an *operator* for `msg.sender`. **`isOperatorFor` function** ``` solidity -function isOperatorFor(address operator, address tokenHolder) public view returns (bool) +function isOperatorFor(address operator, address holder) external view returns (bool) ``` -Indicate whether the `operator` address is an *operator* of the `tokenHolder` address. +Indicate whether the `operator` address is an *operator* of the `holder` address. +> **identifier:** `d95b6371` > **parameters** -> `operator`: Address which may be an *operator* of `tokenHolder`. -> `tokenHolder`: Address of a token holder which may have the `operator` address as an *operator*. +> `operator`: Address which may be an *operator* of `holder`. +> `holder`: Address of a *holder* which may have the `operator` address as an *operator*. > -> **returns:** `true` if `operator` is an *operator* of `tokenHolder` and `false` otherwise. +> **returns:** `true` if `operator` is an *operator* of `holder` and `false` otherwise. -*NOTE*: To know which addresses are *operators* for a given *token holder*, one MUST call `isOperatorFor` with the *token holder* for each *default operator* and parse the `AuthorizedOperator`, and `RevokedOperator` events for the *token holder* in question. +*NOTE*: To know which addresses are *operators* for a given *holder*, +one MUST call `isOperatorFor` with the *holder* for each *default operator* +and parse the `AuthorizedOperator`, and `RevokedOperator` events for the *holder* in question. #### **Sending Tokens** -When an *operator* sends an `amount` of tokens from a *token holder* to a *recipient* with the associated `data` and `operatorData`, the token contract MUST apply the following rules: +When an *operator* sends an `amount` of tokens from a *holder* to a *recipient* +with the associated `data` and `operatorData`, the token contract MUST apply the following rules: + +- Any authorized *operator* MAY send tokens to any *recipient* (except to `0x0`). + +- The balance of the *holder* MUST be decreased by the `amount`. -- Any *token holder* MAY send tokens to any *recipient*. -- The balance of the *token holder* MUST be decreased by the `amount`. - The balance of the *recipient* MUST be increased by the `amount`. -- The balance of the *token holder* MUST be greater or equal to the `amount`—such that its resulting balance is greater or equal to zero (`0`) after the send. + +- The balance of the *holder* MUST be greater or equal to the `amount`—such + that its resulting balance is greater or equal to zero (`0`) after the send. + - The token contract MUST emit a `Sent` event with the correct values as defined in the [`Sent` Event][sent]. -- The *operator* MAY communicate any information in the `operatorData`. -- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC820]. -- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820]. -- The `data` and `operatorData` MUST be immutable during the entire send process—hence the same `data` and `operatorData` MUST be used to call both hooks and emit the `Sent` event. + +- The *operator* MAY include information in the `operatorData`. + +- The token contract MUST call the `tokensToSend` hook of the *holder* + if the *holder* registers an `ERC777TokensSender` implementation via [ERC1820]. + +- The token contract MUST call the `tokensReceived` hook of the *recipient* + if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. + +- The `data` and `operatorData` MUST be immutable during the entire send process—hence + the same `data` and `operatorData` MUST be used to call both hooks and emit the `Sent` event. The token contract MUST `revert` when sending in any of the following cases: -- The *operator* address is not an authorized operator for the *token holder*. -- The resulting *token holder* balance or *recipient* balance after the send is not a multiple of the *granularity* defined by the token contract. -- The address of the *token holder* or the *recipient* is `0x0`. +- The *operator* address is not an authorized operator for the *holder*. + +- The resulting *holder* balance or *recipient* balance after the send + is not a multiple of the *granularity* defined by the token contract. + +- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. + +- The address of the *holder* or the *recipient* is `0x0`. + - Any of the resulting balances becomes negative, i.e. becomes less than zero (`0`). -The token contract MAY send tokens from many *token holders*, to many *recipients*, or both. In this case: +The token contract MAY send tokens from many *holders*, to many *recipients*, or both. In this case: -- The previous send rules MUST apply to all the *token holders* and all the *recipients*. +- The previous send rules MUST apply to all the *holders* and all the *recipients*. - The sum of all the balances incremented MUST be equal to the total sent `amount`. - The sum of all the balances decremented MUST be equal to the total sent `amount`. -- A `Sent` event MUST be emitted for every *token holder* and *recipient* pair with the corresponding amount for each pair. +- A `Sent` event MUST be emitted for every *holder* and *recipient* pair with the corresponding amount for each pair. - The sum of all the amounts from the `Sent` event MUST be equal to the total sent `amount`. -*NOTE*: Mechanisms such as applying a fee on a send is considered as a send to multiple *recipients*: the intended *recipient* and the fee *recipient*. +*NOTE*: Mechanisms such as applying a fee on a send is considered as a send to multiple *recipients*: +the intended *recipient* and the fee *recipient*. -*NOTE*: Transfer of tokens MAY be chained. For example, if a contract upon receiving tokens sends them further to another address. In this case, the previous send rules apply to each send, in order. +*NOTE*: Transfer of tokens MAY be chained. +For example, if a contract upon receiving tokens sends them further to another address. +In this case, the previous send rules apply to each send, in order. *NOTE*: Sending an amount of zero (`0`) tokens is valid and MUST be treated as a regular send. *Implementation Requirement*: - The token contract MUST call the `tokensToSend` hook *before* updating the state. - The token contract MUST call the `tokensReceived` hook *after* updating the state. -I.e., `tokensToSend` MUST be called first, then the balances MUST be updated to reflect the send, and finally `tokensReceived` MUST be called *afterward*. Thus a `balanceOf` call within `tokensToSend` returns the balance of the address *before* the send and a `balanceOf` call within `tokensReceived` returns the balance of the address *after* the send. +I.e., `tokensToSend` MUST be called first, +then the balances MUST be updated to reflect the send, +and finally `tokensReceived` MUST be called *afterward*. +Thus a `balanceOf` call within `tokensToSend` returns the balance of the address *before* the send +and a `balanceOf` call within `tokensReceived` returns the balance of the address *after* the send. + +*NOTE*: The `data` field contains information provided by the *holder*—similar +to the data field in a regular ether send transaction. +The `tokensToSend()` hook, the `tokensReceived()`, or both +MAY use the information to decide if they wish to reject the transaction. -*NOTE*: The `data` field contains extra information intended for, and defined by the recipient— similar to the data field in a regular ether send transaction. Typically, `data` is used to describe the intent behind the send. The `operatorData` MUST only be provided by the *operator*. It is intended more for logging purposes and particular cases. (Examples include payment references, cheque numbers, countersignatures and more.) In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. +*NOTE*: The `operatorData` field is analogous to the `data` field except it SHALL be provided by the *operator*. + +The `operatorData` MUST only be provided by the *operator*. +It is intended more for logging purposes and particular cases. +(Examples include payment references, cheque numbers, countersignatures and more.) +In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. **`Sent` event** @@ -336,78 +474,96 @@ Indicate a send of `amount` of tokens from the `from` address to the `to` addres > **parameters** > `operator`: Address which triggered the send. -> `from`: Token holder. -> `to`: Token recipient. -> `amount`: Number of tokens to send. -> `data`: Information attached to the send, and intended for the recipient (`to`). -> `operatorData`: Information attached to the send by the `operator`. +> `from`: *Holder* whose tokens were sent. +> `to`: Recipient of the tokens. +> `amount`: Number of tokens sent. +> `data`: Information provided by the *holder*. +> `operatorData`: Information provided by the *operator*. The `send` and `operatorSend` functions described below MUST be implemented to send tokens. Token contracts MAY implement other functions to send tokens. -*NOTE*: An address MAY send an amount of `0`, which is valid and MUST be treated as a regular send. - **`send` function** ``` solidity -function send(address to, uint256 amount, bytes data) public +function send(address to, uint256 amount, bytes calldata data) external ``` Send the `amount` of tokens from the address `msg.sender` to the address `to`. -The *operator* and the *token holder* MUST both be the `msg.sender`. +The *operator* and the *holder* MUST both be the `msg.sender`. +> **identifier:** `9bd9bbc6` > **parameters** -> `to`: Token recipient. +> `to`: Recipient of the tokens. > `amount`: Number of tokens to send. -> `data`: Information attached to the send, and intended for the recipient (`to`). +> `data`: Information provided by the *holder*. **`operatorSend` function** ``` solidity -function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) public +function operatorSend(address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external ``` Send the `amount` of tokens on behalf of the address `from` to the address `to`. -The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the `from` (*token holder*) used for the send MUST be `msg.sender` (the `operator`). - -*Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the send process MUST `revert`. +*Reminder*: If the *operator* address is not an authorized operator of the `from` address, +then the send process MUST `revert`. -*NOTE*: `from` and `msg.sender` MAY be the same address. I.e., an address MAY call `operatorSend` for itself. This call MUST be equivalent to `send` with the addition that the *operator* MAY specify an explicit value for `operatorData` (which cannot be done with the `send` function). +*NOTE*: `from` and `msg.sender` MAY be the same address. +I.e., an address MAY call `operatorSend` for itself. +This call MUST be equivalent to `send` with the addition +that the *operator* MAY specify an explicit value for `operatorData` +(which cannot be done with the `send` function). +> **identifier:** `62ad1b83` > **parameters** -> `from`: Token holder (or `0x0` to set `from` to `msg.sender`). -> `to`: Token recipient. +> `from`: *Holder* whose tokens are being sent. +> `to`: Recipient of the tokens. > `amount`: Number of tokens to send. -> `data`: Information attached to the send, and intended for the recipient (`to`). -> `operatorData`: Information attached to the send by the `operator`. +> `data`: Information provided by the *holder*. +> `operatorData`: Information provided by the *operator*. #### **Minting Tokens** -Minting tokens is the act of producing new tokens. [ERC777] intentionally does not define specific functions to mint tokens. This intent comes from the wish not to limit the use of the [ERC777] standard as the minting process is generally specific for every token. +Minting tokens is the act of producing new tokens. +[ERC777] intentionally does not define specific functions to mint tokens. +This intent comes from the wish not to limit the use of the [ERC777] standard +as the minting process is generally specific for every token. Nonetheless, the rules below MUST be respected when minting for a *recipient*: - Tokens MAY be minted for any *recipient* address. + - The total supply MUST be increased by the amount of tokens minted. + - The balance of `0x0` MUST NOT be decreased. + - The balance of the *recipient* MUST be increased by the amount of tokens minted. + - The token contract MUST emit a `Minted` event with the correct values as defined in the [`Minted` Event][minted]. -- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820]. -- The `data` and `operatorData` MUST be immutable during the entire mint process—hence the same `data` and `operatorData` MUST be used to call the `tokensReceived` hook and emit the `Minted` event. + +- The token contract MUST call the `tokensReceived` hook of the *recipient* + if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. + +- The `data` and `operatorData` MUST be immutable during the entire mint process—hence + the same `data` and `operatorData` MUST be used to call the `tokensReceived` hook and emit the `Minted` event. The token contract MUST `revert` when minting in any of the following cases: - The resulting *recipient* balance after the mint is not a multiple of the *granularity* defined by the token contract. -- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC820]. +- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. - The address of the *recipient* is `0x0`. - -*NOTE*: The initial token supply at the creation of the token contract MUST be considered as minting for the amount of the initial supply to the address(es) receiving the initial supply. This means one or more `Minted` events must be emitted and the `tokensReceived` hook of the recipient(s) MUST be called. +*NOTE*: The initial token supply at the creation of the token contract MUST be considered as minting +for the amount of the initial supply to the address(es) receiving the initial supply. +This means one or more `Minted` events must be emitted +and the `tokensReceived` hook of the recipient(s) MUST be called. *[ERC20] compatibility requirement*: -While a `Sent` event MUST NOT be emitted when minting, if the token contract is [ERC20] backward compatible, a `Transfer` event with the `from` parameter set to `0x0` SHOULD be emitted as defined in the [ERC20] standard. +While a `Sent` event MUST NOT be emitted when minting, +if the token contract is [ERC20] backward compatible, +a `Transfer` event with the `from` parameter set to `0x0` SHOULD be emitted as defined in the [ERC20] standard. The token contract MAY mint tokens for multiple *recipients* at once. In this case: @@ -418,7 +574,13 @@ The token contract MAY mint tokens for multiple *recipients* at once. In this ca *NOTE*: Minting an amount of zero (`0`) tokens is valid and MUST be treated as a regular mint. -*NOTE*: The `data` field contains extra information intended for, and defined by the recipient— similar to the data field in a regular ether send transaction. Typically, `data` is used to describe the intent behind the mint. The `operatorData` MUST only be provided by the *operator*. It is intended more for logging purposes and particular cases. (Examples include payment references, cheque numbers, countersignatures and more.) In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. +*NOTE*: While during a send or a burn, the data is provided by the *holder*, it is inapplicable for a mint. +In this case the data MAY be provided by the token contract or the *operator*, +for example to ensure a successful minting to a *holder* expecting specific data. + +*NOTE*: The `operatorData` field contains information provided by the *operator*—similar +to the data field in a regular ether send transaction. +The `tokensReceived()` hooks MAY use the information to decide if it wish to reject the transaction. **`Minted` event** @@ -432,49 +594,74 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator` > **parameters** > `operator`: Address which triggered the mint. -> `to`: Token recipient. +> `to`: Recipient of the tokens. > `amount`: Number of tokens minted. -> `data`: Information attached to the minting, and intended for the recipient (`to`). -> `operatorData`: Information attached to the minting by the `operator`. +> `data`: Information provided for the *recipient*. +> `operatorData`: Information provided by the *operator*. #### **Burning Tokens** -Burning tokens is the act of destroying existing tokens. [ERC777] explicitly defines two functions to burn tokens (`burn` and `operatorBurn`). These functions facilitate the integration of the burning process in wallets and dapps. However, the token contract MAY prevent some or all *token holders* from burning tokens for any reason. The token contract MAY also define other functions to burn tokens. +Burning tokens is the act of destroying existing tokens. +[ERC777] explicitly defines two functions to burn tokens (`burn` and `operatorBurn`). +These functions facilitate the integration of the burning process in wallets and dapps. +However, the token contract MAY prevent some or all *holders* from burning tokens for any reason. +The token contract MAY also define other functions to burn tokens. -The rules below MUST be respected when burning the tokens of a *token holder*: +The rules below MUST be respected when burning the tokens of a *holder*: + +- Tokens MAY be burned from any *holder* address. -- Tokens MAY be burned from any *token holder* address. - The total supply MUST be decreased by the amount of tokens burned. + - The balance of `0x0` MUST NOT be increased. -- The balance of the *token holder* MUST be decreased by amount of tokens burned. + +- The balance of the *holder* MUST be decreased by amount of tokens burned. + - The token contract MUST emit a `Burned` event with the correct values as defined in the [`Burned` Event][burned]. -- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC820]. -- The `operatorData` MUST be immutable during the entire burn process—hence the same `operatorData` MUST be used to call the `tokensToSend` hook and emit the `Burned` event. -- The `data` field of the `tokensToSend` hook MUST be empty. + +- The token contract MUST call the `tokensToSend` hook of the *holder* + if the *holder* registers an `ERC777TokensSender` implementation via [ERC1820]. + +- The `operatorData` MUST be immutable during the entire burn process—hence + the same `operatorData` MUST be used to call the `tokensToSend` hook and emit the `Burned` event. The token contract MUST `revert` when burning in any of the following cases: -- The *operator* address is not an authorized operator for the *token holder*. -- The resulting *token holder* balance after the burn is not a multiple of the *granularity* defined by the token contract. -- The balance of *token holder* is inferior to the amount of tokens to burn (i.e., resulting in a negative balance for the *token holder*). -- The address of the *token holder* is `0x0`. +- The *operator* address is not an authorized operator for the *holder*. + +- The resulting *holder* balance after the burn is not a multiple of the *granularity* + defined by the token contract. + +- The balance of *holder* is inferior to the amount of tokens to burn + (i.e., resulting in a negative balance for the *holder*). + +- The address of the *holder* is `0x0`. *[ERC20] compatibility requirement*: -While a `Sent` event MUST NOT be emitted when burning; if the token contract is [ERC20] enabled, a `Transfer` event with the `to` parameter set to `0x0` SHOULD be emitted. The [ERC20] standard does not define the concept of burning tokens, but this is a commonly accepted practice. +While a `Sent` event MUST NOT be emitted when burning; +if the token contract is [ERC20] enabled, a `Transfer` event with the `to` parameter set to `0x0` SHOULD be emitted. +The [ERC20] standard does not define the concept of burning tokens, but this is a commonly accepted practice. -The token contract MAY burn tokens for multiple *token holders* at once. In this case: +The token contract MAY burn tokens for multiple *holders* at once. In this case: -- The previous burn rules MUST apply to each *token holders*. +- The previous burn rules MUST apply to each *holders*. - The sum of all the balances decremented MUST be equal to the total burned amount. -- A `Burned` event MUST be emitted for every *token holder* with the corresponding amount for each *token holder*. +- A `Burned` event MUST be emitted for every *holder* with the corresponding amount for each *holder*. - The sum of all the amounts from the `Burned` event MUST be equal to the total burned `amount`. *NOTE*: Burning an amount of zero (`0`) tokens is valid and MUST be treated as a regular burn. +*NOTE*: The `data` field contains information provided by the holder—similar +to the data field in a regular ether send transaction. +The `tokensToSend()` hook, the `tokensReceived()`, or both +MAY use the information to decide if they wish to reject the transaction. + +*NOTE*: The `operatorData` field is analogous to the `data` field except it SHALL be provided by the *operator*. + **`Burned` event** ``` solidity -event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData) +event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); ``` Indicate the burning of `amount` of tokens from the `from` address by the `operator` address. @@ -483,9 +670,10 @@ Indicate the burning of `amount` of tokens from the `from` address by the `opera > **parameters** > `operator`: Address which triggered the burn. -> `from`: Token holder whose tokens are burned. -> `amount`: Number of tokens burned. -> `operatorData`: Information attached to the burn by the `operator`. +> `from`: *Holder* whose tokens were burned. +> `amount`: Number of tokens burned. +> `data`: Information provided by the *holder*. +> `operatorData`: Information provided by the *operator*. The `burn` and `operatorBurn` functions described below MUST be implemented to burn tokens. Token contracts MAY implement other functions to burn tokens. @@ -493,40 +681,50 @@ Token contracts MAY implement other functions to burn tokens. **`burn` function** ``` solidity -function burn(uint256 amount) public; +function burn(uint256 amount, bytes calldata data) external ``` Burn the `amount` of tokens from the address `msg.sender`. -The *operator* and the *token holder* MUST both be the `msg.sender`. +The *operator* and the *holder* MUST both be the `msg.sender`. +> **identifier:** `fe9d9303` > **parameters** > `amount`: Number of tokens to burn. +> `data`: Information provided by the *holder*. **`operatorBurn` function** ``` solidity -function operatorBurn(address from, uint256 amount, bytes operatorData) public; +function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external ``` Burn the `amount` of tokens on behalf of the address `from`. -The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the `from` (*token holder*) used for the burn MUST be `msg.sender` (the `operator`). - -*Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the burn process MUST `revert`. +*Reminder*: If the *operator* address is not an authorized operator of the `from` address, +then the burn process MUST `revert`. +> **identifier:** `fc673c4f` > **parameters** -> `from`: Token holder whose tokens will be burned (or `0x0` to set `from` to `msg.sender`). +> `from`: *Holder* whose tokens will be burned. > `amount`: Number of tokens to burn. -> `operatorData`: Information attached to the burn by the *operator*. +> `data`: Information provided by the *holder*. +> `operatorData`: Information provided by the *operator*. -*NOTE*: The *operator* MAY pass any information via `operatorData`. The `operatorData` MUST only be provided by the *operator*. +*NOTE*: The *operator* MAY pass any information via `operatorData`. +The `operatorData` MUST only be provided by the *operator*. -*NOTE*: `from` and `msg.sender` MAY be the same address. I.e., an address MAY call `operatorBurn` for itself. This call MUST be equivalent to `burn` with the addition that the *operator* MAY specify an explicit value for `operatorData` (which cannot be done with the `burn` function). +*NOTE*: `from` and `msg.sender` MAY be the same address. +I.e., an address MAY call `operatorBurn` for itself. +This call MUST be equivalent to `burn` +with the addition that the *operator* MAY specify an explicit value for `operatorData` +(which cannot be done with the `burn` function). #### **`ERC777TokensSender` And The `tokensToSend` Hook** -The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *token holder*. Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC820]. +The `tokensToSend` hook notifies of any request to decrement the balance (send and burn) for a given *holder*. +Any address (regular or contract) wishing to be notified of token debits from their address +MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. ``` solidity interface ERC777TokensSender { @@ -535,56 +733,78 @@ interface ERC777TokensSender { address from, address to, uint256 amount, - bytes data, - bytes operatorData - ) public; + bytes calldata userData, + bytes calldata operatorData + ) external; } ``` -*NOTE*: A regular address MAY register a different address—the address of a contract—implementing the interface on its behalf. A contract MAY register either its address or the address of another contract but said address MUST implement the interface on its behalf. +*NOTE*: A regular address MAY register a different address—the address of a contract—implementing +the interface on its behalf. +A contract MAY register either its address or the address of another contract +but said address MUST implement the interface on its behalf. **`tokensToSend`** ``` solidity -function tokensToSend(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) public +function tokensToSend(address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData) external ``` -Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address. +Notify a request to send or burn (if `to` is `0x0`) an `amount` tokens from the `from` address to the `to` address +by the `operator` address. *NOTE*: This function MUST NOT be called outside of a burn, send or [ERC20] transfer process. +> **identifier:** `75ab9782` > **parameters** > `operator`: Address which triggered the balance decrease (through sending or burning). -> `from`: *token holder*. -> `to`: *token recipient* for a send and `0x` for a burn. -> `amount`: Number of tokens the *token holder* balance is decreased by. -> `data`: Extra information provided by the *token holder*. -> `operatorData`: Extra information provided by the address which triggered the balance decrease. +> `from`: *Holder* whose tokens were sent. +> `to`: Recipient of the tokens for a send (or `0x0` for a burn). +> `amount`: Number of tokens the *holder* balance is decreased by. +> `data`: Information provided by the *holder*. +> `operatorData`: Information provided by the *operator*. The following rules apply when calling the `tokensToSend` hook: - The `tokensToSend` hook MUST be called every time the balance is decremented. + - The `tokensToSend` hook MUST be called *before* the state is updated—i.e. *before* the balance is decremented. + - `operator` MUST be the address which triggered the decrease of the balance. -- `from` MUST be the address of the *token holder* whose balance is decreased. + +- `from` MUST be the address of the *holder* whose balance is decreased. + - `to` MUST be the address of the *recipient* whose balance is increased for a send. + - `to` MUST be `0x0` for a burn. -- `amount` MUST be the number of tokens the *token holder* balance is decreased by. -- `data` MUST contain the extra information provided by the *token holder* (if any) for a send. -- `data` MUST be empty for a burn. -- `operatorData` MUST contain the extra information provided by the address which triggered the decrease of the balance (if any). -- The *token holder* MAY block a decrease of its balance by `revert`ing. (I.e., reject the withdrawal of tokens from its account.) -*NOTE*: Multiple *token holders* MAY use the same implementation of `ERC777TokensSender`. +- `amount` MUST be the number of tokens the *holder* balance is decreased by. -*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. Hence the `ERC777TokensSender` MUST expect to be called by different token contracts. The `msg.sender` of the `tokensToSend` call is expected to be the address of the token contract. +- `data` MUST contain the extra information provided by the *holder* (if any) for a send. + +- `operatorData` MUST contain the extra information provided by the address + which triggered the decrease of the balance (if any). + +- The *holder* MAY block a decrease of its balance by `revert`ing. + (I.e., reject the withdrawal of tokens from its account.) + +*NOTE*: Multiple *holders* MAY use the same implementation of `ERC777TokensSender`. + +*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. +Hence the `ERC777TokensSender` MUST expect to be called by different token contracts. +The `msg.sender` of the `tokensToSend` call is expected to be the address of the token contract. *[ERC20] compatibility requirement*: -This hook takes precedence over [ERC20] and MUST be called (if registered) when calling [ERC20]'s `transfer` and `transferFrom` event. When called from a `transfer`, `operator` MUST be the same value as the `from`. When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. +This hook takes precedence over [ERC20] and MUST be called (if registered) +when calling [ERC20]'s `transfer` and `transferFrom` event. +When called from a `transfer`, `operator` MUST be the same value as the `from`. +When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. #### **`ERC777TokensRecipient` And The `tokensReceived` Hook** -The `tokensReceived` hook notifies of any increment of the balance (send and mint) for a given *recipient*. Any address (regular or contract) wishing to be notified of token credits to their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC820]. +The `tokensReceived` hook notifies of any increment of the balance (send and mint) for a given *recipient*. +Any address (regular or contract) wishing to be notified of token credits to their address +MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. ``` solidity interface ERC777TokensRecipient { @@ -593,105 +813,159 @@ interface ERC777TokensRecipient { address from, address to, uint256 amount, - bytes data, - bytes operatorData - ) public; + bytes calldata data, + bytes calldata operatorData + ) external; } ``` -If the *recipient* is a contract, which has not registered an `ERC777TokensRecipient` implementation; the token contract: +If the *recipient* is a contract, which has not registered an `ERC777TokensRecipient` implementation; +then the token contract: - MUST `revert` if the `tokensReceived` hook is called from a mint or send call. - SHOULD accept if the `tokensReceived` hook is called from an ERC20 `transfer` or `transferFrom` call. -*NOTE*: A regular address MAY register a different address—the address of a contract—implementing the interface on its behalf. A contract MUST register either its address or the address of another contract but said address MUST implement the interface on its behalf. +*NOTE*: A regular address MAY register a different address—the address of a contract—implementing +the interface on its behalf. +A contract MUST register either its address or the address of another contract +but said address MUST implement the interface on its behalf. **`tokensReceived`** ``` solidity -function tokensReceived(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) public +function tokensReceived(address operator, address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external ``` -Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address. +Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address +by the `operator` address. *NOTE*: This function MUST NOT be called outside of a mint, send or [ERC20] transfer process. +> **identifier:** `0023de29` > **parameters** > `operator`: Address which triggered the balance increase (through sending or minting). -> `from`: *token holder* for a send and `0x` for a mint. -> `to`: *token recipient*. +> `from`: *Holder* whose tokens were sent (or `0x0` for a mint). +> `to`: Recipient of the tokens. > `amount`: Number of tokens the *recipient* balance is increased by. -> `data`: Extra information provided by the *token holder* for a send and nothing (empty bytes) for a mint. -> `operatorData`: Extra information provided by the address which triggered the balance increase. +> `data`: Information provided by the *holder*. +> `operatorData`: Information provided by the *operator*. -The following rules apply when calling the `tokensToSend` hook: +The following rules apply when calling the `tokensReceived` hook: - The `tokensReceived` hook MUST be called every time the balance is incremented. + - The `tokensReceived` hook MUST be called *after* the state is updated—i.e. *after* the balance is incremented. + - `operator` MUST be the address which triggered the increase of the balance. -- `from` MUST be the address of the *token holder* whose balance is decreased for a send. + +- `from` MUST be the address of the *holder* whose balance is decreased for a send. + - `from` MUST be `0x0` for a mint. + - `to` MUST be the address of the *recipient* whose balance is increased. + - `amount` MUST be the number of tokens the *recipient* balance is increased by. -- `operatorData` MUST contain the extra information provided by the address which triggered the increase of the balance (if any). -- The *token holder* MAY block an increase of its balance by `revert`ing. (I.e., reject the reception of tokens.) +- `operatorData` MUST contain the extra information provided by the address + which triggered the increase of the balance (if any). +- The *holder* MAY block an increase of its balance by `revert`ing. (I.e., reject the reception of tokens.) -*NOTE*: Multiple *token holders* MAY use the same implementation of `ERC777TokensRecipient`. +*NOTE*: Multiple *holders* MAY use the same implementation of `ERC777TokensRecipient`. -*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. Hence the `ERC777TokensRecipient` MUST expect to be called by different token contracts. The `msg.sender` of the `tokensReceived` call is expected to be the address of the token contract. +*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. +Hence the `ERC777TokensRecipient` MUST expect to be called by different token contracts. +The `msg.sender` of the `tokensReceived` call is expected to be the address of the token contract. *[ERC20] compatibility requirement*: -This hook takes precedence over [ERC20] and MUST be called (if registered) when calling [ERC20]'s `transfer` and `transferFrom` event. When called from a `transfer`, `operator` MUST be the same value as the `from`. When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. +This hook takes precedence over [ERC20] and MUST be called (if registered) +when calling [ERC20]'s `transfer` and `transferFrom` event. +When called from a `transfer`, `operator` MUST be the same value as the `from`. +When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. #### **Note On Gas Consumption** -Dapps and wallets SHOULD first estimate the gas required when sending, minting, or burning tokens—using [`eth_estimateGas`][eth_estimateGas]—to avoid running out of gas during the transaction. + +Dapps and wallets SHOULD first estimate the gas required when sending, minting, or burning tokens—using +[`eth_estimateGas`][eth_estimateGas]—to avoid running out of gas during the transaction. ### Logo -| **Image** |  ![beige logo] |  ![white logo] |  ![light grey logo] |  ![dark grey logo] |  ![black logo][black logo] | -|----------:|:---------:|:---------:|:------------:|:-----------:|:---------:| -| **Color** | beige | white | light grey | dark grey | black | -| **Hex** | `#C99D66` | `#FFFFFF` | `#EBEFF0` | `#3C3C3D` | `#000000` | +| **Image** | ![beige logo] | ![white logo] | ![light grey logo] | ![dark grey logo] | ![black logo] | +|----------:|:-------------:|:-------------:|:------------------:|:-----------------:|:-------------:| +| **Color** | beige | white | light grey | dark grey | black | +| **Hex** | `#C99D66` | `#FFFFFF` | `#EBEFF0` | `#3C3C3D` | `#000000` | -The logo MAY be used, modified and adapted to promote valid [ERC777] token implementations and [ERC777] compliant technologies such as wallets and dapps. +The logo MAY be used, modified and adapted to promote valid [ERC777] token implementations +and [ERC777] compliant technologies such as wallets and dapps. [ERC777] token contract authors MAY create a specific logo for their token based on this logo. -The logo MUST NOT be used to advertise, promote or associate in any way technology—such as tokens—which is not [ERC777] compliant. +The logo MUST NOT be used to advertise, promote or associate in any way technology—such +as tokens—which is not [ERC777] compliant. -The logo for the standard can be found in the [`/assets/eip-777/logo`][logos] folder in `SVG` and `PNG` formats. The `PNG` version of the logo offers a few sizes in pixels. If needed, other sizes MAY be created by converting from `SVG` into `PNG`. +The logo for the standard can be found in the [`/assets/eip-777/logo`][logos] folder in `SVG` and `PNG` formats. +The `PNG` version of the logo offers a few sizes in pixels. +If needed, other sizes MAY be created by converting from `SVG` into `PNG`. ## Rationale -This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20]. It avoids the problems and vulnerabilities of [EIP223]. +This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20]. +It avoids the problems and vulnerabilities of [EIP223]. -It goes a step further by allowing *operators* (generally contracts) which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed. Finally, it adds hooks to provide further control to *token holders* over their tokens. Note that, the usage of [ERC820] provides backward compatibility with wallets and existing contracts without having to be redeployed thanks proxy contracts implementing the hooks. +It goes a step further by allowing *operators* (generally contracts) +which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed. +Finally, it adds hooks to provide further control to *holders* over their tokens. +Note that, the usage of [ERC1820] provides backward compatibility with wallets and existing contracts +without having to be redeployed thanks proxy contracts implementing the hooks. ## Backward Compatibility This EIP does not introduce backward incompatibilities and is backward compatible with the older [ERC20] token standard. -This EIP does not use `transfer` and `transferFrom` and uses `send` and `operatorSend` to avoid confusion and mistakes when deciphering which token standard is being used. +This EIP does not use `transfer` and `transferFrom` and uses `send` and `operatorSend` +to avoid confusion and mistakes when deciphering which token standard is being used. -This standard allows the implementation of [ERC20] functions `transfer`, `transferFrom`, `approve` and `allowance` alongside to make a token fully compatible with [ERC20]. +This standard allows the implementation of [ERC20] functions `transfer`, `transferFrom`, `approve` and `allowance` +alongside to make a token fully compatible with [ERC20]. -The token MAY implement `decimals()` for backward compatibility with [ERC20]. If implemented, it MUST always return `18`. +The token MAY implement `decimals()` for backward compatibility with [ERC20]. +If implemented, it MUST always return `18`. -Therefore a token contract MAY implement both [ERC20] and [ERC777] in parallel. The specification of the `view` functions (such as `name`, `symbol`, `balanceOf`, `totalSupply`) and internal data (such as the mapping of balances) overlap without problems. Note however that the following functions are mandatory in [ERC777] and MUST be implemented: `name`, `symbol` `balanceOf` and `totalSupply` (`decimal` is not part of the [ERC777] standard). +Therefore a token contract MAY implement both [ERC20] and [ERC777] in parallel. +The specification of the `view` functions (such as `name`, `symbol`, `balanceOf`, `totalSupply`) and internal data +(such as the mapping of balances) overlap without problems. +Note however that the following functions are mandatory in [ERC777] and MUST be implemented: +`name`, `symbol` `balanceOf` and `totalSupply` +(`decimals` is not part of the [ERC777] standard). -The state-modifying functions from both standards are decoupled and can operate independently from each other. Note that [ERC20] functions SHOULD be limited to only being called from old contracts. +The state-modifying functions from both standards are decoupled and can operate independently from each other. +Note that [ERC20] functions SHOULD be limited to only being called from old contracts. -If the token implements [ERC20], it MUST register the `ERC20Token` interface with its own address via [ERC820]. If the contract has a switch to enable or disable [ERC20] functions, every time the switch is triggered, the token MUST register or unregister its own address accordingly the `ERC20Token` interface via [ERC820]. (Unregistering implies setting the address to `0x0`.) +If the token implements [ERC20], +it MUST register the `ERC20Token` interface with its own address via [ERC1820]. +This is done by calling the `setInterfaceImplementer` function on the ERC1820 registry +with the token contract address as both the address and the implementer +and the `keccak256` hash of `ERC20Token` as the interface hash. -The difference for new contracts implementing [ERC20] is that `tokensToSend` and `tokensReceived` hooks take precedence over [ERC20]. Even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC820] if the `from` and the `to` address implement `tokensToSend` and `tokensReceived` hook respectively. If any hook is implemented, it MUST be called. Note that when calling [ERC20] `transfer` on a contract, if the contract does not implement `tokensReceived`, the `transfer` call SHOULD still be accepted even if this means the tokens will probably be locked. +If the contract has a switch to enable or disable ERC20 functions, every time the switch is triggered, +the token MUST register or unregister the `ERC20Token` interface for its own address accordingly via ERC1820. +Unregistering implies calling the `setInterfaceImplementer` with the token contract address as the address, +the `keccak256` hash of `ERC20Token` as the interface hash and `0x0` as the implementer. +(See [Set An Interface For An Address][erc1820-set] in [ERC1820] for more details.) -The table below summarizes the different actions the token contract MUST take when sending, minting and transferring token via [ERC777] and [ERC20]: +The difference for new contracts implementing [ERC20] is that +`tokensToSend` and `tokensReceived` hooks take precedence over [ERC20]. +Even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC1820] +if the `from` and the `to` address implement `tokensToSend` and `tokensReceived` hook respectively. +If any hook is implemented, it MUST be called. +Note that when calling [ERC20] `transfer` on a contract, if the contract does not implement `tokensReceived`, +the `transfer` call SHOULD still be accepted even if this means the tokens will probably be locked. +The table below summarizes the different actions the token contract MUST take +when sending, minting and transferring token via [ERC777] and [ERC20]:
- + @@ -722,20 +996,32 @@ The table below summarizes the different actions the token contract MUST take wh
ERC820ERC1820 to address ERC777 Sending And Minting ERC20 transfer/transferFrom
-There is no particular action to take if `tokensToSend` is not implemented. The transfer MUST proceed and only be canceled if another condition is not respected such as lack of funds or a `revert` in `tokensReceived` (if present). +There is no particular action to take if `tokensToSend` is not implemented. +The transfer MUST proceed and only be canceled if another condition is not respected +such as lack of funds or a `revert` in `tokensReceived` (if present). -During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be emitted. Furthermore, if the token contract declares that it implements `ERC20Token` via [ERC820], the token contract SHOULD emit a `Transfer` event for minting and burning and MUST emit a `Transfer` event for sending (as specified in the [ERC20] standard). During an [ERC20]'s `transfer` or `transferFrom` functions, a valid `Sent` event MUST be emitted. +During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be emitted. +Furthermore, if the token contract declares that it implements `ERC20Token` via [ERC1820], +the token contract SHOULD emit a `Transfer` event for minting and burning +and MUST emit a `Transfer` event for sending (as specified in the [ERC20] standard). +During an [ERC20]'s `transfer` or `transferFrom` functions, a valid `Sent` event MUST be emitted. -Hence for any movement of tokens, two events MAY be emitted: an [ERC20] `Transfer` and an [ERC777] `Sent`, `Minted` or `Burned` (depending on the type of movement). Third-party developers MUST be careful not to consider both events as separate movements. As a general rule, if an application considers the token as an ERC20 token, then only the `Transfer` event MUST be taken into account. If the application considers the token as an ERC777 token, then only the `Sent`, `Minted` and `Burned` events MUST be considered. +Hence for any movement of tokens, two events MAY be emitted: +an [ERC20] `Transfer` and an [ERC777] `Sent`, `Minted` or `Burned` (depending on the type of movement). +Third-party developers MUST be careful not to consider both events as separate movements. +As a general rule, if an application considers the token as an ERC20 token, +then only the `Transfer` event MUST be taken into account. +If the application considers the token as an ERC777 token, +then only the `Sent`, `Minted` and `Burned` events MUST be considered. ## Test Cases -The [repository with the reference implementation][jacquesd/ERC777] contains all the [tests][ref tests]. +The [repository with the reference implementation][0xjac/ERC777] contains all the [tests][ref tests]. ## Implementation -The GitHub repository [jacquesd/ERC777] contains the [reference implementation]. The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`. - +The GitHub repository [0xjac/ERC777] contains the [reference implementation]. +The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`. ## Copyright @@ -743,14 +1029,14 @@ Copyright and related rights waived via [CC0]. [operators]: #operators - [ERC20]: https://eips.ethereum.org/EIPS/eip-20 [ERC777]: https://eips.ethereum.org/EIPS/eip-777 -[ERC820]: https://eips.ethereum.org/EIPS/eip-820 -[jacquesd/ERC777]: https://github.com/jacquesd/ERC777 +[ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 +[erc1820-set]: https://eips.ethereum.org/EIPS/eip-1820#set-an-interface-for-an-address +[0xjac/ERC777]: https://github.com/0xjac/ERC777 [npm/erc777]: https://www.npmjs.com/package/erc777 -[ref tests]: https://github.com/jacquesd/ERC777/blob/master/test/ReferenceToken.test.js -[reference implementation]: https://github.com/jacquesd/ERC777/blob/master/contracts/examples/ReferenceToken.sol +[ref tests]: https://github.com/0xjac/ERC777/blob/master/test/ReferenceToken.test.js +[reference implementation]: https://github.com/0xjac/ERC777/blob/master/contracts/examples/ReferenceToken.sol [EIP223]: https://github.com/ethereum/EIPs/issues/223 [eth_estimateGas]: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas @@ -761,7 +1047,6 @@ Copyright and related rights waived via [CC0]. [sent]: #sent [minted]: #minted [burned]: #burned -[initial supply]: #initialSupply [logos]: https://github.com/ethereum/EIPs/tree/master/assets/eip-777/logo [beige logo]: ../assets/eip-777/logo/png/ERC-777-logo-beige-48px.png diff --git a/EIPS/eip-778.md b/EIPS/eip-778.md index 7d0135d0f5a3ba..72d33157f4802f 100644 --- a/EIPS/eip-778.md +++ b/EIPS/eip-778.md @@ -37,10 +37,10 @@ be able to determine which record is newer. The components of a node record are: - `signature`: cryptographic signature of record contents -- `seq`: The sequence number, a 64 bit integer. Nodes should increase the number whenever - the record changes and republish the record. +- `seq`: The sequence number, a 64-bit unsigned integer. Nodes should increase the number + whenever the record changes and republish the record. - The remainder of the record consists of arbitrary key/value pairs, which must be sorted - by key. + by key. Keys must be unique. A record's signature is made and validated according to an *identity scheme*. The identity scheme is also responsible for deriving a node's address in the DHT. @@ -53,9 +53,9 @@ records larger than this size. Records are signed and encoded as follows: - content = rlp(seq) || rlp(k) || rlp(v) || ... - signature = rlp(sign(rlp_list(content))) - record = rlp_list(signature || content) + content = [seq, k, v, ...] + signature = sign(content) + record = [signature, seq, k, v, ...] ### Key/Value Pairs @@ -67,19 +67,20 @@ preferred. The following keys are pre-defined: | `id` | name of identity scheme, e.g. "v4" | | `secp256k1` | compressed secp256k1 public key, 33 bytes | | `ip` | IP address, 4 or 16 bytes | -| `tcp` | TCP port | -| `udp` | UDP port | +| `tcp` | TCP port, big endian integer | +| `udp` | UDP port, big endian integer | ### "v4" Identity Scheme This specification defines a single scheme to be used as the default. The "v4" scheme is -backwards-compatible with the cryptosystem used by Node Discovery Protocol v4. +backwards-compatible with the cryptosystem used by Node Discovery v4. - To sign record `content` with this scheme, apply the keccak256 hash function (as used by the EVM) to `content`, then create a signature of the hash. The resulting 64-byte - signature is encoded as the concatenation of the `r` and `s` signature values. + signature is encoded as the concatenation of the `r` and `s` signature values (the + recovery ID `v` is omitted). - To verify a record, check that the signature was made by the public key in the - "secp256k1" key/value pair. + "secp256k1" key/value pair of the record. - To derive a node address, take the keccak256 hash of the uncompressed public key. # Rationale @@ -98,6 +99,43 @@ in size-constrained protocols such as DNS. A record containing a IPv4 address, w using the "v4" scheme occupies roughly 120 bytes, leaving plenty of room for additional metadata. +# Test Vectors + +Example (valid) record: + +```text +f884b8407098ad865b00a582051940cb9cf36836572411a4727878307701 +1599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11 +df72ecf1145ccb9c01826964827634826970847f00000189736563703235 +366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1 +400f3258cd31388375647082765f +``` + +The raw RLP structure of this record is: + +```text +[ + 7098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c, + 01, + "id", + "v4", + "ip", + 7f000001, + "secp256k1", + 03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138, + "udp", + 765f, +] +``` + +The record contains sequence number `1`. + +A v4 enode URL containing the same information (but no signature or sequence number): + +```text +enode://ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f@127.0.0.1:0?discport=30303 +``` + # Copyright Copyright and related rights waived via CC0. diff --git a/EIPS/eip-779.md b/EIPS/eip-779.md index a8669b2aec7986..4d185471937916 100644 --- a/EIPS/eip-779.md +++ b/EIPS/eip-779.md @@ -5,6 +5,7 @@ author: Casey Detrio type: Meta status: Final created: 2017-11-26 +requires: 606 --- ## Abstract diff --git a/EIPS/eip-8.md b/EIPS/eip-8.md index 006e85c1f433d0..6a01a1ceb2b080 100644 --- a/EIPS/eip-8.md +++ b/EIPS/eip-8.md @@ -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 diff --git a/EIPS/eip-820.md b/EIPS/eip-820.md index dbfded3b05743c..0e0efd1d1671e1 100644 --- a/EIPS/eip-820.md +++ b/EIPS/eip-820.md @@ -3,13 +3,22 @@ eip: 820 title: Pseudo-introspection Registry Contract author: Jordi Baylina , Jacques Dafflon discussions-to: https://github.com/ethereum/EIPs/issues/820 -status: Final +status: Superseded type: Standards Track category: ERC requires: 165, 214 created: 2018-01-05 +superseded-by: 1820 --- +> :information_source: **[ERC1820] has superseded [ERC820].** :information_source: +> [ERC1820] fixes the incompatibility in the [ERC165] logic which was introduced by the Solidty 0.5 update. +> Have a look at the [official announcement][erc1820-annoucement], and the comments about the [bug][erc820-bug] and the [fix][erc820-fix]. +> Apart from this fix, [ERC1820] is functionally equivalent to [ERC820]. +> +> :warning: [ERC1820] MUST be used in lieu of [ERC820]. :warning: + + ## Simple Summary This standard defines a universal registry smart contract where any address (contract or regular account) can register which interface it supports and which smart contract is responsible for its implementation. @@ -56,7 +65,7 @@ This standard also provides a *unique* address for all chains. Thus solving the * * You should have received a copy of the CC0 Public Domain Dedication along * with this software. If not, see - * . + * . * * ███████╗██████╗ ██████╗ █████╗ ██████╗ ██████╗ * ██╔════╝██╔══██╗██╔════╝██╔══██╗╚════██╗██╔═████╗ @@ -636,7 +645,7 @@ The contract has the address above for every chain on which it is deployed. }, "sources": { "./contracts/ERC820Registry.sol": { - "content": "/* ERC820 Pseudo-introspection Registry Contract\n * This standard defines a universal registry smart contract where any address\n * (contract or regular account) can register which interface it supports and\n * which smart contract is responsible for its implementation.\n *\n * Written in 2018 by Jordi Baylina and Jacques Dafflon\n *\n * To the extent possible under law, the author(s) have dedicated all copyright\n * and related and neighboring rights to this software to the public domain\n * worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along\n * with this software. If not, see\n * .\n *\n * ███████╗██████╗ ██████╗ █████╗ ██████╗ ██████╗\n * ██╔════╝██╔══██╗██╔════╝██╔══██╗╚════██╗██╔═████╗\n * █████╗ ██████╔╝██║ ╚█████╔╝ █████╔╝██║██╔██║\n * ██╔══╝ ██╔══██╗██║ ██╔══██╗██╔═══╝ ████╔╝██║\n * ███████╗██║ ██║╚██████╗╚█████╔╝███████╗╚██████╔╝\n * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚════╝ ╚══════╝ ╚═════╝\n *\n * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗\n * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝\n * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝\n * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝\n * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║\n * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝\n *\n */\npragma solidity 0.4.24;\n// IV is value needed to have a vanity address starting with `0x820`.\n// IV: 9513\n\n/// @dev The interface a contract MUST implement if it is the implementer of\n/// some (other) interface for any address other than itself.\ninterface ERC820ImplementerInterface {\n /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not.\n /// @param interfaceHash keccak256 hash of the name of the interface\n /// @param addr Address for which the contract will implement the interface\n /// @return ERC820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`.\n function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32);\n}\n\n\n/// @title ERC820 Pseudo-introspection Registry Contract\n/// @author Jordi Baylina and Jacques Dafflon\n/// @notice This contract is the official implementation of the ERC820 Registry.\n/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-820\ncontract ERC820Registry {\n /// @notice ERC165 Invalid ID.\n bytes4 constant INVALID_ID = 0xffffffff;\n /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`).\n bytes4 constant ERC165ID = 0x01ffc9a7;\n /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address.\n bytes32 constant ERC820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC820_ACCEPT_MAGIC\"));\n\n mapping (address => mapping(bytes32 => address)) interfaces;\n mapping (address => address) managers;\n mapping (address => mapping(bytes4 => bool)) erc165Cached;\n\n /// @notice Indicates a contract is the `implementer` of `interfaceHash` for `addr`.\n event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);\n /// @notice Indicates `newManager` is the address of the new manager for `addr`.\n event ManagerChanged(address indexed addr, address indexed newManager);\n\n /// @notice Query if an address implements an interface and through which contract.\n /// @param _addr Address being queried for the implementer of an interface.\n /// (If `_addr == 0` then `msg.sender` is assumed.)\n /// @param _interfaceHash keccak256 hash of the name of the interface as a string.\n /// E.g., `web3.utils.keccak256('ERC777Token')`.\n /// @return The address of the contract which implements the interface `_interfaceHash` for `_addr`\n /// or `0x0` if `_addr` did not register an implementer for this interface.\n function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) {\n address addr = _addr == 0 ? msg.sender : _addr;\n if (isERC165Interface(_interfaceHash)) {\n bytes4 erc165InterfaceHash = bytes4(_interfaceHash);\n return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : 0;\n }\n return interfaces[addr][_interfaceHash];\n }\n\n /// @notice Sets the contract which implements a specific interface for an address.\n /// Only the manager defined for that address can set it.\n /// (Each address is the manager for itself until it sets a new manager.)\n /// @param _addr Address to define the interface for. (If `_addr == 0` then `msg.sender` is assumed.)\n /// @param _interfaceHash keccak256 hash of the name of the interface as a string.\n /// For example, `web3.utils.keccak256('ERC777TokensRecipient')` for the `ERC777TokensRecipient` interface.\n /// @param _implementer Contract address implementing _interfaceHash for _addr.\n function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external {\n address addr = _addr == 0 ? msg.sender : _addr;\n require(getManager(addr) == msg.sender, \"Not the manager\");\n\n require(!isERC165Interface(_interfaceHash), \"Must not be a ERC165 hash\");\n if (_implementer != 0 && _implementer != msg.sender) {\n require(\n ERC820ImplementerInterface(_implementer)\n .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC820_ACCEPT_MAGIC,\n \"Does not implement the interface\"\n );\n }\n interfaces[addr][_interfaceHash] = _implementer;\n emit InterfaceImplementerSet(addr, _interfaceHash, _implementer);\n }\n\n /// @notice Sets the `_newManager` as manager for the `_addr` address.\n /// The new manager will be able to call `setInterfaceImplementer` for `_addr`.\n /// @param _addr Address for which to set the new manager.\n /// @param _newManager Address of the new manager for `addr`.\n function setManager(address _addr, address _newManager) external {\n require(getManager(_addr) == msg.sender, \"Not the manager\");\n managers[_addr] = _newManager == _addr ? 0 : _newManager;\n emit ManagerChanged(_addr, _newManager);\n }\n\n /// @notice Get the manager of an address.\n /// @param _addr Address for which to return the manager.\n /// @return Address of the manager for a given address.\n function getManager(address _addr) public view returns(address) {\n // By default the manager of an address is the same address\n if (managers[_addr] == 0) {\n return _addr;\n } else {\n return managers[_addr];\n }\n }\n\n /// @notice Compute the keccak256 hash of an interface given its name.\n /// @param _interfaceName Name of the interface.\n /// @return The keccak256 hash of an interface name.\n function interfaceHash(string _interfaceName) external pure returns(bytes32) {\n return keccak256(abi.encodePacked(_interfaceName));\n }\n\n /* --- ERC165 Related Functions --- */\n /* --- Developed in collaboration with William Entriken. --- */\n\n /// @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n /// @param _contract Address of the contract for which to update the cache.\n /// @param _interfaceId ERC165 interface for which to update the cache.\n function updateERC165Cache(address _contract, bytes4 _interfaceId) external {\n interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache(_contract, _interfaceId) ? _contract : 0;\n erc165Cached[_contract][_interfaceId] = true;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not.\n /// The result may be cached, if not a direct lookup is performed.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return `true` if `_contract` implements `_interfaceId`, false otherwise.\n function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) {\n if (!erc165Cached[_contract][_interfaceId]) {\n return implementsERC165InterfaceNoCache(_contract, _interfaceId);\n }\n return interfaces[_contract][_interfaceId] == _contract;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return `true` if `_contract` implements `_interfaceId`, false otherwise.\n function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) {\n uint256 success;\n uint256 result;\n\n (success, result) = noThrowCall(_contract, ERC165ID);\n if (success == 0 || result == 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, INVALID_ID);\n if (success == 0 || result != 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, _interfaceId);\n if (success == 1 && result == 1) {\n return true;\n }\n return false;\n }\n\n /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not.\n /// @param _interfaceHash The hash to check.\n /// @return `true` if the hash is a ERC165 interface (ending with 28 zeroes), `false` otherwise.\n function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) {\n return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;\n }\n\n /// @dev Make a call on a contract without throwing if the function does not exist.\n function noThrowCall(address _contract, bytes4 _interfaceId)\n internal view returns (uint256 success, uint256 result)\n {\n bytes4 erc165ID = ERC165ID;\n\n assembly {\n let x := mload(0x40) // Find empty storage location using \"free memory pointer\"\n mstore(x, erc165ID) // Place signature at beginning of empty storage\n mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature\n\n success := staticcall(\n 30000, // 30k gas\n _contract, // To addr\n x, // Inputs are stored at location x\n 0x08, // Inputs are 8 bytes long\n x, // Store output over input (saves space)\n 0x20 // Outputs are 32 bytes long\n )\n\n result := mload(x) // Load the result\n }\n }\n}\n", + "content": "/* ERC820 Pseudo-introspection Registry Contract\n * This standard defines a universal registry smart contract where any address\n * (contract or regular account) can register which interface it supports and\n * which smart contract is responsible for its implementation.\n *\n * Written in 2018 by Jordi Baylina and Jacques Dafflon\n *\n * To the extent possible under law, the author(s) have dedicated all copyright\n * and related and neighboring rights to this software to the public domain\n * worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along\n * with this software. If not, see\n * .\n *\n * ███████╗██████╗ ██████╗ █████╗ ██████╗ ██████╗\n * ██╔════╝██╔══██╗██╔════╝██╔══██╗╚════██╗██╔═████╗\n * █████╗ ██████╔╝██║ ╚█████╔╝ █████╔╝██║██╔██║\n * ██╔══╝ ██╔══██╗██║ ██╔══██╗██╔═══╝ ████╔╝██║\n * ███████╗██║ ██║╚██████╗╚█████╔╝███████╗╚██████╔╝\n * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚════╝ ╚══════╝ ╚═════╝\n *\n * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗\n * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝\n * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝\n * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝\n * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║\n * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝\n *\n */\npragma solidity 0.4.24;\n// IV is value needed to have a vanity address starting with `0x820`.\n// IV: 9513\n\n/// @dev The interface a contract MUST implement if it is the implementer of\n/// some (other) interface for any address other than itself.\ninterface ERC820ImplementerInterface {\n /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not.\n /// @param interfaceHash keccak256 hash of the name of the interface\n /// @param addr Address for which the contract will implement the interface\n /// @return ERC820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`.\n function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32);\n}\n\n\n/// @title ERC820 Pseudo-introspection Registry Contract\n/// @author Jordi Baylina and Jacques Dafflon\n/// @notice This contract is the official implementation of the ERC820 Registry.\n/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-820\ncontract ERC820Registry {\n /// @notice ERC165 Invalid ID.\n bytes4 constant INVALID_ID = 0xffffffff;\n /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`).\n bytes4 constant ERC165ID = 0x01ffc9a7;\n /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address.\n bytes32 constant ERC820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC820_ACCEPT_MAGIC\"));\n\n mapping (address => mapping(bytes32 => address)) interfaces;\n mapping (address => address) managers;\n mapping (address => mapping(bytes4 => bool)) erc165Cached;\n\n /// @notice Indicates a contract is the `implementer` of `interfaceHash` for `addr`.\n event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);\n /// @notice Indicates `newManager` is the address of the new manager for `addr`.\n event ManagerChanged(address indexed addr, address indexed newManager);\n\n /// @notice Query if an address implements an interface and through which contract.\n /// @param _addr Address being queried for the implementer of an interface.\n /// (If `_addr == 0` then `msg.sender` is assumed.)\n /// @param _interfaceHash keccak256 hash of the name of the interface as a string.\n /// E.g., `web3.utils.keccak256('ERC777Token')`.\n /// @return The address of the contract which implements the interface `_interfaceHash` for `_addr`\n /// or `0x0` if `_addr` did not register an implementer for this interface.\n function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) {\n address addr = _addr == 0 ? msg.sender : _addr;\n if (isERC165Interface(_interfaceHash)) {\n bytes4 erc165InterfaceHash = bytes4(_interfaceHash);\n return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : 0;\n }\n return interfaces[addr][_interfaceHash];\n }\n\n /// @notice Sets the contract which implements a specific interface for an address.\n /// Only the manager defined for that address can set it.\n /// (Each address is the manager for itself until it sets a new manager.)\n /// @param _addr Address to define the interface for. (If `_addr == 0` then `msg.sender` is assumed.)\n /// @param _interfaceHash keccak256 hash of the name of the interface as a string.\n /// For example, `web3.utils.keccak256('ERC777TokensRecipient')` for the `ERC777TokensRecipient` interface.\n /// @param _implementer Contract address implementing _interfaceHash for _addr.\n function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external {\n address addr = _addr == 0 ? msg.sender : _addr;\n require(getManager(addr) == msg.sender, \"Not the manager\");\n\n require(!isERC165Interface(_interfaceHash), \"Must not be a ERC165 hash\");\n if (_implementer != 0 && _implementer != msg.sender) {\n require(\n ERC820ImplementerInterface(_implementer)\n .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC820_ACCEPT_MAGIC,\n \"Does not implement the interface\"\n );\n }\n interfaces[addr][_interfaceHash] = _implementer;\n emit InterfaceImplementerSet(addr, _interfaceHash, _implementer);\n }\n\n /// @notice Sets the `_newManager` as manager for the `_addr` address.\n /// The new manager will be able to call `setInterfaceImplementer` for `_addr`.\n /// @param _addr Address for which to set the new manager.\n /// @param _newManager Address of the new manager for `addr`.\n function setManager(address _addr, address _newManager) external {\n require(getManager(_addr) == msg.sender, \"Not the manager\");\n managers[_addr] = _newManager == _addr ? 0 : _newManager;\n emit ManagerChanged(_addr, _newManager);\n }\n\n /// @notice Get the manager of an address.\n /// @param _addr Address for which to return the manager.\n /// @return Address of the manager for a given address.\n function getManager(address _addr) public view returns(address) {\n // By default the manager of an address is the same address\n if (managers[_addr] == 0) {\n return _addr;\n } else {\n return managers[_addr];\n }\n }\n\n /// @notice Compute the keccak256 hash of an interface given its name.\n /// @param _interfaceName Name of the interface.\n /// @return The keccak256 hash of an interface name.\n function interfaceHash(string _interfaceName) external pure returns(bytes32) {\n return keccak256(abi.encodePacked(_interfaceName));\n }\n\n /* --- ERC165 Related Functions --- */\n /* --- Developed in collaboration with William Entriken. --- */\n\n /// @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n /// @param _contract Address of the contract for which to update the cache.\n /// @param _interfaceId ERC165 interface for which to update the cache.\n function updateERC165Cache(address _contract, bytes4 _interfaceId) external {\n interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache(_contract, _interfaceId) ? _contract : 0;\n erc165Cached[_contract][_interfaceId] = true;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not.\n /// The result may be cached, if not a direct lookup is performed.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return `true` if `_contract` implements `_interfaceId`, false otherwise.\n function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) {\n if (!erc165Cached[_contract][_interfaceId]) {\n return implementsERC165InterfaceNoCache(_contract, _interfaceId);\n }\n return interfaces[_contract][_interfaceId] == _contract;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return `true` if `_contract` implements `_interfaceId`, false otherwise.\n function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) {\n uint256 success;\n uint256 result;\n\n (success, result) = noThrowCall(_contract, ERC165ID);\n if (success == 0 || result == 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, INVALID_ID);\n if (success == 0 || result != 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, _interfaceId);\n if (success == 1 && result == 1) {\n return true;\n }\n return false;\n }\n\n /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not.\n /// @param _interfaceHash The hash to check.\n /// @return `true` if the hash is a ERC165 interface (ending with 28 zeroes), `false` otherwise.\n function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) {\n return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;\n }\n\n /// @dev Make a call on a contract without throwing if the function does not exist.\n function noThrowCall(address _contract, bytes4 _interfaceId)\n internal view returns (uint256 success, uint256 result)\n {\n bytes4 erc165ID = ERC165ID;\n\n assembly {\n let x := mload(0x40) // Find empty storage location using \"free memory pointer\"\n mstore(x, erc165ID) // Place signature at beginning of empty storage\n mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature\n\n success := staticcall(\n 30000, // 30k gas\n _contract, // To addr\n x, // Inputs are stored at location x\n 0x08, // Inputs are 8 bytes long\n x, // Store output over input (saves space)\n 0x20 // Outputs are 32 bytes long\n )\n\n result := mload(x) // Load the result\n }\n }\n}\n", "keccak256": "0x8eecce3912a15087b3f5845d5a74af7712c93d0a8fcd6f2d40f07ed5032022ab" } }, @@ -889,3 +898,7 @@ Copyright and related rights waived via [CC0]. [Nick]: https://github.com/Arachnid/ [William Entriken]: https://github.com/fulldecent [ENS]: https://ens.domains/ +[ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 +[erc1820-annoucement]: https://github.com/ethereum/EIPs/issues/820#issuecomment-464109166 +[erc820-bug]: https://github.com/ethereum/EIPs/issues/820#issuecomment-452465748 +[erc820-fix]: https://github.com/ethereum/EIPs/issues/820#issuecomment-454021564 diff --git a/EIPS/eip-884.md b/EIPS/eip-884.md index e7a58c630b6fb1..87d2d41477a3cb 100644 --- a/EIPS/eip-884.md +++ b/EIPS/eip-884.md @@ -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 diff --git a/EIPS/eip-902.md b/EIPS/eip-902.md index f81a1775e83c7b..648f82981978c9 100644 --- a/EIPS/eip-902.md +++ b/EIPS/eip-902.md @@ -7,7 +7,7 @@ type: Standards Track category: ERC status: Draft created: 2018-02-14 -require: 1066 +requires: 1066 --- # Simple Summary diff --git a/EIPS/eip-908.md b/EIPS/eip-908.md index dace932f623acc..638f0655fa3ba7 100644 --- a/EIPS/eip-908.md +++ b/EIPS/eip-908.md @@ -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). diff --git a/EIPS/eip-926.md b/EIPS/eip-926.md index 5e210373a6d873..b84973769e80fe 100644 --- a/EIPS/eip-926.md +++ b/EIPS/eip-926.md @@ -6,7 +6,7 @@ type: Standards Track category: ERC status: Draft created: 2018-03-12 -dependencies: 165 +requires: 165 --- ## Abstract diff --git a/EIPS/eip-927.md b/EIPS/eip-927.md index 4087813b2c0e5d..b36910099f1c87 100644 --- a/EIPS/eip-927.md +++ b/EIPS/eip-927.md @@ -6,7 +6,7 @@ type: Standards Track category: ERC status: Draft created: 2018-03-12 -dependencies: 926 +requires: 926 --- ## Abstract diff --git a/EIPS/eip-969.md b/EIPS/eip-969.md index 1c41070cce3b2b..8b6301e6219887 100644 --- a/EIPS/eip-969.md +++ b/EIPS/eip-969.md @@ -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 #include diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 965ebcb18f74a8..28fdd5878292be 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -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. \ No newline at end of file +> 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. diff --git a/README.md b/README.md index ad7b357517ebf0..c313bcde2265cd 100644 --- a/README.md +++ b/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 diff --git a/_includes/social.html b/_includes/social.html index 9783b84a2e269b..a4983ccbf14c44 100644 --- a/_includes/social.html +++ b/_includes/social.html @@ -7,7 +7,7 @@ {%- if site.linkedin_username -%}
  • {{ site.linkedin_username| escape }}
  • {%- endif -%} {%- if site.pinterest_username -%}
  • {{ site.pinterest_username| escape }}
  • {%- endif -%} {%- for mst in site.mastodon -%}{%- if mst.username and mst.instance -%}
  • {{ mst.username|escape }}
  • {%- endif -%}{%- endfor -%} - {%- if site.twitter_username -%}
  • {{ site.twitter_username| escape }}
  • {%- endif -%} + {%- if site.twitter_username -%}
  • {{ site.twitter_username| escape }}
  • {%- endif -%} {%- if site.youtube_username -%}
  • {{ site.youtube_username| escape }}
  • {%- endif -%} {%- if site.googleplus_username -%}
  • {{ site.googleplus_username| escape }}
  • {%- endif -%} {%- if site.rss -%}
  • {{ site.rss | escape }}
  • {%- endif -%} diff --git a/_layouts/eip.html b/_layouts/eip.html index 41980eee48a223..7362e1678947dd 100644 --- a/_layouts/eip.html +++ b/_layouts/eip.html @@ -5,14 +5,18 @@

    EIP {{ page.eip | xml_escape }}: {{ page.title | xml_escape }} - Source + Source

    {% if page["discussions-to"] != undefined %} {% endif %} - + {% if page.category != undefined %} diff --git a/assets/eip-1057/test-vectors.md b/assets/eip-1057/test-vectors.md new file mode 100644 index 00000000000000..a47c7e89d2b1ba --- /dev/null +++ b/assets/eip-1057/test-vectors.md @@ -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`,
    `0x33221100`, `0x77665544`, `0xBBAA9988`, `0xFFEEDDCC` | +| seed | `0x123456789ABCDEF0` | +| digest | `0x00000000`, `0x00000000`, `0x00000000`, `0x00000000`,
    `0x00000000`, `0x00000000`, `0x00000000`, `0x00000000` | +| _result_ | `0x464830EE`, `0x7BA4D0DD`, `0x969E1798`, `0xCEC50EB6`,
    `0x7872E2EA`, `0x597E3634`, `0xE380E73D`, `0x2F89D1E6` | + +Test case 2: + +| | | +| -------- | ----------------------------------------------------------------------------------------------------------------- | +| header | `0xCCDDEEFF`, `0x8899AABB`, `0x44556677`, `0x00112233`,
    `0x33221100`, `0x77665544`, `0xBBAA9988`, `0xFFEEDDCC` | +| seed | `0xEE304846DDD0A47B` | +| digest | `0x0598F111`, `0x66B48AC5`, `0x719CFF10`, `0x5F0ACF9D`,
    `0x162FFA18`, `0xEF8E7905`, `0x21470C77`, `0x7D767492` | +| _result_ | `0x47CD7C5B`, `0xD9FDBE2D`, `0xAC5C895B`, `0xFF67CE8E`,
    `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` \ No newline at end of file diff --git a/assets/eip-1822/proxy-diagram.png b/assets/eip-1822/proxy-diagram.png new file mode 100644 index 00000000000000..26747b2b31b3c9 Binary files /dev/null and b/assets/eip-1822/proxy-diagram.png differ diff --git a/assets/eip-1884/BALANCE-run3.png b/assets/eip-1884/BALANCE-run3.png new file mode 100644 index 00000000000000..324647ab75f58b Binary files /dev/null and b/assets/eip-1884/BALANCE-run3.png differ diff --git a/assets/eip-1884/SLOAD-run3.png b/assets/eip-1884/SLOAD-run3.png new file mode 100644 index 00000000000000..674eb2d9cbb7aa Binary files /dev/null and b/assets/eip-1884/SLOAD-run3.png differ diff --git a/assets/eip-1884/geth_processing.png b/assets/eip-1884/geth_processing.png new file mode 100644 index 00000000000000..64bf92e4e591e8 Binary files /dev/null and b/assets/eip-1884/geth_processing.png differ diff --git a/assets/eip-1884/run3.total-bars-5.png b/assets/eip-1884/run3.total-bars-5.png new file mode 100644 index 00000000000000..9eeb4b91e64c3d Binary files /dev/null and b/assets/eip-1884/run3.total-bars-5.png differ diff --git a/assets/eip-1884/run3.total-bars-6.png b/assets/eip-1884/run3.total-bars-6.png new file mode 100644 index 00000000000000..56548b96f4f17a Binary files /dev/null and b/assets/eip-1884/run3.total-bars-6.png differ diff --git a/assets/eip-858/calculations.md b/assets/eip-858/calculations.md index b7b1ba70d47718..e02b94fa982638 100644 --- a/assets/eip-858/calculations.md +++ b/assets/eip-858/calculations.md @@ -1,7 +1,7 @@ | Variable | Symbol | Value | Unit | Source | | -------------------|--------------|---------------|---------------|--------| | Network Hashrate |HN | 296000 | GH/s | https://etherscan.io/chart/hashrate | -| GPU Hashrate |HM | 31.2 | MH/s | http://www.legitreviews.com/geforce-gtx-1070-ethereum-mining-small-tweaks-great-hashrate-low-power_195451 | +| GPU Hashrate |HM | 31.2 | MH/s | https://www.legitreviews.com/geforce-gtx-1070-ethereum-mining-small-tweaks-great-hashrate-low-power_195451 | | GPU Power |PM | 110.6 | W | https://www.reddit.com/r/ethereum/comments/7vewys/10000_tons_co2_per_day_and_climbing_eip_858/dtrswyz/ | diff --git a/index.html b/index.html index 8eb533ad42b8fb..079dd0922d5c8c 100644 --- a/index.html +++ b/index.html @@ -14,9 +14,11 @@

    Contributing

    EIP status terms

      -
    • Draft - an EIP that is open for consideration.
    • -
    • Accepted - an EIP that is planned for immediate adoption, i.e. expected to be included in the next hard fork (for Core/Consensus layer EIPs).
    • -
    • Final - an EIP that has been adopted in a previous hard fork (for Core/Consensus layer EIPs).
    • +
    • Draft - an EIP that is open for consideration and 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 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.
    Author{% include authorlist.html authors=page.author %}
    Discussions-To{{ page["discussions-to"] | xml_escape }}
    Status{{ page.status | xml_escape }}
    Status{{ page.status | xml_escape }} + {% if page.review-period-end != undefined %} + (review ends {{ page.review-period-end | xml_escape }}) + {% endif %} +
    Type{{ page.type | xml_escape }}
    Category{{ page.category | xml_escape }}