From 656aeda526d67da8f2dd06291465330c354cf777 Mon Sep 17 00:00:00 2001 From: Ronan Sandford Date: Fri, 24 May 2019 00:33:26 +0200 Subject: [PATCH 1/4] New Opcode to check if a chainID is part of the history of chainIDs (#1959) --- EIPS/eip-1959.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 EIPS/eip-1959.md diff --git a/EIPS/eip-1959.md b/EIPS/eip-1959.md new file mode 100644 index 00000000000000..40af70b401ca76 --- /dev/null +++ b/EIPS/eip-1959.md @@ -0,0 +1,79 @@ +--- +eip: 1959 +title: New Opcode to check if a chainID is part of the history of chainIDs +author: Ronan Sandford (@wighawag) +category: Core +type: Standards Track +discussions-to: https://ethereum-magicians.org/t/eip-1959-valid-chainid-opcode/3170 +status: Draft +created: 2019-04-20 +requires: 155 +--- + + +## Simple Summary +To protect off-chain messages from being reused across different chain, a mechanism need to be given to smart contract to only accept messages for that chain. Since a chain can change its chainID, the mechanism should consider old chainID valid. + +## Abstract +This EIP adds an opcode that returns whether the specific number passed in has been a valid chainID (EIP-155 unique identifier) in the history of the chain (including the current chainID). + +## Motivation +[EIP-155](https://eips.ethereum.org/EIPS/eip-155) proposes to use the chain ID to prevent replay attacks between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling signatures, especially for Layer 2 signature schemes using [EIP-712](https://eips.ethereum.org/EIPS/eip-712). + +[EIP-1344](https://eips.ethereum.org/EIPS/eip-1344) 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. + +## Specification +Adds a new opcode ```VALID_CHAINID``` at 0x46, which uses 1 stack argument : a 32 bytes value that represent the chainID to test. It will push ```0x1``` onto the stack if the uint256 value is part of the history (since genesis) of chainIDs of that chain, ```0x0``` otherwise. + +The operation costs `G_blockhash` to execute. + +The cost of the operation might need to be adjusted later as the number of chainID in the history of the chain grows. + +Note though that the alternative to keep track of old chainID is to implement a smart contract based caching solution as EIP-1344 proposes comes with an overall higher gas cost. As such the gas cost is simply a necessary cost for the feature. + +## Rationale +The only approach available today is to specify the chain ID at compile time. Using this approach will result in problems after a contentious hardfork as the contract can't accept message signed with a new chainID. + +The approach proposed by EIP-1344 is to give access to the latest chainID. This is in itself not sufficient and pose the opposite of the problem mentioned above since as soon as a hardfork that change the chainID happens, every L2 messages signed as per [EIP-712](https://eips.ethereum.org/EIPS/eip-712) (with the previous chainID) will fails to be accepted by the contracts after the fork. + +That's why in the rationale of EIP-1344 it is mentioned that users need to implement/use a mechanism to verify the validity of past chainID via a trustless cache implemented via smart contract. + +While this works (except for a temporary gap where the immediately previous chainID is not considered valid), this is actually a required procedure for all contracts that want to accept L2 messages since without it, messages signed before an hardfork that updated the chainID would be rejected. In other words, EIP-1344 expose such risk and it is easy for contract to not consider it by simply checking ```chainID == CHAIN_ID()``` without considering past chainIDs. + +Indeed letting contracts access the latest chainID for L2 message verification is dangerous. The latest chainID is only the tip of the chainID history. As a changing value, the latest chainID is thus not appropriate to ensure the validity of L2 messages. + +Users signing off-chain messages expect their messages to be valid from the time of signing and do not expect these message to be affected by a future hardfork. If the contract use the latest chainID as is for verification, the messages would be invalid as soon as a hardfork that update the chainID happens. For some applications, this will require users to resubmit a new message (think meta transaction), causing them potential loss (or some inconvenience during the hardfork transition), but for some other applications (think state channel) the whole off-chain state become inaccessible, resulting in potentially disastrous situations. + +In other words, we should consider all off-chain messages (with valid chainID) as part of the chain's offchain state. The opcode proposed here, offer smart contracts a simple and safe method to ensure that the offchain state stay valid across fork. + +As for replay protection, the idea of considering all of the off-chain messages signed with valid chainID as part of the chain's offchain-state means that all of these off-chain messages can be reused on the different forks which share a common chainID history (up to where they differ). This is actually an important feature since as mentioned, users expect their signed messages to be valid from the time of signing. From that time onwards these messages should be considered as part of the chain's offchain state. A hardfork should not thus render them invalid. This is similar to how the previous on-chain state is shared between 2 hardforks. + +The wallets will make sure that at any time, a signing message request use the latest chainID of the chain being used. This prevent replay attack onto chain that have different chainID histories (they would not have the same latest chainID). + +Now it is argued in the [EIP1344 discussion](https://ethereum-magicians.org/t/eip-1344-add-chain-id-opcode/1131) that when a contentious hardfork happen and one side of the fork decide to not update its chainID, that side of the chain would be vulnerable to replays since users will keep signing with a chainID that is also valid in the chain that forked. An issue also present in EIP-1344. + +This is simply a natural consequence of using chainID as the only anti-replay information for L2 messages. But this can indeed be an issue if the hardfork is created by a small minority. In that case if the majority ignore the fork and do not update its chainID, then all new message from the majority chain (until they update their chainID) can be replayed on the minority-led hardfork since the majority's current chainID is also part of the minority-led fork's chainID history. + +To fix this, every message could specify the block number representing the time it was signed. The contract could then verify that chainID specified as part of that message was valid at that particular block. + + +While EIP-1344 can't do that accurately as the caching system might leave a gap, this proposal can solve it if it is modified to return the blockNumber at which a chainID become invalid. Unfortunately, this would be easy for contracts to not perform that check. And since it suffice of only one important applications to not follow this procedure to put the minority-led fork at a disadvantage, this would fail to achieve the desired goal of protecting the minority-led fork from replay. + +Since a minority-led fork ignored by the majority means that the majority will not keep track of the messages to be submitted (state channel, ...), if such fork get traction later, this would be at the expense of majority users who were not aware of it. As such this proposal assume that minority-led fork will not get traction later and thus do not require to be protected. + +## Test Cases +TBD + +## Implementation +TBD + +## Backwards Compatibility +This EIP is fully backwards compatible with all chains which implement EIP-155 chain ID domain separator for transaction signing. Existing contract are not affected. + +Similarly to EIP-1344, it might be beneficial to update EIP-712 (still in Draft) to deal with chainID separately from the domain separator. Indeed since chainID is expected to change, if the domain separator include chainID, it would have to be dynamically computed. A caching mechanism could be used by smart contract instead though. + +## References +This was previously suggested as part of [EIP-1344 discussion](https://ethereum-magicians.org/t/eip-1344-add-chain-id-opcode/1131/39). + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file From cef55f5cb9de4c9d1317cb28c0710194ad7a30d9 Mon Sep 17 00:00:00 2001 From: Ronan Sandford Date: Fri, 24 May 2019 00:38:29 +0200 Subject: [PATCH 2/4] Automatically merged updates to draft EIP(s) 1679 (#2055) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 7b29f74b76aed7..0021feaae2663a 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -48,6 +48,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - [EIP-1829](https://eips.ethereum.org/EIPS/eip-1829): Precompile for Elliptic Curve Linear Combinations - [EIP-1884](https://eips.ethereum.org/EIPS/eip-1884): Repricing for trie-size-dependent opcodes - [EIP-1930](https://eips.ethereum.org/EIPS/eip-1930): CALLs with strict gas semantic. Revert if not enough gas available. +- [EIP-1959](https://eips.ethereum.org/EIPS/eip-1959): New Opcode to check if a chainID is part of the history of chainIDs - [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028): Calldata gas cost reduction - [EIP-2046](https://eips.ethereum.org/EIPS/eip-2046): Reduced gas cost for static calls made to precompiles From d7db470b40947f98fd6cc0c9e4826007124d89e2 Mon Sep 17 00:00:00 2001 From: Ronan Sandford Date: Fri, 24 May 2019 00:43:43 +0200 Subject: [PATCH 3/4] Copyright 107 (#2068) * add copyrights for 107 * use github username --- EIPS/eip-107.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-107.md b/EIPS/eip-107.md index 897feb804b6f96..67caa48d96d459 100644 --- a/EIPS/eip-107.md +++ b/EIPS/eip-107.md @@ -1,7 +1,7 @@ --- eip: 107 title: safe "eth_sendTransaction" authorization via html popup -author: Ronan Sandford +author: Ronan Sandford (@wighawag) created: 2016-06-05 status: Draft type: Standards Track @@ -612,3 +612,6 @@ That's it. ``` +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From dbf67d4f993d25053de8f0423eba8f5e6a05c0aa Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Fri, 24 May 2019 03:02:34 -0400 Subject: [PATCH 4/4] Automatically merged updates to draft EIP(s) 1155 (#2074) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 7dccdcdc2ae497..c736f9bf8f84e4 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -44,7 +44,7 @@ pragma solidity ^0.5.8; interface ERC1155 /* is ERC165 */ { /** @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). - The `_operator` argument MUST be msg.sender. + The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). The `_from` argument MUST be the address of the holder whose balance is decreased. The `_to` argument MUST be the address of the recipient whose balance is increased. The `_id` argument MUST be the token type being transferred. @@ -56,7 +56,7 @@ interface ERC1155 /* is ERC165 */ { /** @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). - The `_operator` argument MUST be msg.sender. + The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). The `_from` argument MUST be the address of the holder whose balance is decreased. The `_to` argument MUST be the address of the recipient whose balance is increased. The `_ids` argument MUST be the list of tokens being transferred. @@ -242,7 +242,8 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op * Forwarding should be considered acceptance and then initiating a new `safeTransferFrom` or `safeBatchTransferFrom` in a new context. - The prescribed keccak256 acceptance value magic for the receiver hook being called MUST be returned after forwarding is successful. * The `_data` argument MAY be re-purposed for the new context. -* If forwarding unexpectedly fails the transaction MUST be reverted. +* If forwarding fails the transaction MAY be reverted. + - If the contract logic wishes to keep the ownership of the token(s) itself in this case it MAY do so. #### Rules @@ -269,7 +270,7 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op **_TransferSingle and TransferBatch event rules:_** * `TransferSingle` SHOULD be used to indicate a single balance transfer has occurred between a `_from` and `_to` pair. - It MAY be emitted multiple times to indicate multiple balance changes in the transaction, but note that `TransferBatch` is designed for this to reduce gas consumption. - - The `_operator` argument MUST be msg.sender. + - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). - The `_from` argument MUST be the address of the holder whose balance is decreased. - The `_to` argument MUST be the address of the recipient whose balance is increased. - The `_id` argument MUST be the token type being transferred. @@ -278,7 +279,7 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). * `TransferBatch` SHOULD be used to indicate multiple balance transfers have occurred between a `_from` and `_to` pair. - It MAY be emitted with a single element in the list to indicate a singular balance change in the transaction, but note that `TransferSingle` is designed for this to reduce gas consumption. - - The `_operator` argument MUST be msg.sender. + - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). - The `_from` argument MUST be the address of the holder whose balance is decreased for each entry pair in `_ids` and `_values`. - The `_to` argument MUST be the address of the recipient whose balance is increased for each entry pair in `_ids` and `_values`. - The `_ids` array argument MUST contain the ids of the tokens being transferred. @@ -292,7 +293,7 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op - To make sure event order is correct in the case of valid re-entry (e.g. if a receiver contract forwards tokens on receipt) state balance and events balance MUST match before calling an external contract. **_onERC1155Received rules:_** -* The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). +- The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). * The `_from` argument MUST be the address of the holder whose balance is decreased. - `_from` MUST be 0x0 for a mint. * The `_id` argument MUST be the token type being transferred. @@ -309,7 +310,7 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op - The set of all calls to `onERC1155Received` and `onERC1155BatchReceived` describes all balance changes that occurred during the transaction in the order submitted. **_onERC1155BatchReceived rules:_** -* The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). +- The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). * The `_from` argument MUST be the address of the holder whose balance is decreased. - `_from` MUST be 0x0 for a mint. * The `_ids` argument MUST be the list of tokens being transferred.