Skip to content
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: Deactivate/Reactivate a Delegated EOA's Key #9193

Merged
merged 22 commits into from
Jan 5, 2025

Conversation

colinlyguo
Copy link
Contributor

Introduce a new precompiled contract to enable Externally Owned Accounts (EOAs) to deactivate and reactivate their private keys.

@colinlyguo colinlyguo requested a review from eth-bot as a code owner December 26, 2024 21:33
@github-actions github-actions bot added c-new Creates a brand new proposal s-draft This EIP is a Draft t-core labels Dec 26, 2024
@eth-bot
Copy link
Collaborator

eth-bot commented Dec 26, 2024

✅ All reviewers have approved.

@eth-bot eth-bot added e-consensus Waiting on editor consensus e-review Waiting on editor to review labels Dec 26, 2024
@github-actions github-actions bot added the w-ci Waiting on CI to pass label Dec 26, 2024
EIPS/eip-xxxx.md Outdated
@@ -0,0 +1,201 @@
---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
---
---
eip: 7851

Assigning next sequential EIP/ERC/RIP number.
Numbers are assigned by editors & associates.

Please also update the filename.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. updated in commit 314ed2b.

EIPS/eip-xxxx.md Outdated
title: Private key deactivation and reactivation
description: Introduce a new precompiled contract to enable Externally Owned Accounts (EOAs) to deactivate and reactivate their private keys.
author: Liyi Guo (@colinlyguo)
discussions-to: <URL>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please create a discussions topic in Eth Magicians using the template: https://ethereum-magicians.org/c/eips/5

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks. updated in 314ed2b.

@eth-bot eth-bot changed the title Add EIP: Private key deactivation and reactivation Add EIP: Private key deactivation and reactivation of EOAs with delegated code Dec 27, 2024
@github-actions github-actions bot removed the w-ci Waiting on CI to pass label Dec 27, 2024
@eth-bot eth-bot changed the title Add EIP: Private key deactivation and reactivation of EOAs with delegated code Add EIP: EOA private key deactivation/reactivation Dec 27, 2024
@github-actions github-actions bot added the w-ci Waiting on CI to pass label Dec 27, 2024
@github-actions github-actions bot removed the w-ci Waiting on CI to pass label Dec 27, 2024
@jochem-brouwer
Copy link
Member

I don't see how this works with 7702 though. If I have the private key of account A, then if I "deactivate" sending txs from A then I can still auth-sign from address B to A, thus removing the "deactivation" from A?

Should this add an extra check to 7702 when checking the auth-tuples? If the authority has the 00 deactivation byte then skip this authority?

EIPS/eip-7851.md Outdated

A new precompiled contract is introduced at address `PRECOMPILE_ADDRESS`. For each call, it consumes `PRECOMPILE_GAS_COST` gas, and the precompiled contract executes the following steps:

- The precompiled contract checks that the caller is an EOA with delegated code (i.e., its account code begins with the prefix `0xef0100`, as defined in [EIP-7702](./eip-7702)). If the code does not conform to the required prefix, the contract MUST terminate without making any state changes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Terminate" here means just "stop" the call to this precompile without making any state changes? (One could also "revert", thus the item put on stack when using the CALL* opcodes to this precompile would put 0 on stack if these conditions are not met (so no state changes are done?))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification, the error case of precompile is updated as: "Returns a precompile contract error and consumes all provided gas" (refer to 0f2aaba).

The handling logic is consistent with other precompiles mentioned in https://www.evm.codes/precompiled. Also, consuming all gas for invalid calls (reducing DoS attack vectors) looks reasonable.

For the error return, I searched client implementation in geth and found it handled outside by CALL, STATICCALL, CALLCODE, DELEGATECALL. When precompiles return an error, it will be returned to CALL, and CALL will set return value as 0. But formal documents would help clarify this for sure.

EIPS/eip-7851.md Outdated
- The precompile determines the current state of the delegated code based on its byte length:
- If the delegated code is 24 bytes (`0xef0100 || address || 0x00`), it removes the last byte (`0x00`), transitioning to the active state (`0xef0100 || address`).
- If the delegated code is 23 bytes (`0xef0100 || address`), it appends `0x00`, transitioning to the deactivated state (`0xef0100 || address || 0x00`).
- The updated delegated code is saved as the new account code for the EOA.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a rule should be added here. In case that we are updating the delegated code, but we are running in "static" mode (so a call chain after using STATICCALL) this should abort (revert, no state-changes).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. you're right! I added the STATICCALL error case in this commit: 0f2aaba

