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

State trie clearing (invariant-preserving alternative) #161

Closed
gavofyork opened this issue Oct 24, 2016 · 13 comments
Closed

State trie clearing (invariant-preserving alternative) #161

gavofyork opened this issue Oct 24, 2016 · 13 comments

Comments

@gavofyork
Copy link

gavofyork commented Oct 24, 2016

EDITOR UPDATE (2017-08-15): This EIP is now located at https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md. Please go there for the correct specification. The text below may be incorrect or outdated, and is not maintained.

Specification

a. Account creation transactions and the CREATE operation SHALL, prior to the execution of the initialisation code, increment the nonce over and above its normal starting value by one (for normal networks, this will be simply 1, however test-nets with non-zero default starting nonces will be different).

b. Whereas CALL and SUICIDE would charge 25,000 gas when the destination is non-existent, now the charge SHALL only be levied if the operation transfers more than zero value and the destination account is dead.

c. No account may change state from non-existent to existent-but-empty. If an operation would do this, the account SHALL instead remain non-existent.

d. At the end of the transaction, any account touched by the execution of that transaction which is now empty SHALL instead become non-existent (i.e. deleted).

Where:

An account is considered to be touched when it is involved in any potentially state-changing operation. This includes, but is not limited to, being the recipient of a transfer of zero value.

An account is considered empty when it has no code and zero nonce and zero balance.

An account is considered dead when either it is non-existent or it is empty.

At the end of the transaction is immediately following the execution of the suicide list, prior to the determination of the state trie root for receipt population.

An account changes state when:

  • it is the target or refund of a SUICIDE operation for zero or more value;
  • it is the source or destination of a CALL operation or message-call transaction transferring zero or more value;
  • it is the source or newly-creation of a CREATE operation or contract-creation transaction endowing zero or more value;
  • as the block author ("miner") it is recipient of block-rewards or transaction-fees of zero or more.

Notes

In the present Ethereum protocol, it should be noted that very few state changes can ultimately result in accounts that are empty following the execution of the transaction. In fact there are only four contexts that current implementations need track:

  • an empty account has zero value transferred to it through CALL;
  • an empty account has zero value transferred to it through SUICIDE;
  • an empty account has zero value transferred to it through a message-call transaction;
  • an empty account has zero value transferred to it through a zero-gas-price fees transfer.

Rationale

Same as #158 except that several edge cases are avoided since we do not break invariants:

  • that an account can go from having code and storage to not having code or storage mid-way through the execution of a transaction; [corrected]
  • that a newly created account cannot be deleted prior to being deployed.

CREATE avoids zero in the nonce to avoid any suggestion of the oddity of CREATEd accounts being reaped half-way through their creation.

@holiman
Copy link
Contributor

holiman commented Oct 24, 2016

An account is considered empty when it has no code and zero nonce and balance.

For clarity, shouldn't this be

An account is considered empty when it has no code, no storage and zero nonce and balance.

@chfast
Copy link
Member

chfast commented Oct 24, 2016

@holiman I think that issue has been described in #158 and we want to ignore storage.

@vbuterin
Copy link
Contributor

There is one other difference between this and #158: in #158, an account being empty also requires the storage root to be null, and it's only for the purposes of the account existence extern (used to sometimes charge 25000) gas that storage is ignored. Here, it seems like we delete an account if it has no nonce, balance or code even if it has storage.

I am confused: in #158, what are the cases in which a newly created account can be deleted prior to being deployed, or an account can go from having code and storage to not having code or storage mid-way through the execution of a transaction? Would be good to get more explanation there.

@gavofyork
Copy link
Author

It's true; that said I'd argue it's a similar edge case: An account can only have storage and no code if it was put there in init and since code execution is the only means of an account's storage interacting with anything within Ethereum's state, it is therefore inert. In any case, I'm happy to require no storage, too if desired.

CREATE -- [A's init code executing under A's account] -> B.CALL -> SUICIDE(A) [A now gets deleted] -> A... {A has been "deleted" mid-way through creation yet is still the subject of execution leading to oddities should an SSTORE happen}

On the last point I think you're right - an account can't go from having code + storage to having no code + no storage within a transaction.

@vbuterin
Copy link
Contributor

vbuterin commented Oct 24, 2016

A has been "deleted" mid-way through creation

SUICIDE doesn't delete an account immediately; the deletion happens at the end of processing the transaction.

I'd prefer to require an empty storage root for deletion (though not for applying the 25000 gas penalty), as this way it allows the rule to be understood as nonexistence being a canonical encoding for (0, 0, '', '') rather than a weird custom rule that says that under some set of circumstances a bunch of storage keys have to be deleted too.

@gavofyork
Copy link
Author

gavofyork commented Oct 25, 2016

SUICIDE doesn't delete an account immediately; the deletion happens at the end of processing the transaction.

Indeed. However, in this case, A is the target, B is the source. B is suiciding to A with no funds, which, in #158, has the effect of placing B on the suicides list and immediately deleting the otherwise empty A.

@gavofyork
Copy link
Author

gavofyork commented Oct 25, 2016

though not for applying the 25000 gas penalty
...
rather than a weird custom rule

I'm not sure I see the difference between a "weird custom rule" for one thing and exactly the same custom rule applied to something else.

Furthermore, I'm not sure of the rationale for it - if it's simply there in order to help some particular client implementation's caching optimisations then I can't say I think it's a particularly great upside compared to the wart it introduces.

@vbuterin
Copy link
Contributor

if it's simply there in order to help some particular client implementation's caching optimisations

I would say it's about simplifying the interface. If you ignore storage roots for the purpose of gas calculations, it means that the only kinds of queries that can be made during EVM execution are balance, nonce, code and individual state entry queries. If you admit the possibility of state emptiness queries, then that's a fundamentally different and more complex thing. It's sort of like why we decided not to add a "find the nearest key to X in the storage tree" opcode.

@gavofyork
Copy link
Author

I see; but then if we're already specifying emptiness in some way that pointedly ignores storage, is it really such a weird custom rule to reuse that same definition elsewhere? Especially in light of the fact that empty-code implies that the emptiness of storage be strictly irrelevant.

@obscuren
Copy link
Contributor

obscuren commented Oct 26, 2016

An account is considered empty when it has no code and zero nonce and zero balance.

I disagree. An account should be considered empty when the code, nonce, balance and state root is empty.

@joeykrug
Copy link

Along the lines of state pruning, is there any reason we need to store multiple copies of code if the same contracts use the same code? ie if I upload y token contract and have a contract that does that / creates it a bunch of times, why does it store the code multiple times instead of just once

@ethernomad
Copy link

This EIP needs to specify the block number (2675000).

@cdetrio
Copy link
Member

cdetrio commented Aug 15, 2017

This EIP is now located at https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md. Please go there for the correct specification. The text in this issue may be incorrect or outdated, and is not maintained.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants