diff --git a/.github/actions/merge-repos/action.yml b/.github/actions/merge-repos/action.yml new file mode 100644 index 00000000000000..7bab2c33072655 --- /dev/null +++ b/.github/actions/merge-repos/action.yml @@ -0,0 +1,24 @@ +name: Merge ERCs + +runs: + using: 'composite' + steps: + - name: Checkout ERCs + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ethereum/ERCs + path: ERCs + - name: Merge Repos + shell: bash + run: | + mkdir -p $GITHUB_WORKSPACE/ERCs/ERCS + mkdir -p $GITHUB_WORKSPACE/ERCs/EIPS + cp -rp $GITHUB_WORKSPACE/ERCs/ERCS/. $GITHUB_WORKSPACE/EIPS + cp -rp $GITHUB_WORKSPACE/ERCs/EIPS/. $GITHUB_WORKSPACE/EIPS + cp -rp $GITHUB_WORKSPACE/ERCs/assets/. $GITHUB_WORKSPACE/assets + cd $GITHUB_WORKSPACE/EIPS + find . -name "erc-*.md" -type f -exec sh -c 'echo mv "$1" "$(echo "$1" | sed s/erc/eip/)"' _ {} \; | sh + cd $GITHUB_WORKSPACE/assets + find . -name "erc-*" -type d -exec sh -c 'echo mv "$1" "$(echo "$1" | sed s/erc/eip/)"' _ {} \; | sh + cd $GITHUB_WORKSPACE + rm -rf ERCs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38b275409999b4..51060d2f3efaf2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: save-pr: name: Save PR Number runs-on: ubuntu-latest - + steps: - name: Save PR number env: @@ -38,7 +38,7 @@ jobs: htmlproofer: name: HTMLProofer - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout EIPs @@ -46,26 +46,10 @@ jobs: with: repository: ethereum/EIPs path: '' - - name: Checkout ERCs - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ethereum/ERCs - path: ERCs - name: Merge Repos - run: | - mkdir -p $GITHUB_WORKSPACE/ERCs/ERCS - mkdir -p $GITHUB_WORKSPACE/ERCs/EIPS - cp -rp $GITHUB_WORKSPACE/ERCs/ERCS/. $GITHUB_WORKSPACE/EIPS - cp -rp $GITHUB_WORKSPACE/ERCs/EIPS/. $GITHUB_WORKSPACE/EIPS - cp -rp $GITHUB_WORKSPACE/ERCs/assets/. $GITHUB_WORKSPACE/assets - cd $GITHUB_WORKSPACE/EIPS - find . -name "erc-*.md" -type f -exec sh -c 'echo mv "$1" "$(echo "$1" | sed s/erc/eip/)"' _ {} \; | sh - cd $GITHUB_WORKSPACE/assets - find . -name "erc-*" -type d -exec sh -c 'echo mv "$1" "$(echo "$1" | sed s/erc/eip/)"' _ {} \; | sh - cd $GITHUB_WORKSPACE - rm -rf ERCs + uses: ./.github/actions/merge-repos - name: Setup Ruby - uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # v1.196.0 + uses: ruby/setup-ruby@fb404b9557c186e349162b0d8efb06e2bc36edea # v1.232.0 with: ruby-version: '3.1' # Not needed with a .ruby-version file bundler-cache: true # runs 'bundle install' and caches installed gems automatically @@ -74,7 +58,7 @@ jobs: run: bundle exec jekyll build env: JEKYLL_ENV: production - + - name: Build Website run: | bundle exec jekyll doctor @@ -88,11 +72,11 @@ jobs: link-check: name: Link Check runs-on: ubuntu-latest - + steps: - name: Checkout EIP Repository uses: actions/checkout@47fbe2df0ad0e27efb67a70beac3555f192b062f - + - name: Link Checker uses: gaurav-nelson/github-action-markdown-link-check@d53a906aa6b22b8979d33bc86170567e619495ec with: @@ -135,6 +119,8 @@ jobs: steps: - name: Checkout EIP Repository uses: actions/checkout@47fbe2df0ad0e27efb67a70beac3555f192b062f + - name: Merge Repos + uses: ./.github/actions/merge-repos - uses: ethereum/eipw-action@be3fa642ec311d0b8e1fdb811e5c9b4ada3d3d93 id: eipw diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml index 5d97260ac443ba..3abe21988a7efa 100644 --- a/.github/workflows/jekyll.yml +++ b/.github/workflows/jekyll.yml @@ -34,28 +34,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout EIPs - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: repository: ethereum/EIPs path: '' - - name: Checkout ERCs - uses: actions/checkout@v4 - with: - repository: ethereum/ERCs - path: ERCs - name: Merge Repos - run: | - mkdir -p $GITHUB_WORKSPACE/ERCs/ERCS - mkdir -p $GITHUB_WORKSPACE/ERCs/EIPS - cp -rp $GITHUB_WORKSPACE/ERCs/ERCS/. $GITHUB_WORKSPACE/EIPS - cp -rp $GITHUB_WORKSPACE/ERCs/EIPS/. $GITHUB_WORKSPACE/EIPS - cp -rp $GITHUB_WORKSPACE/ERCs/assets/. $GITHUB_WORKSPACE/assets - cd $GITHUB_WORKSPACE/EIPS - find . -name "erc-*.md" -type f -exec sh -c 'echo mv "$1" "$(echo "$1" | sed s/erc/eip/)"' _ {} \; | sh - cd $GITHUB_WORKSPACE/assets - find . -name "erc-*" -type d -exec sh -c 'echo mv "$1" "$(echo "$1" | sed s/erc/eip/)"' _ {} \; | sh - cd $GITHUB_WORKSPACE - rm -rf ERCs + uses: ./.github/actions/merge-repos - name: Setup Ruby uses: ruby/setup-ruby@f26937343756480a8cb3ae1f623b9c8d89ed6984 # v1.196.0 with: @@ -64,7 +48,7 @@ jobs: cache-version: 0 # Increment this number if you need to re-download cached gems - name: Setup Pages id: pages - uses: actions/configure-pages@v3 + uses: actions/configure-pages@v5 - name: Build with Jekyll # Outputs to the './_site' directory by default run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}" diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index d2bd33ab7bd224..e2b46fcbf914c0 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -79,7 +79,7 @@ The following is the standardization process for all EIPs in all tracks: **Review** - An EIP Author marks an EIP as ready for and requesting Peer Review. -**Last Call** - This is the final review window for an EIP before moving to `Final`. An EIP editor will assign `Last Call` status and set a review end date (`last-call-deadline`), typically 14 days later. +**Last Call** - This is the final review window for an EIP before it is moved to `Final`. An EIP enters `Last Call` when the specification is stable and the author opens a PR with a review end date (`last-call-deadline`), typically 14 days later. If this period results in necessary normative changes it will revert the EIP to `Review`. @@ -105,7 +105,7 @@ Each EIP should have the following parts: - Specification - The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (besu, erigon, ethereumjs, go-ethereum, nethermind, or others). - Rationale - The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The rationale should discuss important objections or concerns raised during discussion around the EIP. - Backwards Compatibility *(optional)* - All EIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their consequences. The EIP must explain how the author proposes to deal with these incompatibilities. This section may be omitted if the proposal does not introduce any backwards incompatibilities, but this section must be included if backward incompatibilities exist. -- Test Cases *(optional)* - Test cases for an implementation are mandatory for EIPs that are affecting consensus changes. Tests should either be inlined in the EIP as data (such as input/expected output pairs, or included in `../assets/eip-###/`. This section may be omitted for non-Core proposals. +- Test Cases *(optional)* - Test cases for an implementation are mandatory for EIPs that are affecting consensus changes. Tests should either be inlined in the EIP as data (such as input/expected output pairs) or included in `../assets/eip-###/`. This section may be omitted for non-Core proposals. - Reference Implementation *(optional)* - An optional section that contains a reference/example implementation that people can use to assist in understanding or implementing this specification. This section may be omitted for all EIPs. - Security Considerations - All EIPs must contain a section that discusses the security implications/considerations relevant to the proposed change. Include information that might be important for security discussions, surfaces risks and can be used throughout the life-cycle of the proposal. E.g. include security-relevant design decisions, concerns, important discussions, implementation-specific guidance and pitfalls, an outline of threats and risks and how they are being addressed. EIP submissions missing the "Security Considerations" section will be rejected. An EIP cannot proceed to status "Final" without a Security Considerations discussion deemed sufficient by the reviewers. - Copyright Waiver - All EIPs must be in the public domain. The copyright waiver MUST link to the license file and use the following wording: `Copyright and related rights waived via [CC0](../LICENSE.md).` @@ -507,6 +507,24 @@ See the [Citation Style Language Schema](https://resource.citationstyles.org/sch The top-level URL field must resolve to a copy of the referenced document which can be viewed at zero cost. Values under `additional-urls` must also resolve to a copy of the referenced document, but may charge a fee. +### Execution API Specification + +Links to the Ethereum Execution API Specification may be included using normal markdown syntax, such as: + +```markdown +[Ethereum Execution API Specification](https://github.com/ethereum/execution-apis/blob/dd00287101e368752ba264950585dde4b61cdc17/README.md) +``` + +Which renders to: + +[Ethereum Execution API Specification](https://github.com/ethereum/execution-apis/blob/dd00287101e368752ba264950585dde4b61cdc17/README.md) + +Permitted Execution API Specification URLs must anchor to a specific commit, and so must match this regular expression: + +```regex +^(https://github.com/ethereum/execution-apis/(blob|commit)/[0-9a-f]{40}/.*|https://github.com/ethereum/execution-apis/tree/[0-9a-f]{40}/.*)$ +``` + ## Linking to other EIPs References to other EIPs should follow the format `EIP-N` where `N` is the EIP number you are referring to. Each EIP that is referenced in an EIP **MUST** be accompanied by a relative markdown link the first time it is referenced, and **MAY** be accompanied by a link on subsequent references. The link **MUST** always be done via relative paths so that the links work in this GitHub repository, forks of this repository, the main EIPs site, mirrors of the main EIP site, etc. For example, you would link to this EIP as `./eip-1.md`. diff --git a/EIPS/eip-1015.md b/EIPS/eip-1015.md index af447e242e1cc6..f1679228809e66 100644 --- a/EIPS/eip-1015.md +++ b/EIPS/eip-1015.md @@ -48,7 +48,7 @@ This EIP proposes a future hard fork where block reward is not issued to miners/ ##### It can only deal with issuance -It's not meant to be a general governance contract. The contract **should NOT be used to** to decide software updates, to freeze funds, change contracts balances or anything on the consensus layer other than the strict definition of *where block rewards go*. It should be seen as a platform to settle disputes to avoid the implementation of contentious hard forks, not as a mean to remove the power of users and developers to execute them. +It's not meant to be a general governance contract. The contract **should NOT be used** to decide software updates, to freeze funds, change contract balances or anything on the consensus layer other than the strict definition of *where block rewards go*. It should be seen as a platform to settle disputes to avoid the implementation of contentious hard forks, not as a mean to remove the power of users and developers to execute them. ##### It cannot only decrease issuance, and once decreased it cannot be increased again @@ -94,7 +94,7 @@ A contract that has the power to decide the changes to issuance, the core of the The decision would be made by multiple signalling contracts, each one implemented by separate groups and representing one aspect of the community or one sort of measurement. Each signaling process would have a `int` bound in which they could vote and they would have their own internal process to decide that. As new governance methods are tested and debated, new signalling contracts should be added and removed. Suggested signalling contracts: * Futarchy and prediction markets based on multiple measures -* Votes weighted by ether balance (optionally with multipliers if the voters where committed to locking votes) +* Votes weighted by ether balance (optionally with multipliers if the voters were committed to locking votes) * Token votes, weighted by their own relative ether exchange rate * Votes by individual humans if a good sybil resistance, coercion mechanism is developed * Block-signalling, as a way to measure validators/miners choices diff --git a/EIPS/eip-1051.md b/EIPS/eip-1051.md index c6b1a7ef34afb6..6d40d605ee39c3 100644 --- a/EIPS/eip-1051.md +++ b/EIPS/eip-1051.md @@ -25,12 +25,12 @@ The `ovf` flag is set in the following circumstances: - When an `ADD` (`0x01`) opcode, with both inputs treated as unsigned integers, produces an ideal output in excess of 2^256 - 1. - When a `SUB` (`0x03`) opcode, with both inputs treated as unsigned integers, produces an ideal output less than 0. - - When a `MUL`(`0x02`) opcode, with both inputs treated as unsigned integers, produces an ideal output in excess of 2^256 - 1. + - When a `MUL` (`0x02`) opcode, with both inputs treated as unsigned integers, produces an ideal output in excess of 2^256 - 1. The `sovf` flag is set whenever the `ovf` flag is set, and additionally in the following circumstances: - When an `ADD` opcode with both inputs having the same MSB results in the output having a different MSB (eg, `(+a) + (+b) = (-c)` or `(-a) + (-b) = (+c)`). - - When a `SUB` opcode occurs and the result has the same MSB as the subtractand (second argument) (eg, `(+a) - (-b) = (-c)` or `(-a) - (+b) = (+c)`. + - When a `SUB` opcode occurs and the result has the same MSB as the subtracted (second argument) (eg, `(+a) - (-b) = (-c)` or `(-a) - (+b) = (+c)`). - When a `MUL` opcode with both inputs being positive has a negative output. - When a `MUL` opcode with both inputs being negative has a negative output. - When a `MUL` opcode with one negative input and one positive input has a positive output. diff --git a/EIPS/eip-1052.md b/EIPS/eip-1052.md index 356404f1915b14..2dcbc7ce1563e9 100644 --- a/EIPS/eip-1052.md +++ b/EIPS/eip-1052.md @@ -46,9 +46,9 @@ Only the 20 last bytes of the argument are significant (the first 12 bytes are ignored) similarly to the semantics of the `BALANCE` (`0x31`), `EXTCODESIZE` (`0x3b`) and `EXTCODECOPY` (`0x3c`). -The `EXTCODEHASH` distincts accounts without code and non-existing accounts. +The `EXTCODEHASH` distinguishes accounts without code and non-existing accounts. This is consistent with the way accounts are represented in the state trie. -This also allows smart contracts to check whenever an account exists. +This also allows smart contracts to check whether an account exists. ## Backwards Compatibility @@ -59,7 +59,7 @@ There are no backwards compatibility concerns. ## Test Cases 1. The `EXTCODEHASH` of the account without code is `c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` - what is the keccack256 hash of empty data. + what is the keccak256 hash of empty data. 2. The `EXTCODEHASH` of non-existent account is `0`. 3. The `EXTCODEHASH` of a precompiled contract is either `c5d246...` or `0`. 4. If `EXTCODEHASH` of `A` is `X`, then `EXTCODEHASH` of `A + 2**160` is `X`. diff --git a/EIPS/eip-1057.md b/EIPS/eip-1057.md index cccc97a29c040a..0cd85a2660f174 100644 --- a/EIPS/eip-1057.md +++ b/EIPS/eip-1057.md @@ -69,10 +69,10 @@ With the growth of large mining pools, the control of hashing power has been del 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. +4. Delegated centralization vs implementation centralization: While pool centralization is delegated, hardware monoculture is not: only the limited 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. +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 dedicated mining ASIC company as soon as it becomes useful. Therefore, ASIC resistance is: the efficiency difference of specialized 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. @@ -528,7 +528,7 @@ We do not recommend implementing this fix at this time. Ethash will not be explo After the completion of the audits a clever finding by [Kik](https://github.com/kik/) disclosed a vulnerability to [bypassing ProgPoW memory hardness](https://github.com/kik/progpow-exploit). The vulnerability is present in Ethash as well but is near-impossible to exploit. In progPoW it is not possible to exploit -- it assumes the ability to create variants of the candidate block's header hash in a fashion similar to bitcoin, which is actually not possible in Ethereum. An attacker would need modified block headers, would need customized nodes able to accept the modified block headers, and uses extraNonce/extraData as entropy -- which isn’t the standard. And the required brute-force search would be difficult to accomplish in one blocktime. And even if supported by a customized node the block propagation of such mined blocks would be immediately blocked by other peers as the header hash is invalid. -The author's have since found another vulnerability similar to Kik's, but it adds too much overhead to be ASIC-friendly. See Lanfranchi's full explanation [here](https://github.com/ifdefelse/ProgPOW/issues/51#issuecomment-690155355). To completely prevent such exploits we could change the condition modifying the input state of the last keccak pass from +The authors have since found another vulnerability similar to Kik's, but it adds too much overhead to be ASIC-friendly. See Lanfranchi's full explanation [here](https://github.com/ifdefelse/ProgPOW/issues/51#issuecomment-690155355). To completely prevent such exploits we could change the condition modifying the input state of the last keccak pass from * header (256 bits) + * seed for mix initiator (64 bits) + * mix from main loop (256 bits) diff --git a/EIPS/eip-107.md b/EIPS/eip-107.md index c730bd4d3c084f..ca19256546f4e6 100644 --- a/EIPS/eip-107.md +++ b/EIPS/eip-107.md @@ -60,10 +60,10 @@ In this popup window mode, the html file's javascript code will allow ```eth_sen The html page also checks for the availability of the "personal" api and if so, will ask the user to unlock the account if necessary. The unlocking is temporary (3s) so the password will be asked again if a transaction is attempted before the end of this short time. In both iframe mode and window mode, the communication with the dapp is achieved using ```window.postMessage```. -The fist message the iframe/window sends is a message containing the string "ready" to let the dapp know that it now accepts messages. Then the dapp can start performing rpc call by sending message using the following object : +The first message the iframe/window sends is a message containing the string "ready" to let the dapp know that it now accepts messages. Then the dapp can start performing rpc call by sending message using the following object : ``` { - id:, //so responses can be match as there is no guarantee of the order of the response + id:, //so responses can be match as there is no guarantee of the order of the response payload: //this is the exact object that usually send to the node } ``` diff --git a/EIPS/eip-1108.md b/EIPS/eip-1108.md index 85bc480489800f..1b8b4818f0f8bf 100644 --- a/EIPS/eip-1108.md +++ b/EIPS/eip-1108.md @@ -90,9 +90,67 @@ Fast elliptic curve cryptography is a keystone of a growing number of protocols * [The AZTEC protocol](https://github.com/AztecProtocol/AZTEC) utilizes the elliptic curve precompiles to construct private tokens, with zero-knowledge transaction logic, via the [ERC-1723](https://github.com/ethereum/EIPs/issues/1723) and [ERC-1724](https://github.com/ethereum/EIPs/issues/1724) standard. * [Matter Labs](https://github.com/matter-labs/matter-network) utilizes the precompiles to implement Ignis, a scaling solution with a throughput of 500txns per second * [Rollup](https://github.com/rollup/rollup) utilizes the precompiles to create L2 scaling solutions, where the correctness of transactions is guaranteed by main-net, without an additional consensus layer -* [ZEther](https://crypto.stanford.edu/~buenz/papers/zether.pdf) uses precompiles `ECADD` and `ECMUL` to construct confidential transactions - -These are all technologies that have been, or are in the process of being, deployed to main-net. There protocols would all benefit from reducing the gas cost of the precompiles. +* ZEther[^1] uses precompiles `ECADD` and `ECMUL` to construct confidential transactions + +[^1]: + ```csl-json + { + "publisher-place": "Cham", + "URL": "https://eprint.iacr.org/2019/191.pdf", + "custom": { + "additional-urls": [ + "https://web.archive.org/web/20220819003610/https://crypto.stanford.edu/~buenz/papers/zether.pdf" + ] + }, + "DOI": "10.1007/978-3-030-51280-4_23", + "abstract": "Smart contract platforms such as Ethereum and Libra provide ways to seamlessly remove trust and add transparency to various distributed applications. Yet, these platforms lack mechanisms to guarantee user privacy, even at the level of simple payments, which are essential for most smart contracts.", + "author": [ + { + "given": "Benedikt", + "family": "Bünz" + }, + { + "given": "Shashank", + "family": "Agrawal" + }, + { + "given": "Mahdi", + "family": "Zamani" + }, + { + "given": "Dan", + "family": "Boneh" + } + ], + "container-title": "Financial Cryptography and Data Security", + "editor": [ + { + "given": "Joseph", + "family": "Bonneau" + }, + { + "given": "Nadia", + "family": "Heninger" + } + ], + "type": "paper-conference", + "id": "10.1007/978-3-030-51280-4_23", + "citation-key": "10.1007/978-3-030-51280-4_23", + "ISBN": "978-3-030-51280-4", + "issued": { + "date-parts": [ + [ + 2020 + ] + ] + }, + "page": "423-443", + "publisher": "Springer International Publishing", + "title": "Zether: Towards Privacy in a Smart Contract World" + } + ``` + +These are all technologies that have been, or are in the process of being, deployed to main-net. These protocols would all benefit from reducing the gas cost of the precompiles. To give a concrete example, it currently costs `820,000` gas to validate the cryptography in a typical AZTEC confidential transaction. If the gas schedule for the precompiles correctly reflected their load on the Ethereum network, this cost would be `197,000` gas. This significantly increases the potential use cases for private assets on Ethereum. AZTEC is planning to deploy several cryptographic protocols Ethereum, but these are at the limits of what is practical given the current precompile costs: diff --git a/EIPS/eip-1186.md b/EIPS/eip-1186.md index 13ed2e6f3899af..1a341c3f9b8094 100644 --- a/EIPS/eip-1186.md +++ b/EIPS/eip-1186.md @@ -16,7 +16,7 @@ One of the great features of Ethereum is the fact, that you can verify all data ## Abstract -Ethereum uses a [Merkle Tree](https://github.com/ethereum/wiki/wiki/Patricia-Tree) to store the state of accounts and their storage. This allows verification of each value by simply creating a Merkle Proof. But currently, the standard RPC-Interface does not give you access to these proofs. This EIP suggests an additional RPC-Method, which creates Merkle Proofs for Accounts and Storage Values. +Ethereum uses a [Merkle Tree](https://github.com/ethereum/eth-wiki/blob/master/fundamentals/patricia-tree.md) to store the state of accounts and their storage. This allows verification of each value by simply creating a Merkle Proof. But currently, the standard RPC-Interface does not give you access to these proofs. This EIP suggests an additional RPC-Method, which creates Merkle Proofs for Accounts and Storage Values. Combined with a stateRoot (from the blockheader) it enables offline verification of any account or storage-value. This allows especially IOT-Devices or even mobile apps which are not able to run a light client to verify responses from an untrusted source only given a trusted blockhash. diff --git a/EIPS/eip-1283.md b/EIPS/eip-1283.md index cdc8d222b04013..2a56a5607af599 100644 --- a/EIPS/eip-1283.md +++ b/EIPS/eip-1283.md @@ -13,7 +13,7 @@ created: 2018-08-01 This EIP proposes net gas metering changes for `SSTORE` opcode, enabling new usages for contract storage, and reducing excessive gas costs -where it doesn't match how most implementation works. +where it doesn't match how most implementations work. This acts as an alternative for EIP-1087, where it tries to be friendlier to implementations that use different optimization @@ -23,7 +23,7 @@ strategies for storage change caches. This EIP proposes a way for gas metering on SSTORE (as an alternative for EIP-1087 and EIP-1153), using information that is more universally -available to most implementations, and require as little change in +available to most implementations, and requires as little change in implementation structures as possible. * *Storage slot's original value*. @@ -207,7 +207,7 @@ anticipated, and many contracts will see gas reduction. Below we provide 17 test cases. 15 of them covering consecutive two `SSTORE` operations are based on work [by @chfast](https://github.com/ethereum/tests/issues/483). Two additional -case with three `SSTORE` operations is used to test the case when a +cases with three `SSTORE` operations is used to test the case when a slot is reset and then set again. | Code | Used Gas | Refund | Original | 1st | 2nd | 3rd | diff --git a/EIPS/eip-1355.md b/EIPS/eip-1355.md index dba48d45c8e780..60cfe2010d0d1d 100644 --- a/EIPS/eip-1355.md +++ b/EIPS/eip-1355.md @@ -22,7 +22,7 @@ Provide minimal set of changes to Ethash algorithm to hinder and delay the adopt ``` where `FNV1A_PRIME` is 16777499 or 16777639. 2. Change the hash function that determines the DAG item index in Ethash algorithm from `fnv()` to new `fnv1a()`. - In [Main Loop](https://github.com/ethereum/wiki/wiki/Ethash#main-loop) change + In [Main Loop](https://github.com/ethereum/eth-wiki/blob/master/concepts/ethash/ethash.md#main-loop) change ```python p = fnv(i ^ s[0], mix[i % w]) % (n // mixhashes) * mixhashes ``` diff --git a/EIPS/eip-1571.md b/EIPS/eip-1571.md index 5338fd0088d32c..3d0f998860eeef 100644 --- a/EIPS/eip-1571.md +++ b/EIPS/eip-1571.md @@ -10,14 +10,17 @@ created: 2018-11-09 --- ## Abstract + This draft contains the guidelines to define a new standard for the Stratum protocol used by Ethereum miners to communicate with mining pool servers. ### Conventions + 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://tools.ietf.org/html/rfc2119). The definition `mining pool server`, and it's plural form, is to be interpreted as `work provider` and later in this document can be shortened as `pool` or `server`. The definition `miner(s)`, and it's plural form, is to be interpreted as `work receiver/processor` and later in this document can be shortened as `miner` or `client`. ### Rationale + Ethereum does not have an official Stratum implementation yet. It officially supports only getWork which requires miners to constantly pool the work provider. Only recently go-ethereum have implemented a [push mechanism](https://github.com/ethereum/go-ethereum/pull/17347) to notify clients for mining work, but whereas the vast majority of miners do not run a node, it's main purpose is to facilitate mining pools rather than miners. The Stratum protocol on the other hand relies on a standard stateful TCP connection which allows two-way exchange of line-based messages. Each line contains the string representation of a JSON object following the rules of either [JSON-RPC 1.0](https://www.jsonrpc.org/specification_v1) or [JSON-RPC 2.0](https://www.jsonrpc.org/specification). Unfortunately, in absence of a well defined standard, various flavours of Stratum have bloomed for Ethereum mining as a derivative work for different mining pools implementations. The only attempt to define a standard was made by NiceHash with their [EthereumStratum/1.0.0](https://github.com/nicehash/Specifications/blob/master/EthereumStratum_NiceHash_v1.0.0.txt) implementation which is the main source this work inspires from. @@ -25,36 +28,43 @@ Mining activity, thus the interaction among pools and miners, is at it's basics Due to the simplicity of the subject, the proponent, means to stick with JSON formatted objects rather than investigating more verbose solutions, like for example [Google's Protocol Buffers](https://developers.google.com/protocol-buffers/docs/overview) which carry the load of strict object definition. ### Stratum design flaws + The main Stratum design flaw is the absence of a well defined standard. This implies that miners (and mining software developers) have to struggle with different flavours which make their life hard when switching from one pool to another or even when trying to "guess" which is the flavour implemented by a single pool. Moreover all implementations still suffer from an excessive verbosity for a chain with a very small block time like Ethereum. A few numbers may help understand. A normal `mining.notify` message weigh roughly 240 bytes: assuming the dispatch of 1 work per block to an audience of 50k connected TCP sockets means the transmission of roughly 1.88TB of data a month. And this can be an issue for large pools. But if we see the same figures the other way round, from a miner's perspective, we totally understand how mining decentralization is heavily affected by the quality of internet connections. ### Sources of inspiration + - [NiceHash EthereumStratum/1.0.0](https://github.com/nicehash/Specifications/blob/master/EthereumStratum_NiceHash_v1.0.0.txt) - [Zcash variant of the Stratum protocol](https://github.com/zcash/zips/blob/23d74b0373c824dd51c7854c0e3ea22489ba1b76/drafts/str4d-stratum/draft1.rst#json-rpc-1-0) ## Specification + The Stratum protocol is an instance of [JSON-RPC-2.0](https://www.jsonrpc.org/specification). The miner is a JSON-RPC client, and the server is a JSON-RPC server. All communications exist within the scope of a `session`. A session starts at the moment a client opens a TCP connection to the server till the moment either party do voluntary close the very same connection or it gets broken. Servers **MAY** support session resuming if this is initially negotiated (on first session handshaking) between the client and the server. During a session all messages exchanged among server and client are line-based which means all messages are JSON strings terminated by ASCII LF character (which may also be denoted as `\n` in this document). The LF character **MUST NOT** appear elsewhere in a message. Client and server implementations **MUST** assume that once they read a LF character, the current message has been completely received and can be processed. -Line messages are of three types : +Line messages are of three types: + - `Requests` : messages for which the issuer expects a response. The receiver **MUST** reply back to any request individually - `Responses` : solicited messages by a previous request. The responder **MUST** label the response with the same identifier of the originating request. -- `Notifications` : unsolicited messages for which the issuer is not interested nor is expecting a response. Nevertheless a response (eg. an aknowledgement) **MAY** be sent by the receiver. +- `Notifications` : unsolicited messages for which the issuer is not interested nor is expecting a response. Nevertheless a response (eg. an acknowledgement) **MAY** be sent by the receiver. During a `session` both parties **CAN** exchange messages of the above depicted three types. ### JSON-RPC-2.0 Compliances -As per [JSON-RPC-2.0](https://www.jsonrpc.org/specification) specification requests and responses differ from notifications by the identifier (`id`) member in the JSON object: +As per [JSON-RPC-2.0](https://www.jsonrpc.org/specification) specification requests and responses differ from notifications by the identifier (`id`) member in the JSON object: + - Requests **MUST** have an `id` member - Responses **MUST** have an `id` member valued exactly as the `id` member of the request this response is for - Notifications **MUST NOT** have an `id` member ### JSON-RPC-2.0 Defiances -In order to get the most concise messages among parties of a session/conversation this implementation enforces the following defiances : +In order to get the most concise messages among parties of a session/conversation this implementation enforces the following defiances: + - JSON member `jsonrpc` (always valued to "2.0") **MUST ALWAYS BE OMITTED** - JSON member `id` **MUST NOT** be `null`. When member is present, mandatorily in requests and responses, it **MUST** be valued to an integer Number ranging from 0 to 65535. Please note that a message with `"id": 0` **MUST NOT** be interpreted as a notification: it's a request with identifier 0 - JSON member `id` **MUST** be only of type primitive number. The removal of other identifier types (namely strings) is due to the need to reduce the number of bytes transferred. ## Conventions + - The representation of a JSON object is, at it's base, a string - The conversation among the client and the server is made of strings. Each string ending with a LF (ASCII char 10) denotes a `line`. Each line **MUST** contain only one JSON root object. Eventually the root object **MAY** contain additional JSON objects in it's members. - Aside the `LF` delimiter each `line` **MUST** be made of printable ASCII chars in the range 32..126 @@ -70,35 +80,45 @@ In order to get the most concise messages among parties of a session/conversatio - Numbers : any non-fractional number **MUST** be transferred by it's hexadecimal representation ### Requests + The JSON representation of `request` object is made of these parts: + - mandatory `id` member of type Integer : the identifier established by the issuer - mandatory `method` member of type String : the name of the method to be invoked on the receiver side - optional `params` member : in case the method invocation on the receiver side requires the application of additional parameters to be executed. The type **CAN** be Object (with named members of different types) or Array of single type. In case of an array the parameters will be applied by their ordinal position. If the method requested for invocation on the receiver side does not require the application of additional parameters this member **MUST NOT** be present. The notation `"params" : null` **IS NOT PERMITTED** ### Responses + The JSON representation of `response` object is made of these parts: + - mandatory `id` member of type Integer : the identifier of the request this response corresponds to - optional `error` member : whether an error occurred during the parsing of the method or during it's execution this member **MUST** be present and valued. If no errors occurred this member **MUST NOT** be present. For a detailed structure of the `error` member see below. - optional `result` member : This has to be set, if the corresponding request requires a result from the user. If no errors occurred by invoking the corresponding function, this member **MUST** be present even if one or more information are null. The type can be of Object or single type Array or Primitive string/number. If no data is meant back for the issuer (the method is void on the receiver) or an error occurred this member **MUST NOT** be present. -You'll notice here some differences with standard JSON-RPC-2.0. Namely the result member is not always required. Basically a response like this : +You'll notice here some differences with standard JSON-RPC-2.0. Namely the result member is not always required. Basically a response like this: + ```json {"id": 2} ``` + means "request received and processed correctly with no data to send back". To better clarify the concept and clear the field of free interpretations let's take another example of **wrong response** + ```json {"id": 2, "result": false} ``` -This response syntax leaves room to many interpretations : is it an error ? is `false` the legit response value to the issued request ? + +This response syntax leaves room to many interpretations: is it an error? is `false` the legit response value to the issued request? For this reason responses, we reiterate, **MUST BE** of two types: + - success responses : no error occurred during the processing, the request was legit, syntactically correct, and the receiver had no issues processing it. This kind of responses **MUST NOT** have the `error` member and **MAY** have the `result` member if a value is expected back to the issuer. - failure responses : something wrong with the request, it's syntax, it's validity scope, or server processing problems. This kind of responses **MUST HAVE** the `error` member and **MAY** have the `result` member. The latter deserves a better explanation: failure responses can be distinguished by a severity degree. -Example 1 : a client submits a solution and server rejects it cause it's not below target. Server **MUST** respond like this +Example 1 : a client submits a solution and server rejects it cause it's not below target. Server **MUST** respond like this; + ```json { "id": 31, @@ -108,7 +128,9 @@ Example 1 : a client submits a solution and server rejects it cause it's not bel } } ``` -Example 2 : a client submits a solution and server **accepts** it **but** it accounts the share as stale. Server **MUST** respond like this + +Example 2 : a client submits a solution and server **accepts** it **but** it accounts the share as stale. Server **MUST** respond like this; + ```json { "id": 31, @@ -118,7 +140,9 @@ Example 2 : a client submits a solution and server **accepts** it **but** it acc } } ``` -Example 3 : a client submits an authorization request specifying an invalid workername. Server authorizes the account but rejects worker name. Server **MUST** respond like this + +Example 3 : a client submits an authorization request specifying an invalid workername. Server authorizes the account but rejects worker name. Server **MUST** respond like this; + ```json { "id": 1, @@ -140,15 +164,19 @@ Using proper error codes pools may properly inform miners of the condition of th - Error codes 5xx : server could not process the request due to internal errors ### Notifications + A notification message has the very same representation of a `request` with the only difference the `id` member **MUST NOT** be present. This means the issuer is not interested nor expects any response to this message. It's up to the receiver to take actions accordingly. For instance the receiver **MAY** decide to execute the method, or, in case of errors or methods not allowed, drop the connection thus closing the session. #### Error member + As seen above a `response` **MAY** contain an `error` member. When present this member **MUST** be an Object with: + - mandatory member `code` : a Number which identifies the error occurred - mandatory member `message` : a short human readable sentence describing the error occurred - optional member `data` : a Structured or Primitive value that contains additional information about the error. The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.). ## Protocol Flow + - Client starts session by opening a TCP socket to the server - Client advertises and request protocol compatibility - Server confirms compatibility and declares ready @@ -166,6 +194,7 @@ As seen above a `response` **MAY** contain an `error` member. When present this - Eventually either party closes session and TCP connection ### Session Handling - Hello + ~~One of the worst annoyances until now is that server, at the very moment of socket connection, does not provide any useful information about the stratum flavour implemented. This means the client has to start a conversation by iteratively trying to connect via different protocol flavours. This proposal amends the situation making mandatory for the server to advertise itself to the client. When a new client connects to the server, the server **MUST** send a `mining.hello` notification :~~ @@ -185,7 +214,9 @@ For this reason the duty of first advertisement is kept on client which will iss } } ``` + The `params` member object has these mandatory members: + - `agent` (string) the mining software version - `host` (string) the host name of the server this client is willing to connect to - `port` (hex) the port number of the server this client is willing to connect to @@ -194,6 +225,7 @@ The `params` member object has these mandatory members: The rationale behind sending host and port is it enables virtual hosting, where virtual pools or private URLs might be used for DDoS protection, but that are aggregated on Stratum server backends. As with HTTP, the server CANNOT trust the host string. The port is included separately to parallel the client.reconnect method (see below). If the server is prepared to start/resume a session with such requirements it **MUST** reply back with a response like this: + ```json { "id" : 0, @@ -208,7 +240,9 @@ If the server is prepared to start/resume a session with such requirements it ** } } ``` + Where the `result` is an object made of 5 mandatory members + - `proto` (string) which **MUST** match the exact version requested by the client - `encoding` (string) which value states whether or not all **next messages** should be gzip compressed or not. Possible values are "gzip" or "plain" - `resume` (hex) which value states whether or not the host can resume a previously created session; @@ -222,6 +256,7 @@ Should the server, after this reply, receive other messages as plain text, it ** Eventually the client will continue with `mining.subscribe` (further on descripted) Otherwise, in case of errors or rejection to start the conversation, the server **MAY** reply back with an error giving the other party useful information or, at server's maintainers discretion, abruptly close the connection. + ```json { "id" : 0, @@ -232,7 +267,9 @@ Otherwise, in case of errors or rejection to start the conversation, the server } } ``` + or + ```json { "id" : 0, @@ -243,22 +280,28 @@ or } } ``` + _The above two JSON error values are only samples_ Eventually the server will close the connection. -Why a pool should advertise the node's version ? It's a matter of transparency : miners should know whether or not pool have upgraded to latest patches/releases for node's software. +Why a pool should advertise the node's version? It's a matter of transparency : miners should know whether or not pool have upgraded to latest patches/releases for node's software. ### Session Handling - Bye + Disconnection are not gracefully handled in Stratum. Client disconnections from pool may be due to several errors and this leads to waste of TCP sockets on server's side which wait for keepalive timeouts to trigger. A useful notification is `mining.bye` which, once processed, allows both parties of the session to stop receiving and gracefully close TCP connections + ```json { "method": "mining.bye" } ``` + The party receiving this message aknowledges the other party wants to stop the conversation and closes the socket. The issuer will close too. The explicit issuance of this notification implies the session gets abandoned so no session resuming will be possible even on server which support session-resuming. Client reconnecting to the same server which implements session resuming **SHOULD** expect a new session id and **MUST** re-authorize all their workers. ### Session Handling - Session Subscription + After receiving the response to `mining.hello` from server, the client, in case the server does support session resuming **MAY** request to resume a previously interrupted session with `mining.subscribe` request: + ```json { "id": 1, @@ -266,9 +309,11 @@ After receiving the response to `mining.hello` from server, the client, in case "params": "s-12345" } ``` + where `params` is the id of the session the client wants to resume. Otherwise, if client wants to start a new session **OR** server does not support session resuming, the request of subscription **MUST** omit the `params` member: + ```json { "id": 1, @@ -277,19 +322,24 @@ Otherwise, if client wants to start a new session **OR** server does not support ``` ### Session Handling - Response to Subscription + A server receiving a client session subscription **MUST** reply back with + ```json { "id": 1, "result": "s-12345" } ``` + A server receiving a subscription request with `params` being a string holding the session id. This cases may apply + - If session resuming is not supported `result` will hold a new session Id which **MUST** be a different value from the `session` member issued by client in previous `mining.subscribe` method - If session resuming is supported it will retrieve working values from cache and `result` will have the same id requested by the client. This means a session is "resumed": as a consequence the server **CAN** start pushing jobs omitting to precede them with `mining.set` (see below) and the client **MUST** continue to use values lastly received within the same session scope. In addition the client **CAN** omit to re-authorize all it's workers. - If session resuming is supported but the requested session has expired or it's cache values have been purged `result` will hold a new session Id which **MUST** be a different value from the `session` member issued by client in previous `mining.subscribe` method. As a consequence the server **MUST** wait for client to request authorization for it's workers and **MUST** send `mining.set` values before pushing jobs. The client **MUST** prepare for a new session discarding all previously cached values (if any). -A server implementing session-resuming **MUST** cache : +A server implementing session-resuming **MUST** cache: + - The session Ids - Any active job per session - The extraNonce @@ -300,16 +350,21 @@ Servers **MAY** drop entries from the cache on their own schedule. It's up to se A client which successfully subscribes and resumes session (the `session` value in server response is identical to `session` value requested by client on `mining.subscribe`) **CAN** omit to issue the authorization request for it's workers. ### Session Handling - Noop + There are cases when a miner struggles to find a solution in a reasonable time so it may trigger the timeout imposed by the server in case of no communications (the server, in fact, may think the client got disconnected). To mitigate the problem a new method `mining.noop`(with no additional parameters) may be requested by the client. + ```json { "id": 50, "method": "mining.noop" } ``` + ### Session Handling - Reconnect + Under certain circumstances the server may need to free some resources and or to relocate miners to another machine. Until now the only option for servers was to abruptly close the connection. On the miner's side this action is interpreted as a server malfunction and they, more often than not, switch to a failover pool. The implementation of the notification `mining.reconnect` helps client to better merge with logic of handling of large mining pools. + ```json { "method": "mining.reconnect", @@ -320,15 +375,18 @@ The implementation of the notification `mining.reconnect` helps client to better } } ``` + This notification is meant only from servers to clients. Should a server receive such a notification it will simply ignore it. After the notification has been properly sent, the server is ALLOWED to close the connection, while the client will take the proper actions to reconnect to the suggested end-point. -The `host` member in `params` object **SHOULD** report an host DNS name and not an IP address: TLS encrypted connections require to validate the CN name in the certificate which, 99% of the cases, is an host name. +The `host` member in `params` object **SHOULD** report a host DNS name and not an IP address: TLS encrypted connections require to validate the CN name in the certificate which, 99% of the cases, is a host name. The third member `resume` of the `params` object sets whether or not the receiving server is prepared for session resuming. After this notification has been issued by the server, the client should expect no further messages and **MUST** disconnect. ### Workers Authorization + The miner **MUST** authorize at least one worker in order to begin receiving jobs and submit solutions or hashrates. The miner **MAY** authorize multiple workers in the same session. The server **MUST** allow authorization for multiple workers within a session and **MUST** validate at least one authorization from the client before starting to send jobs. A `worker` is a tuple of the address where rewards must be credited coupled with identifier of the machine actually doing the work. For Ethereum the most common form is `.`. The same account can be bound to multiple machines. For pool's allowing anonymous mining the account is the address where rewards must be credited, while, for pools requiring registration, the account is the login name. Each time a solution is submitted by the client it must be labelled with the Worker identifier. It's up to server to keep the correct accounting for different addresses. The syntax for the authorization request is the following: + ```json { "id": 2, @@ -336,22 +394,27 @@ The syntax for the authorization request is the following: "params": ["[.]", "password"] } ``` + `params` member must be an Array of 2 string elements. For anonymous mining the "password" can be any string value or empty but not null. Pools allowing anonymous mining will simply ignore the value. The server **MUST** reply back either with an error or, in case of success, with + ```json { "id": 2, "result": "w-123" } ``` + Where the `result` member is a string which holds an unique - within the scope of the `session` - token which identifies the authorized worker. For every further request issued by the client, and related to a Worker action, the client **MUST** use the token given by the server in response to an `mining.authorize` request. This reduces the number of bytes transferred for solution and /or hashrate submission. If client is resuming a previous session it **CAN** omit the authorization request for it's workers and, in this case, **MUST** use the tokens assigned in the originating session. It's up to the server to keep the correct map between tokens and workers. The server receiving an authorization request where the credentials match previously authorized ones within the same session **MUST** reply back with the previously generated unique token. ### Prepare for mining + A lot of data is sent over the wire multiple times with useless redundancy. For instance the seed hash is meant to change only every 30000 blocks (roughly 5 days) while fixed-diff pools rarely change the work target. Moreover pools must optimize the search segments among miners trying to assign to every session a different "startNonce" (AKA extraNonce). For this purpose the `notification` method `mining.set` allows to set (on miner's side) only those params which change less frequently. The server will keep track of seed, target and extraNonce at session level and will push a notification `mining.set` whenever any (or all) of those values change to the connected miner. + ```json { "method": "mining.set", @@ -363,8 +426,10 @@ For this purpose the `notification` method `mining.set` allows to set (on miner' } } ``` + At the beginning of each `session` the server **MUST** send this notification before any `mining.notify`. All values passed by this notification will be valid for all **NEXT** jobs until a new `mining.set` notification overwrites them. Description of members is as follows: -- optional `epoch` (hex) : unlike all actual Stratum implementations the server should inform the client of the epoch number instead of passing the seed hash. This is enforced by two reasons : the main one is that client has only one way to compute the epoch number and this is by a linear search from epoch 0 iteratively trying increasing epochs till the hash matches the seed hash. Second reason is that epoch number is more concise than seed hash. In the end the seed hash is only transmitted to inform the client about the epoch and is not involved in the mining algorithm. + +- optional `epoch` (hex) : unlike all actual Stratum implementations the server should inform the client of the epoch number instead of passing the seed hash. This is enforced by two reasons: the main one is that client has only one way to compute the epoch number and this is by a linear search from epoch 0 iteratively trying increasing epochs till the hash matches the seed hash. Second reason is that epoch number is more concise than seed hash. In the end the seed hash is only transmitted to inform the client about the epoch and is not involved in the mining algorithm. - optional `target` (hex) : this is the boundary hash already adjusted for pool difficulty. Unlike in EthereumStratum/1.0.0, which provides a `mining.set_difficulty` notification of an _index of difficulty_, the proponent opt to pass directly the boundary hash. If omitted the client **MUST** assume a boundary of `"0x00000000ffff0000000000000000000000000000000000000000000000000000"` - optional `algo` (string) : the algorithm the miner is expected to mine on. If omitted the client **MUST** assume `"algo": "ethash"` - optional `extranonce` (hex) : a starting search segment nonce assigned by server to clients so they possibly do not overlap their search segments. If server wants to "cancel" a previously set extranonce it must pass this member valued as an empty string. @@ -383,7 +448,8 @@ If `extranonce` is valued to an empty string, or it's never been set within the Miners connected to a pool might likely process the very same nonces thus wasting a lot of duplicate jobs. A `nonce` is any valid number which, applied to algorithm and job specifications, produces a result which is below a certain target. For every job pushed by server to client(s) there are 2^64 possible nonces to test. -To be noted that : +To be noted that: + - Any nonce in the 2^64 has the very same possibility to be the right one. - A certain hashing job can be solved by more than one nonce @@ -396,25 +462,30 @@ Every "test" over a number is called a hash. Assuming a miner should receive a j This computation capacity is well beyond any miner on the market (including ASICs). For this reason single miners can process only small chunks (segments) of this humongous range. The way miners pick the segments to search on is beyond the scope of this work. Fact is as miners are not coordinated there is no knowledge - for a single miner - of segments picked by other miners. Extranonce concept is here to mitigate this possibility of duplicate jobs charging the server (the work provider) to give miners, at the maximum possible extent, different segments to search on. -Giving the above assumptions we can depict a nonce as any number in the hex range : +Giving the above assumptions we can depict a nonce as any number in the hex range: ``` Min 0x0000000000000000 Max 0xffffffffffffffff ``` + _the prefix 0x is voluntarily inserted here only to give a better visual representation_. -The `extranonce` is, at it's basics, the message of the server saying the client "_I give you the first number to start search from_". More in detail the `extranoce` is the leftmost part of that number. -Assume a pool notifies the client the usage of extranonce `ab5d` this means the client will see it's search segment narrowed as +The `extranonce` is, at it's basics, the message of the server saying the client "_I give you the first number to start search from_". More in detail the `extranonce` is the leftmost part of that number. +Assume a pool notifies the client the usage of extranonce `ab5d` this means the client will see it's search segment narrowed as + ``` Min 0xab5d000000000000 Max 0xab5dffffffffffff ``` + Pushing an extranonce of 4 bytes (like in the example) will give pool the possibility to separate segment 65535 different miners ( or if you prefer 0xffff miners ) while leaving the miner still a segment of 2^48 possible nonces to search on. Recalculating, as above, the computation capacity needed to search this segment we get + ``` ( 2^48 / 15 ) / 1T ~ 18.76 TeraHashes per second ``` + Which is still a wide segment where miners can randomly (or using other ergodic techniques) pick their internal search segments. Extranonce **MUST** be passed with all relevant bytes (no omission of left zeroes) for a specific reason. Assume an extranonce of "01ac" : it has the same decimal value of "1ac" but the number of bytes changes thus changing available search segment @@ -425,12 +496,15 @@ Extranonce **MUST** be passed with all relevant bytes (no omission of left zeroe Min 0x01ac000000000000 Min 0x1ac0000000000000 Max 0x01acffffffffffff Max 0x1acfffffffffffff ``` + As you can see resulting segments are quite different This all said pools (server), when making use of extranonce, **MUST** observe a maximum length of 6 bytes (hex). ### Jobs notification + When available server will dispatch jobs to connected miners issuing a `mining.notify` notification. + ```json { "method": "mining.notify", @@ -442,14 +516,18 @@ When available server will dispatch jobs to connected miners issuing a `mining.n ] } ``` + `params` member is made of 4 mandatory elements: + - 1st element is jobId as specified by pool. To reduce the amount of data sent over the wire pools **SHOULD** keep their job IDs as concise as possible. Pushing a Job id which is identical to headerhash is a bad practice and is highly discouraged. - 2nd element is the hex number of the block id - 3rd element is the headerhash. - 4th element is an hex boolean indicating whether or not eventually found shares from previous jobs will be accounted for sure as stale. ### Solution submission + When a miner finds a solution for a job he is mining on it sends a `mining.submit` request to server. + ```json { "id": 31, @@ -461,19 +539,23 @@ When a miner finds a solution for a job he is mining on it sends a `mining.submi ] } ``` + First element of `params` array is the jobId this solution refers to (as sent in the `mining.notify` message from the server). Second element is the `miner nonce` as hex. Third element is the token given to the worker previous `mining.authorize` request. Any `mining.submit` request bound to a worker which was not successfully authorized - i.e. the token does not exist in the session - **MUST** be rejected. -You'll notice in the sample above the `miner nonce` is only 12 bytes wide (should be 16). Why ? +You'll notice in the sample above the `miner nonce` is only 12 bytes wide (should be 16). Why? That's because in the previous `mining.set` the server has set an `extranonce` of `af4c`. This means the full nonce is `af4c68765fccd712` In presence of extranonce the miner **MUST** submit only the chars to append to the extranonce to build the final hex value. If no extranonce is set for the session or for the work the miner **MUST** send all 16 bytes. It's server duty to keep track of the tuples `job ids <-> extranonces` per session. When the server receives this request it either responds success using the short form + ```json {"id": 31} ``` + or, in case of any error or condition with a detailed error object + ```json { "id": 31, @@ -487,10 +569,13 @@ or, in case of any error or condition with a detailed error object Client **should** treat errors as "soft" errors (stales) or "hard" (bad nonce computation, job not found etc.). Errors in 5xx range are server errors and suggest the miner to abandon the connection and switch to a failover. ### Hashrate + Most pools offer statistic information, in form of graphs or by API calls, about the calculated hashrate expressed by the miner while miners like to compare this data with the hashrate they read on their devices. Communication about parties of these information have never been coded in Stratum and most pools adopt the method from getWork named `eth_submitHashrate`. In this document we propose an official implementation of the `mining.hashrate` request. This method behaves differently when issued from client or from server. + #### Client communicates it's hashrate to server. + ```json { "id" : 16, @@ -501,12 +586,16 @@ This method behaves differently when issued from client or from server. ] } ``` + where `params` is an array made of two elements: the first is a hexadecimal string representation (32 bytes) of the hashrate the miner reads on it's devices and the latter is the authorization token issued to worker this hashrate is refers to (see above for `mining.authorization`). Server **MUST** respond back with either an aknowledgment message + ```json {"id": 16 } ``` + Optionally the server can reply back reporting it's findings about calculated hashrate **for the same worker**. + ```json { "id": 16, @@ -516,7 +605,9 @@ Optionally the server can reply back reporting it's findings about calculated ha ] } ``` + In case of errors - for example when the client submits too frequently - with + ```json { "id": 16, @@ -526,8 +617,11 @@ In case of errors - for example when the client submits too frequently - with } } ``` + #### Server communicates hashrate to client + Optionally the server can **notify** client about it's overall performance (according to schedule set on server) with a `mining.hashrate` notification composed like this + ```json { "method": "mining.hashrate", @@ -539,7 +633,9 @@ Optionally the server can **notify** client about it's overall performance (acco } } ``` + Where `params` is an object which holds these members for values of the **whole session**: + - `interval` (number) the width, in minutes, of the observation window. "_in the last x minutes we calculated ..._" - `hr` (hex) representation of the hashrate the pool has calculated for the miner - `accepted` is an array of two number elements : the first is the overall count of accepted shares and the second is the number of stale shares. The array must be interpreted as "total accepted of which x are stale" @@ -548,4 +644,5 @@ Where `params` is an object which holds these members for values of the **whole The client will eventually take internal actions to reset/restart it's workers. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index a6bf39fa837eb3..b3f791b88d7b19 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -34,7 +34,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista ## References -1. Included EIPs were finalized in [All Core Devs Call #68](https://github.com/ethereum/pm/blob/master/All%20Core%20Devs%20Meetings/Meeting%2068.md) +1. Included EIPs were finalized in [All Core Devs Call #68](https://github.com/ethereum/pm/blob/master/AllCoreDevs-EL-Meetings/Meeting%2068.md) 2. https://medium.com/ethereum-cat-herders/istanbul-testnets-are-coming-53973bcea7df ## Copyright diff --git a/EIPS/eip-1702.md b/EIPS/eip-1702.md index bfcc9a76b829cb..f200ae2bcdf065 100644 --- a/EIPS/eip-1702.md +++ b/EIPS/eip-1702.md @@ -142,10 +142,10 @@ Note that this section is provided only for documentation purpose. When "enabling EIP-1702", those extensions should not be enabled unless the extension specification is also included. -- [44-VERTXN: Account Versioning Extension for Contract Creation - Transaction](https://specs.corepaper.org/44-vertxn/) -- [45-VEROP: Account Versioning Extension for CREATE and - CREATE2](https://specs.corepaper.org/45-verop/) +* [44-VERTXN: Account Versioning Extension for Contract Creation + Transaction](https://corepaper.org/ethereum/compatibility/versioning/#extensions-for-state-based-account-versioning) +* [45-VEROP: Account Versioning Extension for CREATE and + CREATE2](https://corepaper.org/ethereum/compatibility/versioning/#create-and-create2-extension) ## Usage Template @@ -192,9 +192,9 @@ together), then this will requires extensions such as 44-VERTXN and Alternatively, account versioning can also be done through: -* **[26-VER](https://specs.corepaper.org/26-ver/)** and - **[40-UNUSED](https://specs.corepaper.org/40-unused/)**: This makes an - account's versioning soly dependent on its code header prefix. If +* **[26-VER](https://corepaper.org/ethereum/compatibility/versioning/#prefix-based-account-versioning)** and + **[40-UNUSED](https://corepaper.org/ethereum/compatibility/forward/)**: This makes an + account's versioning solely dependent on its code header prefix. If with only 26-VER, it is not possible to certify any code is valid, because current VM allows treating code as data. This can be fixed by 40-UNUSED, but the drawback is that it's potentially backward @@ -234,7 +234,7 @@ To be added. ## References The source of this specification can be found at -[43-VER](https://specs.corepaper.org/43-ver/). +[43-VER](https://corepaper.org/ethereum/compatibility/versioning/#state-based-account-versioning). ## Copyright diff --git a/EIPS/eip-1898.md b/EIPS/eip-1898.md index 0bb8bc4d7c5ae6..4ab7007867da48 100644 --- a/EIPS/eip-1898.md +++ b/EIPS/eip-1898.md @@ -4,7 +4,7 @@ title: Add `blockHash` to defaultBlock methods description: Add `blockHash` option to JSON-RPC methods that currently support defaultBlock parameter. author: Charles Cooper (@charles-cooper) discussions-to: https://ethereum-magicians.org/t/eip-1898-add-blockhash-option-to-json-rpc-methods-that-currently-support-defaultblock-parameter/11757 -status: Review +status: Final type: Standards Track category: Interface created: 2019-04-01 diff --git a/EIPS/eip-1965.md b/EIPS/eip-1965.md index bb791ced399219..8c78b6f65b29db 100644 --- a/EIPS/eip-1965.md +++ b/EIPS/eip-1965.md @@ -11,16 +11,19 @@ requires: 155 --- ## Abstract + This EIP adds a precompile that returns whether a specific chainID (EIP-155 unique identifier) is valid at a specific blockNumber. ChainID are assumed to be valid up to the blockNumber at which they get replaced by a new chainID. ## Motivation + [EIP-155](./eip-155.md) proposes to use the chain ID to prevent the replay of transactions between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling off-chain message signatures, especially for Layer 2 signature schemes using [EIP-712](./eip-712.md). [EIP-1344](./eip-1344.md) is attempting to solve this by giving smart contract access to the tip of the chainID history. This is insufficient as such value is changing. Hence why EIP-1344 describes a contract based solution to work around the problem. It would be better to solve it in a simpler, cheaper and safer manner, removing the potential risk of misuse present in EIP-1344. Furthermore EIP-1344 can't protect replay properly for minority-led hardfork as the caching system cannot guarantee accuracy of the blockNumber at which the new chainID has been introduced. -[EIP-1959](./eip-1959.md) solves the issue of EIP-1344 but do not attempt to protect from minority-led hardfork as mentioned in the rationale. We consider this a mistake, since it remove some freedom to fork. We consider that all fork should be given equal oportunities. And while there will always be issues we can't solve for the majority that ignore a particular fork, **users that decide to use both the minority-fork and the majority-chain should be protected from replay without having to wait for the majority chain to update its chainID.** +[EIP-1959](./eip-1959.md) solves the issue of EIP-1344 but do not attempt to protect from minority-led hardfork as mentioned in the rationale. We consider this a mistake, since it remove some freedom to fork. We consider that all fork should be given equal opportunities. And while there will always be issues we can't solve for the majority that ignore a particular fork, **users that decide to use both the minority-fork and the majority-chain should be protected from replay without having to wait for the majority chain to update its chainID.** ## Specification + Adds a new precompile which uses 2 argument : a 32 bytes value that represent the chainID to test and a 32 bytes value representing the blockNumber at which the chainID is tested. It return 0x1 if the chainID is valid at the specific blockNumber, 0x0 otherwise. Note that chainID are considered valid up to the blockNumber at which they are replaced. So they are valid for every blockNumber past their replacement. The operation will costs no more than `G_blockhash` + `G_verylow` to execute. This could be lower as chainID are only introduced during hardfork. @@ -35,7 +38,7 @@ The rationale at EIP-1959 applies here as well too : - An opcode is better than a caching system for past chainID, It is cheaper, safer and do not include gaps. - Direct access to the latest chainID is dangerous since it make it easy for contract to use it as a replay protection mechanism while preventing otherwise valid old messages to be valid after a fork that change the chainID. This can have disastrous consequences on users. -- all off-chain messaged signed before a fork should be valid across all side of the fork. +- all off-chain messages signed before a fork should be valid across all side of the fork. The only difference is that this current proposal propose a solution to protect hardfork led by a minority. @@ -45,7 +48,7 @@ To summarize there is 2 possible fork scenario : 2) A minority decide to create an hardfork that the majority disagree with (or simply ignore). Now, the same as above can happen but since we are talking about a minority there is a chance that the majority do not care about the minority. In that case, there would be no incentive for the majority to upgrade the chainID. This means that user of both side of the fork will have the messages meant for the majority chain replayable on the minority-chain (even if this one changed its chainID) unless extra precaution is taken. -The solution is to add the blockNumber representing the time at which the message was signed and use it as an argument to the opcode proposed here. This way, when the minority forks with a new chainID, the previous chainID become invalid from that time onward. So new messages destinated to the majority chain can't be replayed on the minority fork. +The solution is to add the blockNumber representing the time at which the message was signed and use it as an argument to the opcode proposed here. This way, when the minority forks with a new chainID, the previous chainID become invalid from that time onward. So new messages destined to the majority chain can't be replayed on the minority fork. ## Backwards Compatibility @@ -57,7 +60,9 @@ Since chainID and blockNumber will vary, they should not be part of the domain s While the pair could be optional for contract that do not care about replays or have other ways to prevent them, if chainID is present, the blockNumber must be present too. And if any of them is present, wallet need to ensure that the chainID is indeed the latest one of the chain being used, while the blockNumber is the latest one at the point of signing. During fork transition, the wallet can use the blockNumber to know which chainID to use. ## References + This was previously suggested as part of [EIP1959 discussion](https://ethereum-magicians.org/t/eip-1959-valid-chainid-opcode/3170). ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-2003.md b/EIPS/eip-2003.md index c96aac070908c8..2081a82ccf3e7c 100644 --- a/EIPS/eip-2003.md +++ b/EIPS/eip-2003.md @@ -111,7 +111,7 @@ Copyright and related rights waived via [CC0](../LICENSE.md). [EVMC]: https://github.com/ethereum/evmc [EVMC documentation]: https://ethereum.github.io/evmc/ [EVMC VM API]: https://ethereum.github.io/evmc/vmguide.html -[evmc-vmtester]: https://ethereum.github.io/evmc/vmtester.html +[evmc-vmtester]: https://evmc.ethereum.org/vmtester.html [example_precompiles_vm.cpp]: https://github.com/ethereum/evmc/blob/master/examples/example_precompiles_vm/example_precompiles_vm.cpp [ewasm precompiles]: https://github.com/ewasm/ewasm-precompiles diff --git a/EIPS/eip-2025.md b/EIPS/eip-2025.md index ae9baa017c31db..445a348a54c1dc 100644 --- a/EIPS/eip-2025.md +++ b/EIPS/eip-2025.md @@ -55,6 +55,7 @@ FOR BENEFICIARY in BENEFICIARY_ADDRESSES: ``` ## Rewards Distribution Rationale + ``` Development loan repayment: 0.005 ETH per block: 15500 ETH total Development loan interest (10% total over the period, simple interest): 0.0005 ETH per block: 1550 ETH total @@ -62,12 +63,11 @@ FOR BENEFICIARY in BENEFICIARY_ADDRESSES: Total Block Reward Increase = `0.0055` ETH per block: 17050 ETH Total ``` -*With a price of Etheruem at $150.00 this will raise approx USD $2,325,000.00 for developing Eth1.X over the next 18 months.* - +*With a price of Ethereum at $150.00 this will raise approx USD $2,325,000.00 for developing Eth1.X over the next 18 months.* ![Block Rewards Distribution](../assets/eip-2025/block_rewards_distribution.png) *Specific Addresses to be determined -* [FAQ - Why hardcoded values?]( #why-hardcoded-values ) +- [FAQ - Why hardcoded values?]( #why-hardcoded-values ) ## Rationale @@ -90,12 +90,14 @@ There is a risk that the investors lose part of their contribution in the case t `Development Loan: 0.005` over 3.1 Million blocks = 15500 ETH **Funding Working Groups on 1.X** -* Funding Contractors, Coordinators, and project managers -* Working Groups defined with clear mandates + +- Funding Contractors, Coordinators, and project managers +- Working Groups defined with clear mandates Budget Working groups + - State rent (750k) - Better sync (360k) - finality gadget (360k) @@ -111,7 +113,7 @@ At the end of the 18 Months, the whole process would be torn down to prevent any -* [FAQ - How will the funding of the devs be organized?]( #how-will-funding-the-devs-be-organized) +- [FAQ - How will the funding of the devs be organized?]( #how-will-funding-the-devs-be-organized) ## Accountability @@ -126,6 +128,7 @@ The funds will be transferred into DAI and secured in a multi-sig comprised of m - Community ## Personal Notes and Disclosure + I want to address any concerns about conflicts of interests directly. My participation with Eth1.X currently has been as a volunteer. I am in talks about a possible funded role helping with testing and coordination. If my work for with Eth1.x is funded, I will accept no additional funding collected by the mechanism proposed in this EIP. Eth1.X is the now of Ethereum and I would like to see it succeed. This is the intent of my proposal. @@ -154,7 +157,7 @@ Not Implemented ### Why Hardcoded Values? -Why not us a smart contract with some governance mechanism to allow changing the distribution of funds? Wouldn’t that be more flexible and effective? +Why not use a smart contract with some governance mechanism to allow changing the distribution of funds? Wouldn’t that be more flexible and effective? *TLDR: This EIP is not about governance reform* @@ -162,15 +165,15 @@ First, the payment of the loan will be hardcoded. Once agreed, the terms must be After the loan, there is the option to allow the amounts (limited to less than .05ETH), and the locations (orgs that receive ecosystem funding) to be changed throughout the emission schedule. It is pretty easy to imagine a smart contract or DAO fulfilling this role. However, there are three classes of options available today we can consider when governing changes. -* **Give the Keys to the Hands of the Few (Oligarchy)** +- **Give the Keys to the Hands of the Few (Oligarchy)** -Create a multisig that allows a group of individuals to update the smart contract. The most likely candidates for this are the Core Devs themselves, but it could also be a trusted few from the community/stakeholders. No matter how you slice it, there is a fundamental issue in deciding who gets to decide. There currently is not a trusted/adopted governance mechanism to make these decisions within the Ethereum ecosytem. Also, preventing changing the contract in self interest is difficult without a well-engineered governance system of checks and balances. This EIP does not claim nor aim to solve these issues. +Create a multisig that allows a group of individuals to update the smart contract. The most likely candidates for this are the Core Devs themselves, but it could also be a trusted few from the community/stakeholders. No matter how you slice it, there is a fundamental issue in deciding who gets to decide. There currently is not a trusted/adopted governance mechanism to make these decisions within the Ethereum ecosystem. Also, preventing changing the contract in self interest is difficult without a well-engineered governance system of checks and balances. This EIP does not claim nor aim to solve these issues. -* **Give the Keys to the Hands of the Many (Plutarchy)** +- **Give the Keys to the Hands of the Many (Plutarchy)** Allow ethereum holders with coin votes to update the smart contract. Using holographic consensus could overcome the issue of voter turnout as it scales as participation scales, even to the size of the whole network. This has some benefits as the entire network can participate. However, the problem is that some individuals in the network are over represented -- the wealthy. Without a solution to identity that has been agreed to and implemented by the entire Ethereum Network, there is no way around giving more power in votes to the rich. This EIP does not claim, nor aim to solve these issues. -* **Use Ethereum Governance as it is Today** +- **Use Ethereum Governance as it is Today** Criticisms or support aside, there is a system that governs Ethereum today. It is a mix of rough consensus among core devs, miners running nodes, clients implementing changes, and stakeholders adopting those changes. It includes yelling or not yelling on twitter and reddit. It is complicated and I don’t claim to understand it. Even without a clear view of how it works, there is evidence of its existence. This evidence is there are changes that have allowed to be implemented, and changes that have not allowed to be implemented in Ethereum. @@ -180,7 +183,7 @@ This EIP is not about governance reform. ### Why not allow current client implementors fund this work? (EF, Consensys, Parity, etc...) -Historically there has been a precedent that the Ethereum Foundation is solely responsible for funding the development of Ethereum. This process has evolved as the development has become more distributed. Aya Miyaguchi observed in a recent [Coindesk article](https://www.coindesk.com/ethereum-foundation-director-sets-new-vision-for-blockchain-non-profit), “it really is not only Ethereum Foundation people who are building [Ethereum]”. Yes, we could rely on the Ethereum Foundation to fund Eth1.X. But, why should we? This is a call for the network to come together and fund its own development. Ethereum _the network_ is not owned by any one organization or group of people. We are lucky to have the EF and I consider this EIP in support of their coordination efforts. +Historically there has been a precedent that the Ethereum Foundation is solely responsible for funding the development of Ethereum. This process has evolved as the development has become more distributed. Aya Miyaguchi observed in a recent [Coindesk article](https://www.coindesk.com/ethereum-foundation-director-sets-new-vision-for-blockchain-non-profit), “it really is not only Ethereum Foundation people who are building [Ethereum]”. Yes, we could rely on the Ethereum Foundation to fund Eth1.X. But, why should we? This is a call for the network to come together and fund its own development. Ethereum *the network* is not owned by any one organization or group of people. We are lucky to have the EF and I consider this EIP in support of their coordination efforts. ### How Will Funding the Devs be Organized @@ -196,14 +199,14 @@ I am not a lawyer and will seek further guidance from lawyers in the field on th As the result of [REVES ET AL. v . ERNST YOUNG 1990](https://casetext.com/case/reves-v-ernst-young), the court stated that a home loan, consumer financing, a loan secured by a lien on a small business or some assets of a small business, short term notes, or notes that formalize a debt incurred in the ordinary course of business are not securities. If the note resembles the items listed above (home loans, etc.) then the note will not be deemed a security. The Supreme Court provided four factors to determine if a note sufficiently resembles the types of notes that are not classified as securities. ([source](https://www.invigorlaw.com/loan-subject-securities-regulations/)) **Family Resemblance Test** + 1) The intentions of the company and the individual—if the company raised money for general use in a business enterprise, then the note is more likely to be a security; if the individual agreed to the loan primarily for the profit the note was expected to generate, the note is more likely to be a security. 2) The plan of distribution—the more widely the note is offered, the more likely it is to be found a security. 3) The expectations of the investing public—if the investors thought they were investing in a business to make a profit on their investment, the note is more likely to be found a security. 4) Other risk-reducing factor—if the note is collateralized or otherwise less risky than common notes, the note is less likely to be found to be a security. -The loan is for the specific use of supporting Eth1.X research and development. The distribution will not be widely offered and the note will be collateralized by the network itself, provided in ETH and repaid in ETH. In coordinating the collection of these funds recognise I may be legally liable for some of this work and I will do all of the due dilegence I can, seek legal counsel, and accept any legal repercussions resulting from this work. - -#### +The loan is for the specific use of supporting Eth1.X research and development. The distribution will not be widely offered and the note will be collateralized by the network itself, provided in ETH and repaid in ETH. In coordinating the collection of these funds recognise I may be legally liable for some of this work and I will do all of the due dilegence I can, seek legal counsel, and accept any legal repercussions resulting from this work. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-2200.md b/EIPS/eip-2200.md index 9da3dc1360fc1f..39fb53be512985 100644 --- a/EIPS/eip-2200.md +++ b/EIPS/eip-2200.md @@ -151,7 +151,7 @@ Examine examples provided in EIP-1087's Motivation (with `SLOAD_GAS` being In order to keep in place the implicit reentrancy protection of existing contracts, transactions should not be allowed to modify state -if the remaining gas is lower then the gas stipend given to +if the remaining gas is lower than the gas stipend given to "transfer"/"send" in Solidity. These are other proposed remediations and objections to implementing them: diff --git a/EIPS/eip-225.md b/EIPS/eip-225.md index 2dce2e16cca8e2..b14fa30a4edd23 100644 --- a/EIPS/eip-225.md +++ b/EIPS/eip-225.md @@ -192,7 +192,7 @@ This list may be expired after a certain number of blocks / epochs, but it's imp ## Test Cases ```go -// block represents a single block signed by a parcitular account, where +// block represents a single block signed by a particular account, where // the account may or may not have cast a Clique vote. type block struct { signer string // Account that signed this particular block @@ -451,7 +451,7 @@ tests := []struct { }, { // An authorized signer that signed recently should not be able to sign again signers: []string{"A", "B"}, - blocks []block{ + blocks: []block{ {signer: "A"}, {signer: "A"}, }, @@ -467,7 +467,7 @@ tests := []struct { {signer: "A"}, }, failure: errRecentlySigned, - },, + }, } ``` diff --git a/EIPS/eip-2294.md b/EIPS/eip-2294.md index e13f5eb2fafbfa..c67d3bfcd8cd86 100644 --- a/EIPS/eip-2294.md +++ b/EIPS/eip-2294.md @@ -4,7 +4,7 @@ title: Explicit bound to Chain ID size description: Adds a maximum value to the Chain ID parameter to avoid potential encoding issues that may occur when using large values of the parameter. author: Zainan Victor Zhou (@xinbenlv), Alex Beregszaszi (@axic), Bryant Eisenbach (@fubuloubu) discussions-to: https://ethereum-magicians.org/t/eip-2294-explicit-bound-to-chain-id/11090 -status: Review +status: Stagnant type: Informational created: 2019-09-19 requires: 155 @@ -12,15 +12,15 @@ requires: 155 ## Abstract -This EIP informationally defines the "Safe Range" and "Max Range" of ChainId based on a few known restrictions such as [EIP-155](./eip-155.md) and major wallet and JsonPRC representation of ChainId. +This EIP informationally defines the "Safe Range" and "Max Range" of ChainId based on a few known restrictions such as [EIP-155](./eip-155.md) and major wallet and JSON-RPC representation of ChainId. ## Motivation -1. We want chainId to be safe across the different components of the ecosystem such as smart contract, wallet, dApp and JsonPRC etc. +1. We want chainId to be safe across the different components of the ecosystem such as smart contract, wallet, dApp and JSON-RPC etc. 2. We want to enable Cross-Chain function call 3. We want to ensure [EIP-712](./eip-712.md) domains have a clear definition of how to pack ChainID. -4. Enable possbile expansion of chains, such as increasing amount of L2s, L3s, or shards of Ethereum mainnets. -5. Enable hashed based temparary chain: There have been suggestions of using a hash-based identifier in place on Chain ID to allow the value to adapt over time to different contentious forks and other scenarios. This proposal does not describe this behavior, but ~63 bits of entropy should be enough to ensure that no collisions are likely for reasonable (e.g. non-malicious) uses of this feature for that purpose. +4. Enable possible expansion of chains, such as increasing amount of L2s, L3s, or shards of Ethereum mainnets. +5. Enable hashed based temporary chain: There have been suggestions of using a hash-based identifier in place on Chain ID to allow the value to adapt over time to different contentious forks and other scenarios. This proposal does not describe this behavior, but ~63 bits of entropy should be enough to ensure that no collisions are likely for reasonable (e.g. non-malicious) uses of this feature for that purpose. ## Specification @@ -43,7 +43,7 @@ and suggests a reasonable maximum enforced size in order to ensure that there ar Without a well-chosen value of Chain ID, there could be differences in the implementation of [EIP-155](./eip-155.md) (and [EIP-1344](./eip-1344.md) by derivative) in both client codebase and external tooling that could lead to consensus-critical vulnerabilities being introduced to the network. By making this limit explicit, we avoid this scenario for Ethereum and any project which uses the Ethereum codebase. -Also, the field `chainID` have experienced increasing usage and dependencies, due more and more contracts are depending on [EIP-1344](./eip-1344.md) to expose CHAIN ID in the smart contract execution. For example when used with [EIP-712](./eip-712.md), [ERC-1271](./eip-1271.md) for on-contract signature verification, chainId has been increasingly introduced for replay attack prevention. It's security critical to ensure clients depending on the chainId computation in cryptography yields identical result for verification in +Also, the field `chainID` has experienced increasing usage and dependencies, due more and more contracts are depending on [EIP-1344](./eip-1344.md) to expose CHAIN ID in the smart contract execution. For example when used with [EIP-712](./eip-712.md), [ERC-1271](./eip-1271.md) for on-contract signature verification, chainId has been increasingly introduced for replay attack prevention. It's security critical to ensure clients depending on the chainId computation in cryptography yields identical result for verification in all cases. ## Backwards Compatibility diff --git a/EIPS/eip-2537.md b/EIPS/eip-2537.md index c99470686ac77d..bb29a0aa0fd9fa 100644 --- a/EIPS/eip-2537.md +++ b/EIPS/eip-2537.md @@ -4,8 +4,7 @@ title: Precompile for BLS12-381 curve operations description: Adds operation on BLS12-381 curve as a precompile in a set necessary to efficiently perform operations such as BLS signature verification. author: Alex Vlasov (@shamatar), Kelly Olson (@ineffectualproperty), Alex Stokes (@ralexstokes), Antonio Sanso (@asanso) discussions-to: https://ethereum-magicians.org/t/eip2537-bls12-precompile-discussion-thread/4187 -status: Last Call -last-call-deadline: 2025-04-01 +status: Final type: Standards Track category: Core created: 2020-02-21 @@ -195,10 +194,6 @@ Error cases: - An input is on its respective elliptic curve but not in the correct subgroup - Input has invalid length -Note: - -If any input is the infinity point, pairing result will be 1. Protocols may want to check and reject infinity points prior to calling the precompile. - #### ABI for mapping Fp element to G1 point Field-to-curve call expects `64` bytes as an input that is interpreted as an element of Fp. Output of this call is `128` bytes and is an encoded G1 point. diff --git a/EIPS/eip-2539.md b/EIPS/eip-2539.md index 3e4f850a592dfd..d4bb956d83bd32 100644 --- a/EIPS/eip-2539.md +++ b/EIPS/eip-2539.md @@ -4,7 +4,7 @@ title: BLS12-377 curve operations description: Precompiles for BLS12-377 curve operations author: Alex Vlasov (@shamatar), hujw77 (@hujw77) discussions-to: https://ethereum-magicians.org/t/eip-2539-bls12-377-precompile-discussion-thread/4659 -status: Draft +status: Stagnant type: Standards Track category: Core created: 2020-02-26 @@ -178,7 +178,7 @@ Error cases: #### ABI for mapping Fp element to G1 point -Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. Output of this call is `128` bytes and is G1 point following respective encoding rules. +Field-to-curve call expects `64` bytes an input that is interpreted as a an element of the base field. Output of this call is `128` bytes and is G1 point following respective encoding rules. Error cases: - Input has invalid length @@ -186,7 +186,7 @@ Error cases: #### ABI for mapping Fp2 element to G2 point -Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. Output of this call is `256` bytes and is G2 point following respective encoding rules. +Field-to-curve call expects `128` bytes an input that is interpreted as a an element of the quadratic extension field. Output of this call is `256` bytes and is G2 point following respective encoding rules. Error cases: - Input has invalid length diff --git a/EIPS/eip-2696.md b/EIPS/eip-2696.md index 555d5178967d85..fd4323f1c472b6 100644 --- a/EIPS/eip-2696.md +++ b/EIPS/eip-2696.md @@ -39,7 +39,7 @@ interface EthereumProvider { request(args: RequestArguments): Promise } ``` -The Provider **MUST** implement implement a `request` method on the exposed `EthereumProvider` object. The `request` method **MUST** be callable with a single parameter which contains the arguments for the request as defined in the TypeScript `interface` above. +The Provider **MUST** implement a `request` method on the exposed `EthereumProvider` object. The `request` method **MUST** be callable with a single parameter which contains the arguments for the request as defined in the TypeScript `interface` above. If the Provider supports a JSON-RPC (https://www.jsonrpc.org/specification) request as specified elsewhere, then it **MUST** accept a `request` call for that JSON-RPC method with the `RequestArguments.method` argument matching the JSON-RPC `method` string for the RPC call and the `RequestArguments.params` matching the `params` object of the RPC call. The `RequestArguments.params` should be encoded as a JavaScript object matching the specified JSON-RPC type, not encoded as a JSON string as would normally be the case when transporting JSON-RPC. diff --git a/EIPS/eip-2711.md b/EIPS/eip-2711.md index 4c733e9dc9dd57..4c6bf2a974509f 100644 --- a/EIPS/eip-2711.md +++ b/EIPS/eip-2711.md @@ -23,7 +23,7 @@ An EIP-2718 transaction with the type number `2` is a new type of transaction th ### Sponsored Transactions With the advent of tokens and especially stable coins, it has become common for users to not hold ETH in an account while they may have other assets of value in that account. Some users don't want to be exposed to the perceived volatility of ETH and instead would prefer to transact using other assets. Unfortunately, since gas **MUST** be paid for with ETH, this prevents the user from transacting with their assets without first acquiring some ETH using some other means, and then using that ETH to pay fees. -This EIP proposes a mechanism by which we can allow people to transact without ever having to own any ETH by allowing someone else to cover gas costs. The arrangements that enable the covering of gas costs is out of scope for this EIP but it could be an extra-protocol monthly subscription, payment could occur as part of the transaction being submitted, the recpient may be willing to cover gas costs, or it could be a free service offered as a value-add by a company that you are working with. +This EIP proposes a mechanism by which we can allow people to transact without ever having to own any ETH by allowing someone else to cover gas costs. The arrangements that enable the covering of gas costs is out of scope for this EIP but it could be an extra-protocol monthly subscription, payment could occur as part of the transaction being submitted, the recipient may be willing to cover gas costs, or it could be a free service offered as a value-add by a company that you are working with. While it is possible to implement these sort of mechanisms at the individual contract layer, such solutions require integration by just about every contract and those solutions also end up depending on gas costs being stable with time in order to appropriately bake them into contracts without putting either party at risk of malicious participants in the system. For this reason, it is believed that separating out `GAS_PAYER` from `msg.sender` at the protocol layer is valuable. @@ -121,7 +121,7 @@ For the dust-account clearing usecase, - The unix 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 13s 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. -- unix 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. +- unix time is more user-friendly, a user can more easily decide on reasonable end-date for a transaction, rather than a suitable number of valid blocks. ## Backwards Compatibility No known issues. diff --git a/EIPS/eip-2780.md b/EIPS/eip-2780.md index 175d1e541c90cf..16d191dec35b92 100644 --- a/EIPS/eip-2780.md +++ b/EIPS/eip-2780.md @@ -1,116 +1,251 @@ --- eip: 2780 title: Reduce intrinsic transaction gas -author: Matt Garnett (@lightclient), Uri Klarman (@uriklarman) +description: Reduce intrinsic transaction gas and charge 25k when a value transfer creates a new account +author: Matt Garnett (@lightclient), Uri Klarman (@uriklarman), Ben Adams (@benaadams), Maria Inês Silva (@misilva73) discussions-to: https://ethereum-magicians.org/t/eip-2780-reduce-intrinsic-cost-of-transactions/4413 -status: Withdrawn +status: Draft type: Standards Track category: Core created: 2020-07-11 +requires: 1559, 2718, 2929, 2930 --- ## Abstract -Reduce the intrinsic cost of a transaction from `21,000` to `7,000` gas. + +Reduce the intrinsic cost `TX_BASE_COST` from `21,000` to `6,000`. + +If a non-create transaction has `value > 0` and targets a **non-existent** account add `GAS_NEW_ACCOUNT = 25,000` to align with `CALL` account creation and price in state growth. + +This additional `GAS_NEW_ACCOUNT` cost is not applied in the case of a `CREATE` transaction as it is already applied in its cost structure. + +Calldata and access-list metering are unchanged. This is a focused change targeted at the initial stage of processing a transaction and returning the gas overpricing to do more useful work. + +Capacity Impact: + +* **Average:** +18.5% more transactions per block. +* **Max:** +250% more minimal transactions (i.e. pure ETH transfers). +* **"Equivalent" gaslimit:** +18.5% effectual gaslimit increase (e.g. 45 M => 53.3 M); though nominally would remain the same. ## Motivation -The current `21,000` gas intrinsic cost of a transaction makes sending ETH very costly, often times prohibitively costly for small amounts (tens of USD). -While broad changes to the gas price and first price auction are being considerted in other EIPs (like EIP-1559), -substantially reducing the cost of sending ETH and enabling higher volumes of such transactions would be a net positive if done in a safe manner, -and without imposing negative externalities, as outlined below. +The current `21,000` intrinsic gas is a legacy constant. It no longer matches the work all transactions must perform under warm/cold accounting. When decomposed into signature recovery, warming `sender` and `to`, and two warm writes for nonce and balance, the common path totals `6,000` gas. + +Top-level value transfers that create new accounts do not pay an explicit new-account surcharge today, while `CALL` does. This underprices state growth. Charging `GAS_NEW_ACCOUNT = 25,000` on value transfers that create an account aligns entry points and internalizes state growth. + +A high fixed base penalizes small ETH payments and encourages batching to dodge the base rather than for real efficiency. Lowering the base removes that distortion while leaving calldata and storage prices unchanged. + +The result is cheaper ETH transfers without subsidies: state growth costs the same whether reached by `CALL` or by a top-level transfer. Access-list and 1559 mechanics are unchanged. + +We intentionally do **not** charge per-byte gas for the transaction envelope (`nonce`, `gas*`, `to`, `value`, `v`,`r`,`s`). Calldata pricing applies only to `tx.data`. A plain ETH payment has empty tx.data, so it pays zero calldata gas. Lowering `TX_BASE_COST` to the universal work path makes ETH payments cheaper without subsidizing arbitrary calldata. + +### Equivalent gas-limit increase + +Lowering `TX_BASE_COST` from `21,000` to `6,000` removes `15,000` gas per transaction. Using recent totals of 163 Ggas/day and 1.7 M tx/day: + +* Avg gas/tx: `163Bn / 1.7M ≈ 95,882 gas`. +* New avg: `95,882 − 15,000 ≈ 80,882 gas`. +* Throughput at fixed gaslimit: `95,882 / 80,882 ≈ 1.185` (+18.5%). +* Daily tx at same gas: `1.7M × 1.185 ≈ 2.015M` (+315k/day). + +Perfnet ETH transfer tests show EL clients handle `>300 MGas/s` for pure ETH transfers today; expressed under a 6k base this is `300 × (6/21) ≈ 85.7 MGas/s`, i.e., `≈1,029 MGas` per 12 s slot. + +This indicates the protocol-level processing headroom already exists; and that this portion of the tx is significantly overcharged, so isn't extra engineering required to improve preformance to support this change. + +Net effect equals raising a 45 M gas limit to `≈53.3 M` at unchanged calldata and access-list metering. This directly advances Scaling L1. ## Specification -After `block.number >= FORK_BLOCK`, enforce an intrinsic gas cost of `7,000`. + +After `FORK_BLOCK`, set the following parameters and rules. + +### Parameters + +| Name | Value | Description | +| ----------------- | ------ | ------------------------------------------------------------------------- | +| `TX_BASE_COST` | 6,000 | Base cost of any transaction | +| `GAS_NEW_ACCOUNT` | 25,000 | Surcharge when a **value-transferring** transaction creates a new account | + +### New-account surcharge + +Apply `GAS_NEW_ACCOUNT` when **all** are true: + +1. The transaction is not a `CREATE` transaction. +2. `value > 0`. +3. `to` is not a precompile. +4. `to` is **non-existent** per [EIP-161](./eip-161.md) emptiness at the start of transaction execution. + +If these conditions hold the transfer results in account creation and `GAS_NEW_ACCOUNT` is added. This normalizes account-creation cost via EVM `CALL` or top-level transfer and addresses state growth concerns. For reference, this changes such transfers from `21,000` to `31,000` (+10,000 over current). + +Notes: + +* If `value = 0` and `to` is empty per EIP-161, no account is created and no surcharge applies. +* `CREATE` transactions are unchanged; their cost already includes account creation. + +### Intrinsic gas computation + +Clients must compute intrinsic gas exactly as today for each typed transaction **except**: + +* Replace any hardcoded `21,000` with `TX_BASE_COST = 6,000`. +* Add `GAS_NEW_ACCOUNT` when the *New-account surcharge* conditions hold. + +Pseudocode (normative): + +```text +function CalculateIntrinsicGas(tx, state_at_start): + gasCost = TX_BASE_COST + + // Existing rules for calldata and access lists remain unchanged by this EIP. + gasCost += GasForCalldata(tx.data) // per active calldata pricing EIPs + if tx.has_access_list(): + gasCost += GasForAccessList(tx.access_list) // per EIP-2930 + + if tx.is_create() == false + and tx.value > 0 + and is_precompile(tx.to) == false + and is_nonexistent_per_eip161(state_at_start, tx.to): + gasCost += GAS_NEW_ACCOUNT + + return gasCost +``` + +### Code change example + +In `transactions.py`: + +```diff +-TX_BASE_COST = Uint(21000) ++TX_BASE_COST = Uint(6000) +``` + +Typed transactions defined in EIP-1559/EIP-2930 (and EIP-7702 where applicable) that reference the `21,000` base now inherit `TX_BASE_COST = 6,000`. + +### Edits and interactions with other EIPs + +* **EIP-2930 (Access List Transactions).** Replace references to a fixed `21,000` intrinsic gas with `TX_BASE_COST`. The intrinsic-gas formula remains otherwise unchanged. +* **EIP-7702 (Set EOA Code).** Where 7702 inherits intrinsic cost from EIP-2930, that value is `TX_BASE_COST` after `FORK_BLOCK`. No other changes. +* **EIP-7623 (Calldata cost changes).** This EIP does not modify calldata pricing. If EIP-7623 (or other calldata-pricing EIPs) is active, `GasForCalldata` uses those rules unchanged. + +### Derivation (non-normative) + +Sender is recovered from signature, so is ecrecover cost. Sender and `to` match **access-list pricing for touches**; these are **proxies for work**, not additional charges at the top level: + +``` +ECRECOVER_COST = 3,000 +WARM_ACCOUNT_ACCESS_COST = 100 +TX_OVERHEAD_COST = 2,800 +GAS_NEW_ACCOUNT = 25,000 +``` + +`TX_OVERHEAD_COST` bundles fixed per-transaction work that is not separately metered by EVM opcodes: envelope RLP decode and basic validity checks (nonce, gas, chain ID), fee accounting, two warm account updates to `sender.nonce` and `sender.balance`, and minimal trie/header reads and writes for `sender` and `to`. It also includes a conservative margin to cover implementation overhead across EL clients. + +``` +TX_BASE_COST = + ECRECOVER_COST + + 2 * WARM_ACCOUNT_ACCESS_COST + + TX_OVERHEAD_COST + = 6,000 +``` ## Rationale -The proliferation of calls to DeFi smart-contracts had substantially increased the cost of making transactions, -since such calls are usually both time sensitive and involve large sums of money. -While the utilization of the chain's capacity by the most valuable transactions is by design, -the high cost of sending transactionsz is limiting Ethereum's the use-cases, -create a terribel user experience, -decreases the actual value created (and captured) by ETH, -and pushes users to seek alternatives in other, less-congested chains. +Price only what every transaction always does: ECDSA recovery, warming `sender` and `to`, and two warm writes. That sums to `6,000` gas. Anything not universal should be metered separately. + +Calldata remains metered per byte. No calldata allowance is folded into the base. This reinforces ETH as money and payments: a plain ETH transfer carries no calldata, executes no bytecode, and touches no contract storage slots. It only updates warm account nonce and balance, so it receives the discount. + +When a value transfer creates a previously empty account, charge `GAS_NEW_ACCOUNT = 25,000`, identical to `CALL` account-creation pricing. `CREATE` is unchanged because its cost already includes account creation. Access-list pricing is unchanged. + +This removes cross-subsidies, aligns charges with resources, and keeps costs equal across paths that perform the same state growth. + +Do not fold any calldata allowance into the base. The envelope RLP (`nonce`, `gas*`, `to`, `value`, `v`,`r`,`s`) is not charged as calldata and remains unmetered per byte. Only `tx.data` bytes are metered at the existing calldata schedule, and access lists keep their per-entry costs. A vanilla ETH transfer executes no bytecode and touches no contract storage slots; it performs signature recovery, warms sender and to, and does two warm writes (nonce, balance). It therefore receives the base discount and zero calldata gas. +Bundling multiple transfers into a single contract call avoids repeated `TX_BASE_COST`, but those transfers then execute serially inside one EVM context. That blocks parallel execution. With a lower per-tx base cost, users have less incentive to bundle, so more transfers remain independent transactions. Independent transactions can be scheduled across threads, which improves parallelism at the client and execution-layer level. -Note on Layer-2: It is true that the high cost might push users to try using L2 solutions, -however forcing users to utilize L2 by allowing the UX of using L1 to deteriorate is a losing strategy (see BTC / Lightning), -and the safety of many L2 solutions hinges on the ability to use L1 if needed. -If L2 are to gain significant traction they must achieve it by providing superior properties (e.g., finality, cost, UX), -not by imposing artificial restrictions to encourage it. +Thus, reducing `TX_BASE_COST` not only corrects mispricing but also increases the share of transactions that are naturally parallelizable. +### Why not charge full tx data as calldata? -Reducing the intrinsic cost of a transaction from `21,000` to `7,000` gas will make sending transactions cheaper, -is easily achievable, and does not incur technical debt. -However, such a change should only be made after it is determined that it does not impose non-negligible externalities, specifically: +* **Intrinsic coupling to signed fields.** Pricing full-transaction bytes would make intrinsic gas depend on `gas_limit` and variable-length signature elements (`yParity`,`r`,`s` under RLP’s no-leading-zero rule), creating fixed-point estimation and incentives for signature-length selection as well as iteration unstablity as `gas_limit` depends on signiture which contains `gas_limit`. -* Increases uncle-rate. +* **Serialization neutrality.** A fee rule keyed to RLP size couples costs to one encoding and weakens EIP-2718 type neutrality and future formats such as SSZ. Call data is treated as opaque bytes so doesn't have this encoding coupling. -* Increases the pace at which the state-size of Ethereum grows. +* **Policy targeting and market floor.** Calldata floors ([EIP-7623](./eip-7623.md)/[EIP-7976](./eip-7976.md)) price bytes in `tx.data` to bound EL payload and steer data to blobs; envelope bytes are control-plane. The `TX_BASE_COST` is the smallest tx size, and having a low encoding-agnostic intrinsic base keeps the minimum inclusion price strongly coupled to the basefee market. While also not under pricing to open a DoS vector. -* Enhance gas-manipulation technices (gas-token). +* **Native settlement and unit-of-account** Even though all transactions receive the same absolute gas reduction, it propritionatly improves pristine ETH transfers more. With an ETH transfer at ~6,000 gas versus a permissioned ERC-20/LST/stable coin transfer at ~48,000 gas yields an 8 x higher payment throughput per unit gas, which reinforces ETH as the settlement asset with greater money velocity potential and reduces reliance on contract-based money (which carries smart contract risk, operator risk, governance risk and censorship risks via operator). +![Figure 1](../assets/eip-2780/1.png) ## Backwards Compatibility -This EIP is backward compatible as well as compatible with other approaches pursued in other EIPs. -## Test Cases -While the benefits of reducing transactions' intrinsic cost are appearant, -such a change should be applied if it impose no negative externalities, -or if such effects are negligible. +This EIP is **not** backward compatible. It is a consensus gas repricing that must be activated at `FORK_BLOCK`. +Wallets, RPCs, gas estimators, and any logic that assumes a `21,000` base must update. -#### Increased Uncle Rate +### Effects on transactions per block -Historically, periods of high transaction counts has correlated with -higher-than-average uncle blocks being mined. It must be determined that the -new intrinsic cost `7,000` will not adversely affect uncle rate. +Median ETH transfer is 110 bytes of data, so at [EIP-7934](./eip-7934.md)'s 8MiB uncompressed execution block cap creating an effective max tx count by size of: `8,388,608 / 110 ≈ 76,260 tx` -A testnet applying this change should be deployed to test the effect of this change on uncle rate. +This leads to upper limits on gaslimit for raw tx count. Although more complex smart contracts can make use of a higher block gaslimit. However the market dynamics become more complicated when approaching the block cap and there will be distortions in gas pricing; when other approaches would need to be considered -details TBD. +e.g. +* Raising network max block size (currently 10MiB both in EL devp2p and CL specs) +* [EIP-7782](./eip-7782.md): Reduce Block Latency +* [EIP-7999](./eip-7999.md): Unified Multidimensional Fee Market -## Implementation -TBD +Below TPS are additionally given for [EIP-7782](./eip-7782.md) at 6sec and 3sec blocks; as it is an easily considered effect. -## Security Considerations +#### Transaction base fee 6000 + +Binding point for TX_BASE_COST = 6000: 76,260 × 6,000 = 457,560,000 gas. Above ~457.6 M gas, the 8 MiB size cap dominates. +| Block gaslimit | Old tx/bk (21k) | TPS @ 12s | New tx/bk (6k) | TPS @ 12s | TPS @ 6s | TPS @ 3s | TPS @ 1.5s | +| -------------: | --------------: | --------: | -------------: | --------: | -------: | -------: | ---------: | +| 45M | 2,143 | 179 | 7,500 | 625 | 1,250 | 2,500 | 5,000 | +| 60M | 2,857 | 238 | 10,000 | 833 | 1,667 | 3,333 | 6,667 | +| 100M | 4,762 | 397 | 16,667 | 1,389 | 2,778 | 5,556 | 11,111 | +| 200M | 9,524 | 794 | 33,333 | 2,778 | 5,556 | 11,111 | 22,222 | +| 450M | 21,429 | 1,786 | 75,000 | 6,250 | 12,500 | 25,000 | 50,000 | -#### Increased State Size Growth +* Simple ETH transfer tx to an existing EOA: intrinsic drops from `21,000` to `6,000`. (−71%) +* ETH transfer tx that creates a new EOA: intrinsic becomes `6,000 + 25,000` = `31,000`. (+48%) +* Simple ERC-20 token transfer tx (e.g., USDT) drops from `63,200` to `48,200`. (−24%) +* Solady ERC-20 token transfer tx drops from `33,400` to `18,400`. (-45%) +* Average Uniswap v3 Swap tx drops from `184,523` to `169,523`. (−8%) +* Average Uniswap v3 Add Liquidity tx drops from `216,912` to `201912`. (−7%) -The growth of Ethereum's state size continues to raise concerns among members of the community. -However, an analysis of Ethereum accounts shows that their effect on stat size is negligible. +#### Reference MGas/s for gaslimit / slot time -Looking at the first half of 2020, the number of accounts on the Ethereum chain had grown from 84,127,955 to 103,485,373 - an increase of 19,357,418. Since the *creation* of each new account adds 20 bytes to the chain state, these new accounts had added ~369 MB to the state. -At the same time, the chain had grown from ~117 GB to ~147 GB - an increase of 30 GB. -The creation of new accounts had therefore accounted for only a very small percentage (1.2%) of the chain’s growth. +| Block gaslimit | MGas/s @ 12s | MGas/s @ 6s | MGas/s @ 3s | MGas/s @ 1.5s | +| -------------: | -----------: | ----------: | ----------: | ------------: | +| 45M | 3.75 | 7.50 | 15.00 | 30.00 | +| 60M | 5.00 | 10.00 | 20.00 | 40.00 | +| 100M | 8.33 | 16.67 | 33.33 | 66.67 | +| 200M | 16.67 | 33.33 | 66.67 | 133.33 | +| 450M | 37.50 | 75.00 | 150.00 | 300.00 | -Even under the very aggressive assumption that reducing the intrinsic cost of transactions from `21,000` to `7,000` gas would translate to x3 more new accounts being created, if this change was implemented on 1/1/2020, the state size would have only been 0.49% larger than it is today (see below) +## Test Cases -While the sate-size remains an open issue which needs solving - reducing the intrinsic cost of transactions would hardly affect the rate at which the state-size grows, and would significantly improve the chain’s usability. +While the benefits of reducing transactions' intrinsic cost are apparent, such a change should be applied if it imposes no negative externalities, or if such effects are negligible. +Tests should be created with blocks of just ETH transfers and tested on Perfnet across all EL clients to ensure the pricing is correct. -#### Enhancing Gas-Manipulation (gas-token) +Add explicit test vectors: -Gas Token (https://gastoken.io/) is an Ethereum smart-contracts which leverages the storage refund mechanism by storing data (V.1) or creating accounts (V.2) using a low gas price, and then free (V.1) or self-destruct (V.2) them in a later transaction which utilizes a higher gas price. This mechanism is only economical when the high gas price redeeming the tokens is more than twice as high as the low gas price used to mint them. -Gas Tokens do not actually increase the state-size lon-term, as they release all the data they store in order to benefit from their gas boost. -However, they do manipulate the gas price auction. +1. `value > 0` to an empty EOA (non-existent per EIP-161): intrinsic `31,000`. +2. `value > 0` to a precompile: intrinsic `6,000` (no surcharge). +3. `value = 0` to an empty address: intrinsic `6,000` (no creation, no surcharge). +4. `CREATE` transaction: unchanged from prior rules. +5. EIP-7702 transaction with and without access list: intrinsic uses `TX_BASE_COST` plus unchanged access-list costs. +6. Block of txs calling minimal gas contract execution with maximal contract size addresses (so VM is activated for every tx) -There had been concerns that reducing the intrinsic cost of transactions from `21,000` to `7,000` would boost the savings achiieved using gas tokens, however these concerns are unfounded. -Due to some overhead of using the smart contract, minting and freeing a single gas-token is uneconomical, but the effect of the overhead diminishes the more tokens are minted and freed. -This is also the reason why their efficiency is hardly affected by the intrinsic cost of transactions - the gas token is designed to spread the transaction cost among many tokens. +## Security Considerations -The creators of gas tokens outline the maximal potential savings when minting very large number of tokens (up to x2.97 for V.1, and up to 3.49 for V.2). These numbers are *unaffected* by the proposed change. In a more realistic scenario where 100 gas tokens are minted, the proposed change increases the saving multiplier by a minuscule amount, generally smaller than the increase achieved by minting 200 tokens instead of 100. -The table below captures the effect of this proposal on the savings multiplier in a +As this significantly increases the max tx per block this carries risk. -| Version | free_gas_price / mint_gas_price | old savings multiplier | new savings multiplier | saving multiplier of 200 tokens | -|---|---|---|---|---| -| V.1 | 10 | 2.075 | 2.077 | 2.1 | -| V.1 | 100 | 2.780 | 2.781 | 2.819 | -| V.2 | 10 | 2.243 | 2.275 | 2.261 | -| V.2 | 100 | 3.251 | 3.315 | 3.316 | +However this pricing should be the same as performing the component changes inside the transaction; and it factors in the additional costs from state growth which were not originally in the transaction base price. +Current gaslimit testing mostly uses a block with a single transaction; so this should not cause unexpected load compared to what is already being tested. ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-2926.md b/EIPS/eip-2926.md index bb1562d5a56cc7..e1adb95e61861b 100644 --- a/EIPS/eip-2926.md +++ b/EIPS/eip-2926.md @@ -1,26 +1,27 @@ --- eip: 2926 title: Chunk-Based Code Merkleization -author: Sina Mahmoodi (@s1na), Alex Beregszaszi (@axic) +description: Introduce code-chunking in an MPT context. +author: Sina Mahmoodi (@s1na), Alex Beregszaszi (@axic), Guillaume Ballet (@gballet), Jochem Brouwer (@jochem-brouwer), Ignacio Hagopian (@jsign) discussions-to: https://ethereum-magicians.org/t/eip-2926-chunk-based-code-merkleization/4555 -status: Stagnant +status: Draft type: Standards Track category: Core created: 2020-08-25 -requires: 161, 170, 2584 +requires: 161, 170 --- ## Abstract -Code merkleization, along with binarification of the trie and gas cost bump of state accessing opcodes, are considered as the main levers for decreasing block witness sizes in stateless or partial-stateless Eth1x roadmaps. Here we specify a fixed-sized chunk approach to code merkleization and outline how the transition of existing contracts to this model would look like. +Code merkleization, along with binarification of the trie and gas cost bump of state-accessing opcodes, are considered as the main levers for decreasing block witness sizes in stateless or partial-stateless Eth1x roadmaps. Here we specify a fixed-sized chunk approach to code merkleization and outline how the transition of existing contracts to this model would look like. ## Motivation -Bytecode is currently the [second contributor](https://github.com/mandrigin/ethereum-mainnet-bin-tries-data) to block witness size, after the proof hashes. Transitioning the trie from hexary to binary reduces the hash section of the witness by 3x, thereby making code the first contributor. By breaking contract code into chunks and committing to those chunks in a merkle tree, stateless clients would only need the chunks that were touched during a given transaction to execute it. +Bytecode is currently the second contributor to block witness size, after the proof hashes. Transitioning the trie from hexary to binary reduces the hash section of the witness by 3x, thereby making code the first contributor. By breaking contract code into chunks and committing to those chunks in a merkle tree, stateless clients would only need the chunks that were touched during a given transaction to execute it. ## Specification -This specification assumes that [EIP-2584](./eip-2584.md) is deployed, and the merkleization rules and gas costs are proposed accordingly. What follows is structured to have two sections: +What follows is structured to have two sections: 1. How a given contract code is split into chunks and then merkleized 2. How to merkleize all existing contract codes during a hardfork @@ -29,15 +30,12 @@ This specification assumes that [EIP-2584](./eip-2584.md) is deployed, and the m #### Constants -- `CHUNK_SIZE`: 32 (bytes) -- `KEY_LENGTH`: 2 (bytes) -- `MAX_CHUNK_COUNT`: `0xfffc` -- `VERSION_KEY`: `0xfffd` -- `CODELEN_KEY`: `0xfffe` -- `CODEHASH_KEY`: `0xffff` +- `CHUNK_SIZE`: 31 (bytes) +- `VERSION_KEY`: `max(u256)` - `VERSION`: 0 - `EMPTY_CODE_ROOT`: `0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` (==`keccak256('')`) -- `HF_BLOCK_NUMBER`: to be defined +- `HF_TIMESTAMP`: to be defined +- `ITERATOR_STRIDE`: `TBC` but based on verkle numbers, first devnets should use `50_000` #### Definitions @@ -45,94 +43,82 @@ This specification assumes that [EIP-2584](./eip-2584.md) is deployed, and the m ### Code merkleization -For an account record `A` with code `C`, the field `A.codeHash` is replaced with `codeRoot`. `codeRoot` is `EMPTY_CODE_ROOT` if `C` is empty. Otherwise it contains the root of `codeTrie`, a [binary trie](https://hackmd.io/uCWOpSrUQaytBgcO0MVkTQ) with the following leaves: +For an account record `A` with code `C`, two extra optional fields are added: `A.codeSize` and `A.codeRoot`. `A.codeHash` is retained to serve `EXTCODEHASH`. -- Key: `VERSION_KEY`, value: `BE(VERSION, 1)` -- Key: `CODELEN_KEY`, value: `BE(length(C), 4)` -- Key: `CODEHASH_KEY`, value: `keccak256(C)` +If `C` is empty, i.e. in the case of an EoA, `A.codeRoot` and `A.codeSize` are omitted from the account's RLP. This is intended to limit the size overhead of this change. -In addition to the above, `codeTrie` commits to a list of code `chunks = [(FIO_0, code_0), ..., (FIO_n, code_n)]` which are derived from `C` in a way that: +If `C` is not empty: -- `n < MAX_CHUNK_COUNT`. -- `code_0 || ... || code_n == C`. -- `length(code_i) == CHUNK_SIZE` where `0 <= i < n`. -- `length(code_n) <= CHUNK_SIZE`. -- `FIO_i` is the offset of the first instruction within the chunk. It should only be greater than zero if the last instruction in `code_i-1` is a multi-byte instruction (like `PUSHN`) crossing the chunk boundary. It is set to `CHUNK_SIZE` in the case where all bytes of a chunk are data. + - `A.codeSize = len(code)` + - `A.codeRoot` contains the root of `codeTrie`, a trie with the following leaves: + - Key: `VERSION_KEY`, value: `BE(VERSION, 1)` + - A list of code `chunks = [(FIO_0, code_0), ..., (FIO_n, code_n)]` which are derived from `C` as follows: + - `code_0 || ... || code_n == C`. + - `length(code_i) == CHUNK_SIZE` where `0 <= i < n`. + - `length(code_n) <= CHUNK_SIZE`. + - `FIO_i` is the offset of the first instruction within the chunk. It should only be greater than zero if the last instruction in `code_i-1` is a multi-byte instruction (like `PUSHN`) crossing the chunk boundary. It is set to `CHUNK_SIZE` in the case where all bytes of a chunk are data. The `i`th element of `chunks` is stored in `codeTrie` with: -- Key: `BE(i, KEY_LENGTH)` +- Key: `BE(i, 4)` - Value: `BE(FIO_i, 1) || code_i`, where `||` stands for byte-wise concatenation #### Contract creation gas cost -As of now there is a charge of 200 gas per byte of the code stored in state by contract creation operations, be it initiated via `CREATE`, `CREATE2`, or an external transaction. This per byte cost is to be increased from `200` to `TBD` to account for the chunking and merkleization costs. +As of now there is a charge of 200 gas per byte of the code stored in state by contract creation operations, be it initiated via `CREATE`, `CREATE2`, or an external transaction. This per byte cost is to be increased from `200` to `500` to account for the chunking and merkleization costs. This number is inherited from [EIP-4762](./eip-4762.md) and is picked for forward-compatibility. ### Updating existing code (transition process) -The transition process involves reading all contracts in the state and applying the above procedure to them. A benchmark showing how long this process will take is still pending, but intuitively it should take longer than the time between two blocks (in the order of hours). Hence we recommend clients to pre-process the changes before the EIP is activated. +The transition process involves reading all contracts in the state and applying the above procedure to them. A process similar to [EIP-7612](./eip-7612.md) is to be used, as the total code size at the time of this EIP edit is >10GB and can not be processed in a single block. -Code has the nice property that it is (mostly) static. Therefore clients can maintain a mapping of `[accountAddress -> codeRoot]` which stores the results for the contracts they have already merkleized. During this pre-computation phase, whenever a new contract is created its `codeRoot` is computed, and added to the mapping. Whenever a contract self-destructs, its corresponding entry is removed. +Note that: -At block `HF_BLOCK_NUMBER` when the EIP gets activated, before executing any transaction the client must update the account record for all contracts with non-empty code in the state to replace the `codeHash` field with the pre-computed `codeRoot`. EoA accounts will keep their `codeHash` value as `codeRoot`. *Accounts with empty code will keep their `codeHash` value as `codeRoot`.* + - Because multiple accounts can share the same code hash, the whole account tree needs to be iterated over to convert each account. + - Nonetheless, the conversion process should take a few hours, instead of days for a full tree change. + +At `HF_TIMESTAMP` the EIP gets activated: + + - any contract creation and 7702 delegation updates must use the new format. + - for 7702 accounts, the code size is set to `23`, and `CODESIZE`/`CODECOPY` are forwarded to the delegated account. `EXTCODESIZE`/`EXTCODEHASH`/`EXTCODECOPY` behave the same as they did before the activation of this EIP. + - accounts are NOT converted in case of a balance or nonce update + - at the end of block processing, and after all transactions have been executed, the client iterates over `ITERATOR_STRIDE` accounts in the tree, and for each account: + - if the account has empty code, or is a contract using the new format, leave that account untouched, + - if the account is a "legacy" contract, convert it and write it back to the tree + +The value for `ITERATOR_STRIDE` has been chosen to be safe while ensuring the transition process does not last too long. At the current state size and block time, this represents about 10000 blocks, which is about one and a half day. ## Rationale ### Hexary vs binary trie -The Ethereum mainnet state is encoded as of now in a hexary Merkle Patricia Tree. As part of the Eth1x roadmap, a transition to a [binary trie](https://ethresear.ch/t/binary-trie-format/7621) has been [investigated](https://medium.com/@mandrigin/stateless-ethereum-binary-tries-experiment-b2c035497768) with the goal of reducing witness sizes. Because code chunks are also stored in the trie, this EIP would benefit from the witness size reduction offered by the binarification. Therefore we have decided to explicitly state [EIP-2584](./eip-2584.md) to be a requirement of this change. Note that if code merkleization is included in a hard-fork beforehand, then all code must be re-merkleized after the binary transition. +The trie format is chosen to be the same as that of the account trie. If a tree conversion happens at a later stage, the chunk tree will have to be converted as well, e.g. the way it is in [EIP-6800](./eip-6800.md) or [EIP-7864](./eip-7864.md). ### Chunk size -The current recommended chunk size of 32 bytes has been selected based on a few observations. Smaller chunks are more efficient (i.e. have higher [chunk utilization](https://ethresear.ch/t/some-quick-numbers-on-code-merkelization/7260/3)), but incur a larger hash overhead (i.e. number of hashes as part of the proof) due to a higher trie depth. Larger chunks are less efficient, but incur less hash overhead. We plan to run a larger experiment comparing various chunk sizes to arrive at a final recommendation. +The current recommended chunk size of 31 bytes has been selected based on a few observations. Smaller chunks are more efficient (i.e. have higher chunk utilization), but incur a larger hash overhead (i.e. number of hashes as part of the proof) due to a higher trie depth. Larger chunks are less efficient, but incur less hash overhead. We plan to run a larger experiment comparing various chunk sizes to arrive at a final recommendation. ### First instruction offset -The `firstInstructionOffset` fields allows safe jumpdest analysis when a client doesn't have all the chunks, e.g. a stateless clients receiving block witnesses. +The `firstInstructionOffset` field allows safe jumpdest analysis when a client doesn't have all the chunks, e.g. a stateless clients receiving block witnesses. Note: there could be an edge case when computing FIO for the chunks where the data bytes at the end of a bytecode (last chunk) resemble a multi-byte instruction. This case can be safely ignored. ### Gas cost of code-accessing opcodes -How merkleized code is stored in the client database affects the performance of code-accessing opcodes, i.e: CALL, CALLCODE, DELEGATECALL, STATICCALL, EXTCODESIZE, EXTCODEHASH, and EXTCODECOPY. Storing the code trie with all intermediate nodes in the database implies multiple look-ups to fetch the code of the callee, which is more than the current one look-up (excluding the trie traversal to get the account) required. Note CODECOPY and CODESIZE are not affected since the code for the current contract has already been loaded to memory. - -The gas cost analysis in this section assumes a specific way of storing it. In this approach clients only merkleize code once during creation to compute `codeRoot`, but then discard the chunks. They instead store the full bytecode as well as the metadata fields in the database. We believe per-chunk metering for calls would be more easily solvable by witness metering in the stateless model. +Details of how the code is stored, is left to the client implementers. However, to reflect the removal of the max code limit and the fact that larger codes will be more expensive to load, reading a non-accessed chunk will incur a 200 warming cost, and chunks written beyond the 24kb limit will cost 500 gas instead of 200. ### Different chunking logic We have considered an alternative option to package chunks, where each chunk is prepended with its `chunkLength` and would only contain complete opcodes (i.e. any multi-byte opcode not fitting the `CHUNK_SIZE` would be deferred to the next chunk). This approach has downsides compared to the one specified: + 1) Requires a larger `CHUNK_SIZE` -- at least 33 bytes to accommodate the `PUSH32` instruction. 2) It is more wasteful. For example, `DUP1 PUSH32 <32-byte payload>` would be encoded as two chunks, the first chunk contains only `DUP1`, and the second contains only the `PUSH32` instruction with its payload. 3) Calculating the number of chunks is not trivial and would have to be stored explicitly in the metadata. Additionally we have reviewed many other options (basic block based, Solidity subroutines (requires determining the control flow), EIP-2315 subroutines). This EIP however only focuses on the chunk-based option. -### RLP and SSZ - -To remain consistent with the binary transition proposal we avoid using RLP for serializing the leaf values. We have furthermore considered SSZ for both serializing data and merkleization and remain open to adopting it, but decided to use the binary trie format for simplicity. - -### Metadata fields - -The metadata fields `version`, `codeLen` and `codeHash` are added mostly to facilitate a cheaper implementation of `EXTCODESIZE` and `EXTCODEHASH` in a stateless paradigm. The version field allows for differentiating between bytecode types (e.g. [EVM1.5/EIP-615](./eip-615.md), [EIP-2315](./eip-2315.md), etc.) or code merkleization schemes (or merkleization settings, such as larger `CHUNK_SIZE`) in future. - -Instead of encoding `codeHash` and `codeSize` in the metadata, they could be made part of the account. In our opinion, the metadata is a more concise option, because EoAs do not need these fields, resulting in either additional logic (to omit those fields in the accounts) or calculation (to include them in merkleizing the account). - -An alternative option to the version field would be to add an account-level field: either following [EIP-1702](./eip-1702.md), or by adding an `accountKind` field (with potential options: `eoa`, `merkleized_evm_chunk32`, `merkleized_eip2315_chunk64`, etc.) as the first member of the account. One benefit this could provide is omitting `codeHash` for EoAs. - -### The keys in the code trie (and `KEY_LENGTH`) - -As explained in the specification above, the keys in the code trie are indices of the `chunks` array. Having a key length of 2 bytes means the trie can address 65536 - 3 (minus metadata fields) chunks, which corresponds to ~2Mb code size. That allows for roughly ~85x increase in the code size limit in future without requiring a change in merkleization. - -### Alternate values of codeRoot for EoAs - -This proposal changes the meaning of the fourth field (`codeHash`) of the account. Prior to this change, that field represents the Keccak-256 hash of the bytecode, which is logically hash of an empty input for EoAs. - -Since `codeHash` is replaced with `codeRoot`, the root hash of the code trie, the value would be different for EoAs under the new rules: the root of the `codeTrie(metadata=[codeHash=keccak256(''), codeSize=0])`. An alternative would be simply using the hash of an empty trie. Or to avoid introducing yet another constant (the result of the above), one could also consider using `codeRoot = 0` for EoAs. - -However, we wanted to maintain compatibility with [EIP-1052](./eip-1052.md) and decided to keep matters simple by using the hash of empty input (`c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470`) for EoAs. - ## Backwards Compatibility From the perspective of contracts, the design aims to be transparent, with the exception of changes in gas costs. @@ -149,13 +135,10 @@ Show the `codeRoot` for the following cases: 2. `code='PUSH1(0) DUP1 REVERT'` 3. `code='PUSH32(-1)'` (data passing through a chunk boundary) -## Implementation - -The implementation of the chunking and merkleization logic in Typescript can be found [here](https://github.com/ewasm/biturbo/blob/merklize-mainnet-blocks/src/relayer/bytecode.ts#L172), and in Python [here](https://github.com/hugo-dc/code-chunks/). Please note neither of these examples currently use a binary tree. - ## Security Considerations TBA ## Copyright + Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-2935.md b/EIPS/eip-2935.md index ab2382d5d70e78..b2cc9732192c87 100644 --- a/EIPS/eip-2935.md +++ b/EIPS/eip-2935.md @@ -1,11 +1,10 @@ --- eip: 2935 title: Serve historical block hashes from state -description: Store and serve last 8192 block hashes as storage slots of a system contract to allow for stateless execution +description: Store and serve last 8191 block hashes as storage slots of a system contract to allow for stateless execution author: Vitalik Buterin (@vbuterin), Tomasz Stanczak (@tkstanczak), Guillaume Ballet (@gballet), Gajinder Singh (@g11tech), Tanishq Jasoria (@tanishqjasoria), Ignacio Hagopian (@jsign), Jochem Brouwer (@jochem-brouwer), Sina Mahmoodi (@s1na) discussions-to: https://ethereum-magicians.org/t/eip-2935-save-historical-block-hashes-in-state/4565 -status: Last Call -last-call-deadline: 2025-04-01 +status: Final type: Standards Track category: Core created: 2020-09-03 @@ -197,7 +196,7 @@ The latter option is as follows: ```python def process_block_hash_history(block: Block, state: State): - if block.timestamp >= FORK_TIMESTAMP: // FORK_TIMESTAMP should be definied outside of the EIP + if block.timestamp >= FORK_TIMESTAMP: // FORK_TIMESTAMP should be defined outside of the EIP state.insert_slot(HISTORY_STORAGE_ADDRESS, (block.number-1) % HISTORY_SERVE_WINDOW , block.parent.hash) ``` @@ -215,11 +214,11 @@ This EIP introduces backwards incompatible changes to the block validation rule ## Test Cases -TBD +[EIP-2935 Execution Spec Tests](https://github.com/ethereum/execution-spec-tests/tree/3810d22f84f206866f66f4f6bf856187c2893ab1/tests/prague/eip2935_historical_block_hashes_from_state) ## Security Considerations -Having contracts (system or otherwise) with hot update paths (branches) poses a risk of "branch" poisioning attacks where attacker could sprinkle trivial amounts of eth around these hot paths (branches). But it has been deemed that cost of attack would escalate significantly to cause any meaningful slow down of state root updates. +Having contracts (system or otherwise) with hot update paths (branches) poses a risk of "branch" poisoning attacks where attacker could sprinkle trivial amounts of eth around these hot paths (branches). But it has been deemed that cost of attack would escalate significantly to cause any meaningful slow down of state root updates. ## Copyright diff --git a/EIPS/eip-2938.md b/EIPS/eip-2938.md index 2d208f4a2c87b5..ce55b6e9f747a9 100644 --- a/EIPS/eip-2938.md +++ b/EIPS/eip-2938.md @@ -3,11 +3,12 @@ eip: 2938 title: Account Abstraction author: Vitalik Buterin (@vbuterin), Ansgar Dietrichs (@adietrichs), Matt Garnett (@lightclient), Will Villanueva (@villanuevawill), Sam Wilson (@SamWilsn) discussions-to: https://ethereum-magicians.org/t/eip-2938-account-abstraction/4630 -status: Stagnant +status: Withdrawn type: Standards Track category: Core created: 2020-09-04 requires: 2718 +withdrawal-reason: Very out of date; needs rewrite. --- ## Simple Summary diff --git a/EIPS/eip-2982.md b/EIPS/eip-2982.md index 6a6d00063329d7..379dfb5cdbe993 100644 --- a/EIPS/eip-2982.md +++ b/EIPS/eip-2982.md @@ -238,7 +238,7 @@ For each duty, the actual reward is computed as follows. If: Then: -* Any validator that fulfilled the dury gets a reward of $R * P$ +* Any validator that fulfilled the duty gets a reward of $R * P$ * Any validator that did not fulfill the duty gets a penalty $-R$ The purpose of this "collective reward" scheme where "if anyone performs better, everyone performs better" is to bound griefing factors (see [this paper](../assets/eip-2982/ef-Discouragement-Attacks.pdf) for one description of griefing factors and why they are important). @@ -416,7 +416,7 @@ In phase 0, a "withdrawn" validator cannot actually withdraw to anywhere yet; th #### Effective balances -Most calculations based on a validator's balance use the validator's "effective balance"; the only exception is calculations that increase or decrease the validator's balance. Only when the validators's balance $B$ falls below $EB$ or goes above $EB + 1.5$ is $EB$ adjusted to equal $floor(B)$. This is done to ensure that effective balance changes infrequently, reducing the amount of hashing needed to do to recompute the state every epoch; on average, only the balances need to all be updated, and the effective balances only get updated relatively rarely per validator. Balances are all stored in a dedicated vector, so $2 * \frac{N * 8}{32} = \frac{N}{2}$ hashes are needed to recompute a balance array, whereas effective balances are stored in validator record objects, where at least $5N$ hashes would be needed per validator to adjust the SSZ hash roots. Additionally, $EB$ can be compressed more easily into a CompactValidator object, as it's only one byte. +Most calculations based on a validator's balance use the validator's "effective balance"; the only exception is calculations that increase or decrease the validator's balance. Only when the validators's balance $B$ falls below $EB$ or goes above $EB + 1.5$ is $EB$ adjusted to equal $floor(B)$. This is done to ensure that effective balance changes infrequently, reducing the amount of hashing needed to recompute the state every epoch; on average, only the balances need to all be updated, and the effective balances only get updated relatively rarely per validator. Balances are all stored in a dedicated vector, so $2 * \frac{N * 8}{32} = \frac{N}{2}$ hashes are needed to recompute a balance array, whereas effective balances are stored in validator record objects, where at least $5N$ hashes would be needed per validator to adjust the SSZ hash roots. Additionally, $EB$ can be compressed more easily into a CompactValidator object, as it's only one byte. ### Fork mechanism diff --git a/EIPS/eip-3026.md b/EIPS/eip-3026.md index 560f13bc63a465..4b762acdd2553f 100644 --- a/EIPS/eip-3026.md +++ b/EIPS/eip-3026.md @@ -28,7 +28,7 @@ The multiexponentiation operations are a generalization of point multiplication, ## Motivation -This EIP is based on and tends to replace matter-labs' proposol for significant performance reasons. In most applications, BW6-761 is used as an outer curve to BLS12-377 considered in [EIP-2539](./eip-2539.md). +This EIP is based on and tends to replace matter-labs' proposal for significant performance reasons. In most applications, BW6-761 is used as an outer curve to BLS12-377 considered in [EIP-2539](./eip-2539.md). The motivation of this precompile is to allow efficient one-layer composition of SNARK proofs. Currently this is done by Zexe using the BLS12-377/CP6-782 pair of curves. This precompile proposes a replacement of CP6-782 by BW6-761, which allows much faster operations. For example, it was shown that verifying a Groth16 proof with BW6-761 is 30 times faster than with CP6-782. ### Proposed addresses table @@ -235,13 +235,13 @@ Gas cost is derived by taking the average timing of the same operations over dif - G1 addition: Average timing of 1000 random samples. - G1 multiplication: Average timing of 1000 samples of random worst-case of double-and-add algorithm (scalar of max bit length and max hamming weight and random base points in G1) - G2 addition: Average timing of 1000 random samples -- G2 multiplication: Average timing of 1000 samples of radnom worst-case of double-and-add algorithm (scalar of max bit length and max hamming weight and random base points in G2) +- G2 multiplication: Average timing of 1000 samples of random worst-case of double-and-add algorithm (scalar of max bit length and max hamming weight and random base points in G2) - G1 and G2 multiexponentiations: Expected to be performed by the Peppinger algorithm, with a table prepared for discount in case of `k <= 128` points in the multiexponentiation with a discount cup `max_discount` for `k > 128`. To avoid non-integer arithmetic call cost is calculated as `k * multiplication_cost * discount / multiplier` where `multiplier = 1000`, `k` is a number of (scalar, point) pairs for the call, `multiplication_cost` is a corresponding single multiplication call cost for G1/G2. - Pairing: Average timing of 1000 random samples (random points in G1 and G2) for different number of pairs with linear lifting. ### Multiexponentiation as a separate call -Explicit separate multiexponentiation operation that allows one to save execution time (so gas) by both the algorithm used (namely Peppinger algorithm) and (usually forgotten) by the fact that `CALL` operation in Ethereum is expensive (at the time of writing), so one would have to pay non-negigible overhead if e.g. for multiexponentiation of `100` points would have to call the multipication precompile `100` times and addition for `99` times (roughly `138600` would be saved). +Explicit separate multiexponentiation operation that allows one to save execution time (so gas) by both the algorithm used (namely Peppinger algorithm) and (usually forgotten) by the fact that `CALL` operation in Ethereum is expensive (at the time of writing), so one would have to pay non-negigible overhead if e.g. for multiexponentiation of `100` points would have to call the multiplication precompile `100` times and addition for `99` times (roughly `138600` would be saved). ### Explicit subgroup checks diff --git a/EIPS/eip-3074.md b/EIPS/eip-3074.md index aeb5b3d186def2..52307e90a12b4f 100644 --- a/EIPS/eip-3074.md +++ b/EIPS/eip-3074.md @@ -4,11 +4,12 @@ title: AUTH and AUTHCALL opcodes description: Allow externally owned accounts to delegate control to a contract. author: Sam Wilson (@SamWilsn), Ansgar Dietrichs (@adietrichs), Matt Garnett (@lightclient), Micah Zoltu (@micahzoltu) discussions-to: https://ethereum-magicians.org/t/eip-3074-sponsored-transaction-precompile/4880 -status: Stagnant +status: Withdrawn type: Standards Track category: Core created: 2020-10-15 requires: 155 +withdrawal-reason: Superseded by EIP-7702 --- ## Abstract diff --git a/EIPS/eip-3155.md b/EIPS/eip-3155.md index 009bc77d78fd82..a3620384b20979 100644 --- a/EIPS/eip-3155.md +++ b/EIPS/eip-3155.md @@ -4,7 +4,8 @@ title: EVM trace specification description: A JSON format for EVM traces author: Martin Holst Swende (@holiman), Marius van der Wijden (@MariusVanDerWijden) discussions-to: https://ethereum-magicians.org/t/eip-3155-create-evm-trace-specification/5007 -status: Review +status: Last Call +last-call-deadline: 2025-03-01 type: Standards Track category: Interface created: 2020-12-07 diff --git a/EIPS/eip-3220.md b/EIPS/eip-3220.md index 949413a3f24231..87add1747e91f1 100644 --- a/EIPS/eip-3220.md +++ b/EIPS/eip-3220.md @@ -44,7 +44,7 @@ Hence there is need for a more robust blockchain identifier that will overcome t | Name | Size(bytes) | Description | |---------------|-------------|-------------| -| Truncated Block Hash | 16 | This is the block hash of the genesis block or the block hash of of the block immediate prior to the fork for a fork of a blockchain. The 16 bytes is the 16 least significant bytes, assuming network byte order.| +| Truncated Block Hash | 16 | This is the block hash of the genesis block or the block hash of the block immediate prior to the fork for a fork of a blockchain. The 16 bytes is the 16 least significant bytes, assuming network byte order.| |Native Chain ID| 8 | This is the **Chain Id** value that should be used with the blockchain when signing transactions. For blockchains that do not have a concept of **Chain Id**, this value is zero.| |Chain Type| 2 | Reserve 0x00 as undefined chaintype. 0x01 as mainnet type. 0x1[0-A]: testnet, 0x2[0-A]: private development network| | Governance Identifier | 2 | For new blockchains, a governance_identifier can be specified to identify an original **owner** of a blockchain, to help settle forked / main chain disputes. For all existing blockchains and for blockchains that do not have the concept of an **owner**, this field is zero. | diff --git a/EIPS/eip-3540.md b/EIPS/eip-3540.md index 237875093cf4b7..6b34d1bf71c45a 100644 --- a/EIPS/eip-3540.md +++ b/EIPS/eip-3540.md @@ -2,9 +2,9 @@ eip: 3540 title: EOF - EVM Object Format v1 description: EOF is an extensible and versioned container format for EVM bytecode with a once-off validation at deploy time. -author: Alex Beregszaszi (@axic), Paweł Bylica (@chfast), Andrei Maiboroda (@gumb0), Matt Garnett (@lightclient) +author: Alex Beregszaszi (@axic), Paweł Bylica (@chfast), Andrei Maiboroda (@gumb0), Matt Garnett (@lightclient), Piotr Dobaczewski (@pdobacz) discussions-to: https://ethereum-magicians.org/t/evm-object-format-eof/5727 -status: Stagnant +status: Review type: Standards Track category: Core created: 2021-03-16 @@ -53,7 +53,7 @@ EOF-formatted contracts are created using new instructions which are introduced The opcode `0xEF` is currently an undefined instruction, therefore: *It pops no stack items and pushes no stack items, and it causes an exceptional abort when executed.* This means legacy *initcode* or already deployed legacy *code* starting with this instruction will continue to abort execution. -Unless otherwised specified, all integers are encoded in big-endian byte order. +Unless otherwise specified, all integers are encoded in big-endian byte order. ### Code validation @@ -110,44 +110,42 @@ header := kind_data, data_size, terminator body := types_section, code_section+, container_section*, data_section -types_section := (inputs, outputs, max_stack_height)+ +types_section := (inputs, outputs, max_stack_increase)+ ``` *note: `,` is a concatenation operator, `+` should be interpreted as "one or more" of the preceding item, `*` should be interpreted as "zero or more" of the preceding item, and `[item]` should be interpreted as an optional item.* #### Header -| name | length | value | description | -|------------------------|----------|---------------|--------------------------------------------------------------------------------------------------------------| -| magic | 2 bytes | 0xEF00 | | -| version | 1 byte | 0x01 | EOF version | -| kind_type | 1 byte | 0x01 | kind marker for type section | -| type_size | 2 bytes | 0x0004-0x1000 | 16-bit unsigned big-endian integer denoting the length of the type section content, 4 bytes per code section | -| kind_code | 1 byte | 0x02 | kind marker for code size section | -| num_code_sections | 2 bytes | 0x0001-0x0400 | 16-bit unsigned big-endian integer denoting the number of the code sections | -| code_size | 2 bytes | 0x0001-0xFFFF | 16-bit unsigned big-endian integer denoting the length of the code section content | -| kind_container | 1 byte | 0x03 | kind marker for container size section | -| num_container_sections | 2 bytes | 0x0001-0x0100 | 16-bit unsigned big-endian integer denoting the number of the container sections | -| container_size | 2 bytes | 0x0001-0xFFFF | 16-bit unsigned big-endian integer denoting the length of the container section content | -| kind_data | 1 byte | 0x04 | kind marker for data size section | -| data_size | 2 bytes | 0x0000-0xFFFF | 16-bit unsigned big-endian integer denoting the length of the data section content (*) | -| terminator | 1 byte | 0x00 | marks the end of the header | +| name | length | value | description | +|------------------------|---------|-----------------------|--------------------------------------------------------------------------------------------------------------| +| magic | 2 bytes | 0xEF00 | | +| version | 1 byte | 0x01 | EOF version | +| kind_type | 1 byte | 0x01 | kind marker for type section | +| type_size | 2 bytes | 0x0004-0x1000 | 16-bit unsigned big-endian integer denoting the length of the type section content, 4 bytes per code section | +| kind_code | 1 byte | 0x02 | kind marker for code size section | +| num_code_sections | 2 bytes | 0x0001-0x0400 | 16-bit unsigned big-endian integer denoting the number of the code sections | +| code_size | 2 bytes | 0x0001-0xFFFF | 16-bit unsigned big-endian integer denoting the length of the code section content | +| kind_container | 1 byte | 0x03 | kind marker for container size section | +| num_container_sections | 2 bytes | 0x0001-0x0100 | 16-bit unsigned big-endian integer denoting the number of the container sections | +| container_size | 4 bytes | 0x00000001-0xFFFFFFFF | 32-bit unsigned big-endian integer denoting the length of the container section content | +| kind_data | 1 byte | 0xFF | kind marker for data size section | +| data_size | 2 bytes | 0x0000-0xFFFF | 16-bit unsigned big-endian integer denoting the length of the data section content (*) | +| terminator | 1 byte | 0x00 | marks the end of the header | (*) For not yet deployed containers this can be greater than the actual content length. #### Body -| name | length | value | description | -|-------------------|----------|---------------|--------------------------------------------------------------------------------------------| -| types_section | variable | n/a | stores code section metadata | -| inputs | 1 byte | 0x00-0x7F | number of stack elements the code section consumes | -| outputs | 1 byte | 0x00-0x7F | number of stack elements the code section returns | -| max_stack_height | 2 bytes | 0x0000-0x03FF | maximum number of elements ever placed onto the operand stack by the code section | -| code_section | variable | n/a | arbitrary bytecode | -| container_section | variable | n/a | arbitrary EOF-formatted container | -| data_section | variable | n/a | arbitrary sequence of bytes | - -See [EIP-4750](./eip-4750.md) for more information on the type section content. +| name | length | value | description | +|--------------------|----------|---------------|------------------------------------------------------------------| +| types_section | variable | n/a | stores code section metadata | +| inputs | 1 byte | 0x00-0x7F | number of stack elements the code section consumes | +| outputs | 1 byte | 0x00-0x7F | number of stack elements the code section returns | +| max_stack_increase | 2 bytes | 0x0000-0x03FF | maximum increase of the operand stack height by the code section | +| code_section | variable | n/a | arbitrary bytecode | +| container_section | variable | n/a | arbitrary EOF-formatted container | +| data_section | variable | n/a | arbitrary sequence of bytes | **NOTE**: A special value of `outputs` being `0x80` is designated to denote non-returning functions as defined in a separate EIP. @@ -167,7 +165,7 @@ For an EOF contract: - Execution starts at the first byte of code section 0 - `CODESIZE`, `CODECOPY`, `EXTCODESIZE`, `EXTCODECOPY`, `EXTCODEHASH`, `GAS` are rejected by validation in EOF contracts, with no replacements - `CALL`, `DELEGATECALL`, `STATICCALL` are rejected by validation in EOF contracts, replacement instructions to be introduced in a separate EIP. -- `EXTDELEGATECALL` (`DELEGATECALL` replacement) from an EOF contract to a non-EOF contract (legacy contract, EOA, empty account) is disallowed, and it should fail in the same mode as if the call depth check failed. We allow legacy to EOF path for existing proxy contracts to be able to use EOF upgrades. +- `DELEGATECALL` (or any replacement instruction for EOF) from an EOF contract to a non-EOF contract (legacy contract, EOA, empty account) is disallowed, and it should fail in the same mode as if the call depth check failed. We allow legacy to EOF path for existing proxy contracts to be able to use EOF upgrades. For a legacy contract: @@ -222,7 +220,7 @@ We have considered different questions for the sections: - Streaming headers (i.e. `section_header, section_data, section_header, section_data, ...`) are used in some other formats (such as WebAssembly). They are handy for formats which are subject to editing (adding/removing sections). That is not a useful feature for EVM. One minor benefit applicable to our case is that they do not require a specific "header terminator". On the other hand they seem to play worse with code chunking / merkleization, as it is better to have all section headers in a single chunk. - Whether to have a header terminator or to encode `number_of_sections` or `total_size_of_headers`. Both raise the question of how large of a value these fields should be able to hold. A terminator byte seems to avoid the problem of choosing a size which is too small without any perceptible downside, so it is the path taken. -- (EOF1) Whether to encode section sizes as fixed 16-bit values or some kind of variable length field (e.g. LEB128). We have opted for fixed size, because it simplifies client implementations, and 16-bit seems enough, because of the currently exposed code size limit of 24576 bytes (see [EIP-170](./eip-170.md) and [EIP-3860](./eip-3860.md)). Should this be limiting in the future, a new EOF version could change the format. Besides simplifying client implementations, not using LEB128 also greatly simplifies on-chain parsing. +- (EOF1) Whether to encode section sizes as fixed 16-bit (32-bit for container section size) values or some kind of variable length field (e.g. LEB128). We have opted for fixed size. Should this be limiting in the future, a new EOF version could change the format. Besides simplifying client implementations, not using LEB128 also greatly simplifies on-chain parsing. - Whether or not to have more structure to the container header for all EOF versions to follow. In order to allow future formats optimized for chunking and merkleization (verkleization) it was decided to keep it generic and specify the structure only for a specific EOF version. ### Data-only contracts @@ -239,6 +237,10 @@ Imposing an EOF-validation time limit for the size of EOF containers provides a Given one of the main reasons for the limit is to avoid attack vectors on `JUMPDEST`-analysis, and EOF removes the need for `JUMPDEST`-analysis and introduces a cost structure for deploy-time analysis, in the future this limit could be increased or even lifted for EOF. +### `kind_data` could be `0x04` not `0xff` + +Putting the data section last as `0xff` has the advantage of aligning with the fact that it always comes last. We're avoiding a situation that a new section kind would need to go before the data section and break the section kind ordering. At the same time, data section being last is advantageous because it is the section which gets data appended to during contract deployment. + ## Backwards Compatibility This is a breaking change given that any code starting with `0xEF` was not deployable before (and resulted in exceptional abort if executed), but now some subset of such codes can be deployed and executed successfully. diff --git a/EIPS/eip-3607.md b/EIPS/eip-3607.md index 78ed1ee17a83aa..6d604006d60d27 100644 --- a/EIPS/eip-3607.md +++ b/EIPS/eip-3607.md @@ -41,7 +41,7 @@ A block containing such a transaction MUST be considered invalid. ## Rationale -We note that it was always the expected that a contract account's behaviour is constrained by the code in that contract -- which means that the account's funds should not suddenly be spendable by some private key. It was just implicitly assumed in the past that a 160 bit address length is enough to provide collision resistance, and thus that this case could never occur. In that sense, this EIP should be seen as a clarification of protocol behaviour in a previously undefined case rather than an explicit upgrade of consensus rules. +We note that it was always expected that a contract account's behaviour is constrained by the code in that contract -- which means that the account's funds should not suddenly be spendable by some private key. It was just implicitly assumed in the past that a 160 bit address length is enough to provide collision resistance, and thus that this case could never occur. In that sense, this EIP should be seen as a clarification of protocol behaviour in a previously undefined case rather than an explicit upgrade of consensus rules. This does not exclude all possible attack vectors, only the most serious one. Further possible attack vectors via address collisions between contracts and EOAs are: 1. An attacker can convince a user to send funds to an account before it is deployed. Some applications require this behaviour (e.g. state channels). diff --git a/EIPS/eip-3670.md b/EIPS/eip-3670.md index 23c2a4f3ab0f36..2e6d3115aec61c 100644 --- a/EIPS/eip-3670.md +++ b/EIPS/eip-3670.md @@ -4,7 +4,7 @@ title: EOF - Code Validation description: Validate EOF bytecode for correctness at the time of deployment. author: Alex Beregszaszi (@axic), Andrei Maiboroda (@gumb0), Paweł Bylica (@chfast) discussions-to: https://ethereum-magicians.org/t/eip-3670-eof-code-validation/6693 -status: Review +status: Stagnant type: Standards Track category: Core created: 2021-06-23 @@ -55,6 +55,12 @@ Allowing implicit zero immediate data for `PUSH` instructions introduces ineffic The deprecated instructions `CALLCODE` (0xf2) and `SELFDESTRUCT` (0xff) are removed from the `valid_opcodes` list to prevent their use in the future. +### BLOCKHASH instruction + +The `BLOCKHASH` instruction is well replaced by the system contract introduced in [EIP-2935](./eip-2935). +However, despite a replacement being introduced this opcode has not been deprecated. +This opcode will remain valid in EOF not to differentiate from legacy bytecode. + ## Backwards Compatibility This change poses no risk to backwards compatibility, as it is introduced at the same time EIP-3540 is. The validation does not cover legacy bytecode (code which is not EOF formatted). diff --git a/EIPS/eip-3855.md b/EIPS/eip-3855.md index 42034250ae8dd4..6f85bd73336de4 100644 --- a/EIPS/eip-3855.md +++ b/EIPS/eip-3855.md @@ -47,7 +47,7 @@ The `base` gas cost is used for instructions which place constant values onto th ## Backwards Compatibility -This EIP introduces a new opcode which did not exists previously. Already deployed contracts using this opcode could change their behaviour after this EIP. +This EIP introduces a new opcode which did not exist previously. Already deployed contracts using this opcode could change their behaviour after this EIP. ## Test Cases diff --git a/EIPS/eip-3860.md b/EIPS/eip-3860.md index 5f8151e19ad1c9..9ee005834d488e 100644 --- a/EIPS/eip-3860.md +++ b/EIPS/eip-3860.md @@ -100,7 +100,7 @@ We specified that initcode size limit violation for `CREATE`/`CREATE2` results i This EIP requires a "network upgrade", since it modifies consensus rules. -Already deployed contracts should not be effected, but certain transactions (with `initcode` beyond the proposed limit) would still be includable in a block, but result in an exceptional abort. +Already deployed contracts should not be affected, but certain transactions (with `initcode` beyond the proposed limit) would still be includable in a block, but result in an exceptional abort. ## Test Cases diff --git a/EIPS/eip-4.md b/EIPS/eip-4.md index 2973e03a8d8bcb..f3e3535f3f282e 100644 --- a/EIPS/eip-4.md +++ b/EIPS/eip-4.md @@ -17,7 +17,7 @@ The specification defines the layers and sets forth specific criteria for decidi # Motivation -Ethereum is a system involving a number of different standards. Some standards are absolute requirements for interoperability while others can be considered optional, giving implementors a choice of whether to support them. +Ethereum is a system involving a number of different standards. Some standards are absolute requirements for interoperability while others can be considered optional, giving implementers a choice of whether to support them. In order to have a EIP process which more closely reflects the interoperability requirements, it is necessary to categorize EIPs accordingly. Lower layers present considerably greater challenges in getting standards accepted and deployed. @@ -48,7 +48,7 @@ In a hard fork, structures that were invalid under the old rules become valid un # 2. Networking Layer -The networking layer specifies the Ethereum wire protocol (eth) and the Light Ethereum Subprotocol (les). RLPx is excluded and tracked in the [https://github.com/ethereum/devp2p devp2p repository]. +The networking layer specifies the Ethereum wire protocol (eth) and the Light Ethereum Subprotocol (les). RLPx is excluded and tracked in the [devp2p repository](https://github.com/ethereum/devp2p). Only a subset of subprotocols are required for basic node interoperability. Nodes can support further optional extensions. diff --git a/EIPS/eip-4200.md b/EIPS/eip-4200.md index 7c7a47caff97e2..b7f5ad59b1452c 100644 --- a/EIPS/eip-4200.md +++ b/EIPS/eip-4200.md @@ -157,7 +157,11 @@ This change poses no risk to backwards compatibility, as it is introduced at the ## Security Considerations -TBA +Adding new instructions with immediate arguments should be carefully considered when implementing the EOF container validation algorithm. + +Static relative jump execution does not require runtime check of the jump destination. It greatly reduces execution cost. Therefore the gas cost of the new instructions can also be significantly reduced. + +The `RJUMPV` instruction relative offset table can have up to 256 one-byte entries, so reading an offset cannot be a potential attack surface. ## Copyright diff --git a/EIPS/eip-4444.md b/EIPS/eip-4444.md index df543d454f1667..3a071bc94ed204 100644 --- a/EIPS/eip-4444.md +++ b/EIPS/eip-4444.md @@ -30,7 +30,7 @@ Finally, this change will result in less bandwidth usage on the network as clien Clients SHOULD NOT serve headers, block bodies, and receipts that are older than `HISTORY_PRUNE_EPOCHS` epochs on the p2p network. -Clients MAY locally prune headers, block bodies, and receipts that is older than `HISTORY_PRUNE_EPOCHS` epochs. +Clients MAY locally prune headers, block bodies, and receipts that are older than `HISTORY_PRUNE_EPOCHS` epochs. #### Bootstrapping and syncing @@ -76,7 +76,7 @@ In the second phase, history is pruned by default and the command line option is ### JSON-RPC changes -After this proposal is implemented, certain JSON-RPC endpoints (e.g. like `getBlockByHash`) won't be able to tell whether a given hash is invalid or just too old. Other endpoints like `getLogs` will simply no longer have the data the user is requesting. The way this regression should be handled by applications or clients is out-of-scope for this proposal. +After this proposal is implemented, certain JSON-RPC endpoints (e.g. like `getBlockByHash`) won't be able to tell whether a given hash is invalid or just outdated. Other endpoints like `getLogs` will simply no longer have the data the user is requesting. The way this regression should be handled by applications or clients is out-of-scope for this proposal. ## Security Considerations @@ -98,7 +98,7 @@ Furthermore, there is a risk that more dapps will rely on centralized services f ### Confusion with other proposals -Because there are a number of alternative proposals for reducing the execution client's footprint on disk, we've decided to enforce a specific pronouncination of the EIP. When pronouncing the EIP number, it **MUST** be pronounced EIP "four fours". All other pronounciations are incorrect. +Because there are a number of alternative proposals for reducing the execution client's footprint on disk, we've decided to enforce a specific pronunciation of the EIP. When pronouncing the EIP number, it **MUST** be pronounced EIP "four fours". All other pronunciation are incorrect. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-4750.md b/EIPS/eip-4750.md index 05e111d80e8ba5..a94327c096cd4b 100644 --- a/EIPS/eip-4750.md +++ b/EIPS/eip-4750.md @@ -4,7 +4,7 @@ title: EOF - Functions description: Individual sections for functions with `CALLF` and `RETF` instructions author: Andrei Maiboroda (@gumb0), Alex Beregszaszi (@axic), Paweł Bylica (@chfast) discussions-to: https://ethereum-magicians.org/t/eip-4750-eof-functions/8195 -status: Stagnant +status: Review type: Standards Track category: Core created: 2022-01-10 @@ -31,9 +31,9 @@ Furthermore, it aims to improve analysis opportunities by encoding the number of The type section of EOF containers must adhere to following requirements: -1. The section is comprised of a list of metadata where the metadata index in the type section corresponds to a code section index. Therefore, the type section size MUST be `n * 4` bytes, where `n` is the number of code sections. -2. Each metadata item has 3 attributes: a uint8 `inputs`, a uint8 `outputs`, and a uint16 `max_stack_height`. *Note:* This implies that there is a limit of 255 stack for the input and in the output. This is further restricted to 127 stack items, because the upper bit of both the input and output bytes are reserved for future use (`outputs == 0x80` is already used in EOF1 to denote non-returning functions, as introduced in a separate EIP). `max_stack_height` is further defined in [EIP-5450](./eip-5450.md). -3. The 0th code section MUST have 0 inputs and 0 outputs. +1. The section is a list of metadata where the metadata index in the type section corresponds to a code section index. Therefore, the type section size MUST be `n * 4` bytes, where `n` is the number of code sections. +2. Each metadata item has 3 attributes: a uint8 `inputs`, a uint8 `outputs`, and a uint16 `max_stack_increase`. *Note:* This implies that there is a limit of 255 stack for the input and in the output. This is further restricted to 127 stack items, because the upper bit of both the input and output bytes are reserved for future use (`outputs == 0x80` is already used in EOF1 to denote non-returning functions, as introduced in a separate EIP). `max_stack_increase` is further defined in [EIP-5450](./eip-5450.md). +3. The 0th code section MUST have 0 inputs and be non-returning. Refer to [EIP-3540](./eip-3540.md) to see the full structure of a well-formed EOF bytecode. @@ -43,7 +43,7 @@ A return stack is introduced, separate from the operand stack. It is a stack of Note: Implementations are free to choose particular encoding for a stack item. In the specification below we assume that representation is two unsigned integers: `code_section_index`, `offset`. -The return stack is limited to a maximum 1024 items. +The return stack is limited to a maximum of `1024` items. Additionally, EVM keeps track of the index of currently executing section - `current_section_index`. @@ -60,7 +60,7 @@ First we define several helper values: - `type[i].inputs = type_section_contents[i * 4]` - number of inputs of ith code section - `type[i].outputs = type_section_contents[i * 4 + 1]` - number of outputs of ith code section -- `type[i].max_stack_height = type_section_contents[i * 4 + 2:i * 4 + 4]` - maximum operand stack height of ith code section +- `type[i].max_stack_increase = type_section_contents[i * 4 + 2:i * 4 + 4]` - maximum operand stack height increase of ith code section If the code is valid EOF1, the following execution rules apply: @@ -68,9 +68,9 @@ If the code is valid EOF1, the following execution rules apply: 1. Has one immediate argument,`target_section_index`, encoded as a 16-bit unsigned big-endian value. 2. *Note:* EOF validation [EIP-5450](./eip-5450.md) guarantees that operand stack has enough items to use as callee's inputs. -3. If operand stack size exceeds `1024 - type[target_section_index].max_stack_height + type[target_section_index].inputs` (i.e. if the called function may exceed the global stack height limit), execution results in exceptional halt. This also guarantees that the stack height after the call is within the limits. +3. If operand stack size exceeds `1024 - type[target_section_index].max_stack_increase` (i.e. if the called function may exceed the global stack height limit), execution results in exceptional halt. This also guarantees that the stack height after the call is within the limits. 4. If return stack already has `1024` items, execution results in exceptional halt. -5. Charges 5 gas. +5. Charges `5` gas. 6. Pops nothing and pushes nothing to operand stack. 7. Pushes to return stack an item: @@ -88,7 +88,7 @@ If the code is valid EOF1, the following execution rules apply: 1. Does not have immediate arguments. 2. *Note:* EOF validation [EIP-5450](./eip-5450.md) guarantees that operand stack has exact number of items to use as outputs. -3. Charges 3 gas. +3. Charges `3` gas. 4. Pops nothing and pushes nothing to operand stack. 5. Pops an item from return stack and sets `current_section_index` and `PC` to values from this item. @@ -98,7 +98,7 @@ If the code is valid EOF1, the following execution rules apply: In addition to container format validation rules above, we extend code section validation rules (as defined in [EIP-3670](./eip-3670.md)). -1. Code validation rules of EIP-3670 are applied to every code section. +1. Code validation rules of [EIP-3670](./eip-3670.md) are applied to every code section. 2. Code section is invalid in case an immediate argument of any `CALLF` is greater than or equal to the total number of code sections. 3. `RJUMP`, `RJUMPI` and `RJUMPV` immediate argument value (jump destination relative offset) validation: 1. Code section is invalid in case offset points to a position outside of section bounds. @@ -117,7 +117,7 @@ Dynamic jump instructions `JUMP` (`0x56`) and `JUMPI` (`0x57`) are invalid and t ### Execution -1. Execution starts at the first byte of the 0th code section, and PC is set to 0. +1. Execution starts at the first byte of the 0th code section, and `PC` is set to `0`. 2. Return stack is initialized empty. 3. Stack underflow check is not performed anymore. *Note:* EOF validation [EIP-5450](./eip-5450.md) guarantees that it cannot happen at run-time. 3. Stack overflow check is not performed anymore, except during `CALLF` as specified above. @@ -133,6 +133,17 @@ Alternative logic for `RETF` in the top frame could be to allow it during code v This has been superseded with the validation rule of top frame (0th code section) being non-returning (non-returning sections introduced in a separate EIP), because validating non-returning status of functions is valuable by itself for other reasons. Therefore all considerations of runtime behavior of `RETF` in the top frame were obsoleted. +### "Minimal" function type + +Let's consider a trivial function with single instruction `RETF`. +Such function have the "minimal" type of `inputs = 0, outputs = 0`. +However, any other type like `inputs = k, outputs = k` is also valid for such function. +It has been considered to enforce usage of the "minimal" type for all functions. +This requires additional validation rule that checks if any instruction in the function accesses the bottom stack operand. +This rule can be obeyed by compilers, but causes quite significant annoyance. +On the other hand, it provides close to zero benefits for the EVM implementations. +In the end, it has been decided that this is not enforced. + ### Code section limit and instruction size The number of code sections is limited to 1024. This requires 2-byte immediate for `CALLF` and leaves room for increasing the limit in the future. The 256 limit (1-byte immediate) was discussed and concerns were raised that it might not be sufficient. @@ -143,7 +154,7 @@ Instead of deprecating `JUMPDEST` we repurpose it as `NOP` instruction, because ### Deprecating `JUMPDEST` analysis -The purpose of `JUMPDEST` analysis was to find in code the valid `JUMPDEST` bytes that do not happen to be inside `PUSH` immediate data. Only dynamic jump instructions (`JUMP`, `JUMPI`) required destination to be `JUMPDEST` instruction. Relative static jumps (`RJUMP` and `RJUMPI`) do not have this requirement and are validated once at deploy-time EOF instruction validation. Therefore, without dynamic jump instructions, `JUMPDEST` analysis is not required. +The purpose of `JUMPDEST` analysis was to find in code the valid `JUMPDEST` bytes that do not happen to be inside `PUSH` immediate data. Only dynamic jump instructions (`JUMP`, `JUMPI`) required destination to be `JUMPDEST` instruction. Relative static jumps (`RJUMP`, `RJUMPI` and `RJUMPV`) do not have this requirement and are validated once at deploy-time during EOF instructions validation. Therefore, without dynamic jump instructions, `JUMPDEST` analysis is not required. ## Backwards Compatibility @@ -153,7 +164,9 @@ The new execution state and multi-section control flow pose no risk to backwards ## Security Considerations -TBA +The gas cost of introduced instructions reflects the need to manipulate return stack entries and jumping to proper code section offset in memory when interpreting the bytecode. + +These new instructions need to be carefully considered during implementation of the EOF container validation algorithm. ## Copyright diff --git a/EIPS/eip-4760.md b/EIPS/eip-4760.md index aafcbfd365d511..2a8e779082cb92 100644 --- a/EIPS/eip-4760.md +++ b/EIPS/eip-4760.md @@ -11,7 +11,7 @@ created: 2022-02-03 --- ## Abstract -This EIP renames the `SELFDESCRUCT` opcode to `SENDALL`, and replaces its functionality. The new functionality will be only to send all Ether in the account to the caller. +This EIP renames the `SELFDESTRUCT` opcode to `SENDALL`, and replaces its functionality. The new functionality will be only to send all Ether in the account to the caller. In order to give apps more warning even if their developers are completely unaware of the EIP process, this version will exponentially increase the gas costs of the opcode, so any developer has time to see this change and react by implementing a version of their contract that does not rely on `SELFDESTRUCT` . @@ -53,11 +53,13 @@ Few applications are affected by this change. The only use that breaks is where ## Security Considerations The following applications of `SELFDESTRUCT` will be broken and applications that use it in this way are not safe anymore: + 1. Any use where `SELFDESTRUCT` is used to burn non-ETH token balances, such as ERC20, inside a contract. We do not know of any such use (since it can easily be done by sending to a burn address this seems an unlikely way to use `SELFDESTRUCT`) 2. Where `CREATE2` is used to redeploy a contract in the same place. There are two ways in which this can fail: - - The destruction prevents the contract from being used outside of a certain context. For example, the contract allows anyone to withdraw funds, but `SELFDESTRUCT` is used at the end of an operation to prevent others from doing this. This type of operation can easily be modified to not depend on `SELFDESTRUCT`. - - The `SELFDESTRUCT` operation is used in order to make a contract upgradable. This is not supported anymore and delegates should be used. + + * The destruction prevents the contract from being used outside of a certain context. For example, the contract allows anyone to withdraw funds, but `SELFDESTRUCT` is used at the end of an operation to prevent others from doing this. This type of operation can easily be modified to not depend on `SELFDESTRUCT`. + * The `SELFDESTRUCT` operation is used in order to make a contract upgradable. This is not supported anymore and delegates should be used. ## Copyright -Copyright and related rights waived via [CC0](../LICENSE.md). \ No newline at end of file +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/EIPS/eip-4803.md b/EIPS/eip-4803.md index 9ce1e4cf819876..2d2245e89e0fef 100644 --- a/EIPS/eip-4803.md +++ b/EIPS/eip-4803.md @@ -4,7 +4,7 @@ title: Limit transaction gas to a maximum of 2^63-1 description: Valid transactions must have a reasonable gas limit author: Alex Beregszaszi (@axic) discussions-to: https://ethereum-magicians.org/t/eip-4803-limit-transaction-gas-to-a-maximum-of-2-63-1/8296 -status: Review +status: Stagnant type: Standards Track category: Core created: 2022-02-02 diff --git a/EIPS/eip-5.md b/EIPS/eip-5.md index 5c875111d0e9b0..8af34613a85622 100644 --- a/EIPS/eip-5.md +++ b/EIPS/eip-5.md @@ -39,7 +39,7 @@ After the call, the `MSIZE` opcode should return the size the memory was actuall ### Motivation -In general, it is good practise to reserve a certain memory area for the output of a call, +In general, it is good practice to reserve a certain memory area for the output of a call, because letting a subroutine write to arbitrary areas in memory might be dangerous. On the other hand, it is often hard to know the output size of a call prior to performing the call: The data could be in the storage of another contract which is generally inaccessible and diff --git a/EIPS/eip-5003.md b/EIPS/eip-5003.md index d42d650dd1276d..995c4a235a4c68 100644 --- a/EIPS/eip-5003.md +++ b/EIPS/eip-5003.md @@ -4,11 +4,12 @@ title: Insert Code into EOAs with AUTHUSURP description: Allow migrating away from ECDSA by deploying code in place of an externally owned account. author: Dan Finlay (@danfinlay), Sam Wilson (@SamWilsn) discussions-to: https://ethereum-magicians.org/t/eip-5003-auth-usurp-publishing-code-at-an-eoa-address/8979 -status: Stagnant +status: Withdrawn type: Standards Track category: Core created: 2022-03-26 requires: 3074, 3607 +withdrawal-reason: Superseded by EIP-7702. --- ## Abstract diff --git a/EIPS/eip-5081.md b/EIPS/eip-5081.md index 6b6ad04657c9dc..bbf80e25ca63ec 100644 --- a/EIPS/eip-5081.md +++ b/EIPS/eip-5081.md @@ -1,6 +1,6 @@ --- eip: 5081 -title: Expirable Trainsaction +title: Expirable Transaction description: This EIP adds a new transaction type of that includes expiration with a blocknum author: Zainan Victor Zhou (@xinbenlv), Nick Johnson (@Arachnid), Konrad Feldmeier discussions-to: https://ethereum-magicians.org/t/eip-5081-expirable-transaction/9208 @@ -22,7 +22,7 @@ A common resolution is for the user to submit the transaction again with the sam That previous `tx0` can theoretically be included in any time in the future unless a `tx` with the exact same nonce is already executed. When network is congested, gas price are high, for critical transactions user might try gas price that is much higher than an average day. -This cause the `tx0` choose might be very easy to executed in the average day. +This cause the `tx0` choice might be very easy to executed in the average day. If user already uses a `tx1` with different nonce or from another account to execute the intended transaction, there is currently no clean way to cancel it, @@ -74,7 +74,7 @@ TODO ## Security Considerations 1. If `current_block_num` is available, client MUST drop and stop propagating/broadcasting any transactions that has a -`transacton_type == TX_TYPE` AND `current_block_num > expire_by` +`transaction_type == TX_TYPE` AND `current_block_num > expire_by` 2. It is suggested but not required that a `currentBlockNum` SHOULD be made available to client. Any client doing PoW calculation on blocks expire tx or propagating such are essentially penalized for wasting of work, mitigating possible denial of service attack. @@ -82,7 +82,7 @@ TODO `gossip_ttl` in unit of block_num as a safe net so that it only propagate a tx if `current_block_num + gossip_ttl <= expire_by`. Backward compatibility: for nodes that doesn't have `current_block_num` or `gossip_ttl` available, -they should be presume to be `0`. +they should be presumed to be `0`. 4. It is suggested by not required that any propagating client SHOULD properly deduct the `gossip_ttl` based on the network environment it sees fit. diff --git a/EIPS/eip-5450.md b/EIPS/eip-5450.md index e546311640b6c8..91a581f754bdd3 100644 --- a/EIPS/eip-5450.md +++ b/EIPS/eip-5450.md @@ -33,10 +33,10 @@ The operand stack validation provides several benefits: It also has some disadvantages: -- adds constraints to the code structure (similar to JVM, CPython bytecode, WebAssembly and others); however, these constraints can be lifted in a backward-compatible manner if they are shown to be user-unfriendly, +- adds constraints to the code structure (similar to JVM, CPython bytecode, WebAssembly, SPIR-V and others); however, these constraints can be lifted in a backward-compatible manner if they are shown to be user-unfriendly, - it is natural to implement stack validation as a second validation pass; however, it is not strictly required and validation's computational and space complexity remains linear in any implementation variant. -The guarantees created by these validation rules also improve the feasibility of Ahead-Of-Time and Just-In-Time compilation of EVM code. Single pass transpilation passes can be safely executed with the code validation and advanced stack/register handling can be applied with the stack height validations. While not as impactful to a mainnet validator node that is bound mostly by storage state sizes, these can significantly speed up witness validation and other non-mainnet use cases. +The guarantees created by these validation rules also improve the feasibility of Ahead-Of-Time and Just-In-Time compilation of EVM code. Single pass transpilation passes can be safely executed with the code validation and advanced stack/register handling can be applied with the stack height validations. While not as impactful to a Mainnet validator node that is bound mostly by storage state sizes, these can significantly speed up witness validation and other non-Mainnet use cases. ## Specification @@ -59,9 +59,9 @@ In the second validation phase control-flow analysis is performed on the code. *Terminating instructions* refers to the instructions either: - ending function execution: `RETF`, `JUMPF`, or -- ending call frame execution: `STOP`, `RETURN`, `RETURNCONTRACT`, `REVERT`, `INVALID`. +- ending call frame execution: `STOP`, `RETURN`, `RETURNCODE`, `REVERT`, `INVALID`. -*note: `JUMPF` and `RETURNCONTRACT` are introduced in separate EIPs.* +*note: `JUMPF` and `RETURNCODE` are introduced in separate EIPs.* *Forward jump* refers to any of `RJUMP`/`RJUMPI`/`RJUMPV` instruction with relative offset greater than or equal to 0. *Backwards jump* refers to any of `RJUMP`/`RJUMPI`/`RJUMPV` instruction with relative offset less than 0, including jumps to the same jump instruction. @@ -72,7 +72,7 @@ The first instruction's recorded stack height bounds are initialized to be equal For each instruction: 1. **Check** if this instruction has recorded stack height bounds. If it does not, it means it was neither referenced by previous forward jump, nor is part of sequential instruction flow, and this code fails validation. - - It is a prerequisite to validation algorithm, and code generators are required to order code basic blocks in a way that no block is referenced only by backwards jump. + - It is a prerequisite to validation algorithm, and code generators are required to order code basic blocks in a way that no block is referenced only by backwards jump. Any program can satisfy this requirement by ordering code basic blocks by the reverse postorder. 2. Determine the effect the instruction has on the operand stack: 1. **Check** if the recorded stack height bounds satisfy the instruction requirements. Specifically: - for `CALLF` instruction the recorded stack height lower bound must be at least the number of inputs of the called function according to its type defined in the type section, @@ -81,26 +81,28 @@ For each instruction: - for `JUMPF` into non-returning function the recorded stack height lower bound must be at least the number of inputs of the target function according to its type defined in the type section, - for any other instruction the recorded stack height lower bound must be at least the number of inputs required by instruction, - there is no additional check for terminating instructions other than `RETF` and `JUMPF`, this implies that extra items left on stack at instruction ending EVM execution are allowed. - 2. For `CALLF` and `JUMPF` **check** for possible stack overflow: if recorded stack height upper bound is greater than `1024 - types[target_section_index].max_stack_height + types[target_section_index].inputs`, validation fails. + 2. For `CALLF` and `JUMPF` **check** for possible stack overflow: if recorded stack height upper bound is greater than `1024 - types[target_section_index].max_stack_increase`, validation fails. 3. Compute new stack height bounds after the instruction execution. Upper and lower bound are updated by the same value: - after `CALLF` stack height bounds are adjusted by adding `types[target_section_index].outputs - types[target_section_index].inputs`, - after any other non-terminating instruction stack height bounds are adjusted by subtracting the number of instruction inputs and adding the number of instruction outputs, - terminating instructions do not need to update stack height bounds. 3. Determine the list of successor instructions that can follow the current instructions: - 1. The next instruction for all instructions other than terminating instructions and unconditional jump. - 2. All targets of a conditional or unconditional jump. + 1. The next instruction if the current instruction is not a terminating instruction nor unconditional jump (`RJUMP`). + 2. All the current instruction targets if the current instruction is a conditional (`RJUMPI` or `RJUMPV`) or unconditional jump (`RJUMP`). 4. For each successor instruction: 1. **Check** if the instruction is present in the code (i.e. execution must not "fall off" the code). 2. If the successor is reached via forwards jump or sequential flow from previous instruction: - 1. If the instruction does not have stack height bounds recorded (visited for the first time), record the instruction stack height bound as the value computed in 2.3. - 2. Otherwise instruction was already visited (by previously seen forward jump). Update this instruction's recorded stack height bounds so that they contain the bounds computed in 2.3, i.e. `target_stack_min = min(target_stack_min, current_stack_min)` and `target_stack_max = max(target_stack_max, current_stack_max)`, where `(target_stack_min, target_stack_max)` are successor bounds and `(current_stack_min, current_stack_max)` are bounds computed in 2.3. + 1. If the instruction does not have stack height bounds recorded (being visited for the first time), record the instruction stack height bound as the value computed in 2.3. + 2. Otherwise, instruction has been already visited (by previously seen forward jump). Update this instruction's recorded stack height bounds so that they contain the bounds computed in 2.3, i.e. `target_stack_min = min(target_stack_min, current_stack_min)` and `target_stack_max = max(target_stack_max, current_stack_max)`, where `(target_stack_min, target_stack_max)` are successor bounds and `(current_stack_min, current_stack_max)` are bounds computed in 2.3. 3. If the successor is reached via backwards jump, **check** if the recorded stack height bounds equal the value computed in 2.3. Validation fails if they are not equal, i.e. we see backwards jump to a different stack height. -After all instructions are visited, determine the function maximum operand stack height: +After all instructions are visited, determine the function maximum operand stack height increase: -1. Compute the maximum stack height as the maximum of all recorded stack height upper bounds. -2. **Check** if the maximum stack height does not exceed the limit of 1023 (`0x3FF`). -3. **Check** if the maximum stack height matches the corresponding code section's `max_stack_height` within the type section. +1. Compute the maximum stack height `max_stack_height` as the maximum of all recorded stack height upper bounds. +2. Compute the maximum stack height increase `max_stack_increase` as `max_stack_height - type[current_section_index].inputs`. +3. **Check** if the maximum stack height increase `max_stack_increase` matches the value corresponding code section's within the type section: `types[current_section_index].max_stack_increase`. + +*Note: Although we check only that `max_stack_increase` matches the type section definition, which guarantees that it does not exceed 1023 by EOF header definition, it is also guaranteed that `max_stack_height` does not exceed 1024, because otherwise validation of `CALLF` and `JUMPF` into this section would fail at operand stack overflow check. Every section is required to have `CALLF` or `JUMPF` targeting it, except 0th section (non-reachable sections are not allowed). 0th section is required to have 0 inputs, which implies `max_stack_increase` equals `max_stack_height`.* The computational and space complexity of this pass is *O(len(code))*. Each instruction is visited at most once. @@ -133,7 +135,7 @@ The operand stack validation algorithm rejects any code having any unreachable i ### Clean stack upon termination It is currently required that the operand stack is empty (in the current function context) after the `RETF` instruction. -Otherwise, the `RETF` semantic would be more complicated. For `n` function outputs and `s` the stack height at `RETF` the EVM must erase `s-n` non-top stack items and move the `n` stack items to the place of erased ones. Cost of such operation may be relatively cheap but is not constant. +Otherwise, the `RETF` semantic would be more complicated. For `n` function outputs and `s` the stack height at `RETF` the EVM would have to erase `s-n` non-top stack items and move the `n` stack items to the place of erased ones. Cost of such operation may be relatively cheap but is not constant. However, lifting the requirement and modifying the `RETF` semantic as described above is backward compatible and can be easily introduced in the future. @@ -143,7 +145,7 @@ Originally another variant of stack validation was proposed, where instead of li The advantage of this variant would be somewhat simpler algorithm (we would not need to track stack height bounds, but only a single stack height value for each instruction) and no extra requirement for ordering of code basic blocks (see below). -However compiler teams opposed to such restrictive stack height requirements. One prominent pattern used by compilers which wouldn't be possible is jumping to terminating helpers (code blocks ending with `RETURN` or `REVERT`) from different stack heights. This is common for example for a series of `assert` statements, each one compiled to a `RJUMPI` into a shared terminating helper. Enforcing constant stack requirement would mean that before jumping to such helper, extra items on the stack have to be popped, and this noticeably increases code size and consumed gas, and would defeat the purpose of extracting these common terminating sequences into a helper. +However, compiler teams opposed to such restrictive stack height requirements. One prominent pattern used by compilers which wouldn't be possible is jumping to terminating helpers (code blocks ending with `RETURN` or `REVERT`) from different stack heights. This is common for example for a series of `assert` statements, each one compiled to a `RJUMPI` into a shared terminating helper. Enforcing constant stack requirement would mean that before jumping to such helper, extra items on the stack have to be popped, and this noticeably increases code size and consumed gas, and would defeat the purpose of extracting these common terminating sequences into a helper. ### Ordering of basic blocks @@ -151,6 +153,8 @@ The prerequisite to stack validation algorithm is ordering of code basic blocks This is required to make it possible to examine each instruction in one linear pass over the code section. Forward pass over the code section allows for the algorithm to "expand" each forward jump target's stack height bounds and still keep the complexity linear. Trying to do jump target stack bounds expansion while scanning the code in the breadth-first-search manner would require to re-examine entire code path after its stack height bounds are expanded, which would result in quadratic complexity. +This requirement is not unique to EOF but also present is some low-level IRs like SPIR-V and LLVM MIR. + ## Backwards Compatibility This change requires a "network upgrade," since it modifies consensus rules. @@ -159,7 +163,7 @@ It poses no risk to backwards compatibility, as it is introduced only for EOF1 c ## Security Considerations -Needs discussion. +As mentioned above, the proposed validation algorithm has linear computational and space complexity and its cost is covered by the transaction data costs [EIP-2028](./eip-2028). ## Copyright diff --git a/EIPS/eip-5593.md b/EIPS/eip-5593.md index 49df3983be2e30..ad8ef039679c5d 100644 --- a/EIPS/eip-5593.md +++ b/EIPS/eip-5593.md @@ -63,7 +63,7 @@ Wallet extensions SHOULD consider adding a "developer mode" toggle via a UX so t - Top level `https://b.com` with `