@eth-bot eth-bot changed the title Add EIP: EOA private key deactivation/reactivation Add EIP: EOA private key deactivation and reactivation Dec 28, 2024
@colinlyguo
Copy link
Contributor Author

I don't see how this works with 7702 though. If I have the private key of account A, then if I "deactivate" sending txs from A then I can still auth-sign from address B to A, thus removing the "deactivation" from A?

Should this add an extra check to 7702 when checking the auth-tuples? If the authority has the 00 deactivation byte then skip this authority?

nice catch. added the extra check you mentioned in the draft. pls refer to this commit: 0f2aaba

@eth-bot eth-bot changed the title Add EIP: EOA private key deactivation and reactivation Add EIP: EOA private key deactivation/reactivation Dec 28, 2024
Copy link

The commit e8778dc (as a parent of 0008744) contains errors.
Please inspect the Run Summary for details.

Co-authored-by: Jochem Brouwer <[email protected]>
EIPS/eip-7851.md Outdated

### Gas Cost

No changes to the base transaction gas cost (`21000`) are required, as the additional valid check for the deactivation status is minimal. Thus it is reasonable to consider the overhead covered by the base gas cost.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check if the current account is deactivated actually is more expensive than a base transaction due to the nature of the state trie. To read an account from the trie, one gets these items:

  • Nonce
  • Balance
  • codeHash
  • storageHash

In order to read the actual code (to figure out if the account is delegated and thus to also perform the private key deactivation check) we have to actual read from the database again (to find what code codeHash points to). Since this is a disk read this is expensive and since this is now necessary for all transactions this might be a reason to increase the base transaction cost.

Copy link
Contributor Author

@colinlyguo colinlyguo Dec 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it makes sense. I missed this (code read cost).

In the first draft before opening this pr, the proposal plans to add a new bool (1 byte) field in the account state, so that it can be read together with nonce, balance, codeHash, and storageHash.

this may add some complexities in backward compatibility discussions while keeping the basic cost of transactions cheaper. do you think it makes sense to change the implementation of the draft to this method? so that the basic transaction cost can be kept unchanged.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

