-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add EIP: Set EOA account code for one transaction #8527
Conversation
✅ All reviewers have approved. |
rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, data, access_list, [[contract_code, y_parity, r, s], ...], signature_y_parity, signature_r, signature_s]) | ||
``` | ||
|
||
The intrinsic cost of the new transaction is inherited from [EIP-2930](./eip-2930.md), specifically `21000 + 16 * non-zero calldata bytes + 4 * zero calldata bytes + 1900 * access list storage key count + 2400 * access list address count`. Additionally, we add a cost of `16 * non-zero calldata bytes + 4 * zero calldata bytes` over each `contract_code`, plus `PER_CONTRACT_CODE_BASE_COST` times the length of the `contract_code` array. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems expensive, can users not point to an already deployed contract and reduce data size of txn payload?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking is that that's what delegatecall forwarders are for. But happy to consider the direct-to-address option too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minimal proxy accounts have very little bytecode. Using ERC-1167 should be sufficient and keep this EIP lean
|
||
This EIP breaks the invariant that an account balance can only decrease as a result of transactions originating from that account. This has consequences for mempool design, and for other EIPs such as inclusion lists. However, these issues are common to any proposal that provides similar functionality, including EIP-3074. | ||
|
||
## Security Considerations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume it is, but just to confirm - this EIP doesn't allow storage modification of the EOA right?
e.g., SSTORE, etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
At the start of executing the transaction, for each `[contract_code, y_parity, r, s]` tuple: | ||
|
||
1. Let `signer = ecrecover(keccak(MAGIC + contract_code), y_parity, r, s]`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means that a signature is reusable and non revocable. That can then be reused and encapsulated into other transactions.
If the code is vulnerable (for any reason) the signer becomes vulnerable indefinitely
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Assuming 'MAGIC' is a constant value)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the code tuple contained the signer's nonce then the same revocation strategy as 3074 could be used. While that solves revocation, it's unclear to me if the tuples being reusable is a feature or a bug though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3074 includes the invokerAddress
in the AUTH
payload, so auth is only reusable by a single invoker, so perhaps the tuple also an address field to compare tx.origin
against?
The [EIP-2718](./eip-2718.md) `TransactionPayload` for this transaction is | ||
|
||
``` | ||
rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, data, access_list, [[contract_code, y_parity, r, s], ...], signature_y_parity, signature_r, signature_s]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A small suggestion: when y_parity
is 0 or 1, it's a temporary setting code. When it's 2 or 3, it's secp256r1
and a permanent setting code. When it's 4 or 5, it's secp256k1
and a permanent setting code (currently not supported).
Your idea is very similar to mine, but you chose the tx type
, so there's no need to add an opcode.
https://github.com/ethereum/EIPs/pull/8493/files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a new field, don't overload yParity. We don't need more obscure parsing rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
If EIP7702 has already been implemented, the cost of adding a new algorithm isn't high.
-
The risk of permanently upgrading an EOA to a CA is significant (as EOAs carry historical baggage), but addresses generated by algorithms like secp256r1 are not EOAs, so permanently setting code carries no additional risk.
-
People need a more stable way to ensure deterministic deployments.
-
Better backward compatibility: When temporary code setting is prohibited and only permanent code setting is allowed, simply reject that type and enable a new type.
-
Prevent user errors: In the past, Ethereum used block heights to determine certain code behaviors, which wasn't user-friendly. We should directly reject user requests via a flag since upgrading an EOA to a CA is risky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a new field, don't overload yParity. We don't need more obscure parsing rules.
Yeah, a new flag like this:
0x00: Temporary upgrade And secp256k1
0x10: Permanent upgrade And secp256k1
0x01: Temporary upgrade And secp256r1
0x11: Permanent upgrade And secp256r1
...
3. Set the contract code of `signer` to `contract_code`. | ||
|
||
At the end of the transaction, set the `contract_code` of each `signer` back to empty. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I presume during transaction execution the EXTCODEHASH
will return the contract_code
, right?
Is it intended that the I am asking because this was a huge point of contention for 3074, and many claimed contracts cannot be trusted to do the right thing, which led to the introduction of the nonce concept in 3074. (I don't agree that signing over the account's nonce is necessary btw) |
Nice proposals. I've a few questions though
|
just want to remind everyone this PR is going to be merged shortly so the discussion should continue on in the discussions-to link https://ethereum-magicians.org/t/eip-set-eoa-account-code-for-one-transaction/19923 |
At the end of the transaction, set the `contract_code` of each `signer` back to empty. | ||
|
||
Note that the signer of any of the `contract_code` signatures, and the `tx.origin` of the transaction, are allowed to be different. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
### Opcode restriction | |
For security reasons, some opcodes MUST not be executed in the context of an EOA: | |
- `SSTORE` (0x55): Setting storage under an EOA breaks common assumptions. Conflits could arise from a single EOA using multiple code vertsion (in multiple transactions) that interpret the storage layout under the account differently. Therefore, EOAs should be forbiden from performing `SSTORE` if the code is to be cleared at the end of the transaction. Any CALL performed by the code placed at the EOA's address is free to manipulate storage normally. | |
- `CREATE` (0xF0), `CREATE2` (0xF5) and `SELFDESTRUCT` (0xFF): There may be an expectation that transactions from a given sender should have consecutive nonces. This assumption would be broken if code placed at an EOA's address was to execute one or multiple operations that alter the sender account's nonce. Consequently, EOA performing a delegate transaction should not be able to use the `CREATE`, `CREATE2` or `SELFDESTRUCT` opcodes. Any CALL performed by the code placed at the EOA's address is free to create contracts normally. | |
Any attempts to execute one of these restricted operations in the context of one of the signers MUST throw an exception. | |
This restrictions only apply if the code placed at the signer's address is removed at the end of the transaction. If a flag is set to not set the code back to empty at the end of the transactions, then these restrictions do not apply. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with restricting CREATE
, CREATE2
and SELFDESTRUCT
but not sure what harm SSTORE
poses. While the code stored at the address is deleted, all written storage slots can be cleared alongside it, that way it isn't persisted across different transactions.
I'd argue that the gas cost of SSTORE
and SLOAD
be the same as that of TLOAD
and TSTORE
since they'd behave exactly the same way in this scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to be able to SSTORE
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd also want to use storage, but that would be breaking invariants specified in other EIP
There is a restriction that account with no code should have no storage. If someone can find a référénce that would be great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, but I think if all written slots are cleared at the end of the transaction it doesn't break any invariants.
During the transaction it doesn't break any invariants too since if the code length, code or codehash is queried, it returns a non-default value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a restriction that account with no code should have no storage. If someone can find a référénce that would be great.
Not so sure about this because a contract that sets storage at initialization but also returns 0 bytes at initialization has no bytecode but has > 0 storage slots set.
See here: https://twitter.com/AmadiMichaels/status/1641918500020137984?t=sy3aLWqR4we0tuA_kXV20w&s=19
Co-authored-by: Sam Wilson <[email protected]>
At the start of executing the transaction, for each `[contract_code, y_parity, r, s]` tuple: | ||
|
||
1. Let `signer = ecrecover(keccak(MAGIC + contract_code), y_parity, r, s]`. | ||
2. Verify that the contract code of `signer` is empty. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is important to mention that the outcome of this "verification" is only whether the signer's code is set.
That is: if the ecrecover succeeds (doesn't return zero), AND the returned signer
address doesn't have code, only then its code is set to contract_code
.
In any other circumstance, it is left unmodified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All Reviewers Have Approved; Performing Automatic Merge...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thats more elaborate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
Add a new transaction type that adds a
contract_code
field and a signature, and converts the signing account (not necessarily the same as thetx.origin
) into a smart contract wallet for the duration of that transaction. Intended to offer similar functionality to EIP-3074.