21000**
**

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colinlyguo This extra field in state will make this rather complex, because you are adding an extra field to the account state. This also means there will be logic introduced when enabling this EIP: each time if an account is hit, there will be logic to see if this account is "upgraded" to have this boolean in state. If this is not the case, then it could either add this flag to the state, or it could also do it only when necessary (so, if a transaction is sent, there will first be a check if the private key is deactivated. To check, first see if there is a boolean field at all: if this is not the case, then we can know for sure that this is an "old" account state and the private key is thus active. We can then add this field to the state. But this mechanism of checking and adding these fields will make the test vectors for this very big and it will also add a lot of somewhat boilerplate "upgrade" code to ensure the old accounts will update to the new ones (with this private key enabled flag). I would not recommend it.

I do recall in the past there have been discussions of using the nonce field. One could, for instance, use the highest bit of the nonce for this flag. One could use this flag to see if the accounts private key is disabled. What is handy here is that the nonce data is already in the account, so no extra disk lookups are necessary (when compared to putting it in the code).

However some nonce-limiting EIPs are around: https://eips.ethereum.org/EIPS/eip-3338, https://eips.ethereum.org/EIPS/eip-4803, putting a flag in nonce would likely throw away the benefits/rationales of these EIPs (4803 ensures that it can be decoded as int).

Copy link
Contributor Author

@colinlyguo colinlyguo Dec 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree. introduced a new field in the account state will add a lot of unnecessary "upgrade" code, which should be avoided.

adding a flag in nonce looks like a good idea.

for EIP-3338 which limits the nonce <= 2^52, using the highest bit of 2^52 seems not to make a large difference:

  • the number is still large, 2^51 ~= 2.25 * 10^15.
  • compared with 2^64-1, it's also quite small (same as 2^52).

For forward compatibility, can move the "deactivated bit" based on the nonce length after an upgrade. i.e. modifying the transaction verification rules.

an alternative to avoid encoding in the highest bit would be to encode the "deactivated bit" in the lowest bit of nonce, the actual nonce = nonce / 2.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

EIPS/eip-7851.md Show resolved Hide resolved
@colinlyguo colinlyguo force-pushed the EOA-deactivation branch 2 times, most recently from 9b8824a to 4ff1e76 Compare December 30, 2024 21:07
Copy link

@ADNANALISALHADABY ADNANALISALHADABY left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EIPS/eip-xxxx.md


### In-protocol reactivation

This approach ensures maximum compatibility with future migrations. EOAs can reactivate their private keys, delegate their accounts to an [EIP-7701](./eip-7701) contract, and then deactivate their private keys again. This avoids the limitations of contract upgrades. e.g. to remove legacy proxy contracts (reducing gas overhead) when upgrading to EOF contracts, one can reactivate the EOA and redelegate it to an EOF proxy contract.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no better alternative, but this definitely sounds risky. Once a privkey has been deactivated most users would not take care to keep it secure. If it's leaked an attacker could use it after reactivation.

A powerful solution would be to enable delegation through a precompile. Then the account code could implement the required checks before "upgrading" its own code.


### Additional checks during transaction validation

The deactivation status is determined by checking the length of the delegated code. This check introduces an additional storage read and check comparable to account state read and checks, such as nonce validation. It is integrated into the transaction validity check of the transaction pool and consensus rules, ensuring that invalid transactions are filtered out before propagation and execution.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check introduces an additional storage read

Since we read the account anyway for the nonce, I don't think this requires an additional read, so there's no additional workload for the txpool.

Copy link
Member

@jochem-brouwer jochem-brouwer Jan 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an extra storage read, because the code itself is not directly stored in the account: only the code hash is stored in the account. So an extra storage read is necessary to get the actual code of the account (and not the hash). See also this comment


### In-protocol reactivation

This approach ensures maximum compatibility with future migrations. EOAs can reactivate their private keys, delegate their accounts to an [EIP-7701](./eip-7701) contract, and then deactivate their private keys again. This avoids the limitations of contract upgrades. e.g. to remove legacy proxy contracts (reducing gas overhead) when upgrading to EOF contracts, one can reactivate the EOA and redelegate it to an EOF proxy contract.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EOAs can reactivate their private keys

The code cannot know if its privkey is currently deactivated or not, right? (Since extcodehash only returns the delegation prefix.) Would this be an issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK not to know the specific status, each time the contract invokes the precompile, it just toggles the status, i.e. from deactivated to activated, or from activated to deactivated.

EIPS/eip-7851.md Outdated
@@ -0,0 +1,247 @@
---
eip: 7851
title: EOA private key deactivation/reactivation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
title: EOA private key deactivation/reactivation
title: Delegated EOA's private key deactivation/reactivation

may be doesn't fit the title length constraint...

Copy link
Contributor Author

@colinlyguo colinlyguo Jan 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. While the added delegated seems necessary, what about Deactivate/Reactivate a Delegated EOA's Key?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes sounds good

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EIPS/eip-7851.md

@eth-bot eth-bot changed the title Add EIP: EOA private key deactivation/reactivation Add EIP: Deactivate/Reactivate of Delegated EOA's Key Jan 5, 2025
@eth-bot eth-bot changed the title Add EIP: Deactivate/Reactivate of Delegated EOA's Key Add EIP: Deactivate/Reactivate a Delegated EOA's Key Jan 5, 2025
Copy link
Contributor

@g11tech g11tech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm for draft

@eth-bot eth-bot enabled auto-merge (squash) January 5, 2025 15:58
Copy link
Collaborator

@eth-bot eth-bot left a 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...

@eth-bot eth-bot merged commit d96625a into ethereum:master Jan 5, 2025
16 of 17 checks passed
Copy link
Collaborator

@eth-bot eth-bot left a 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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c-new Creates a brand new proposal e-consensus Waiting on editor consensus e-review Waiting on editor to review s-draft This EIP is a Draft t-core
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants