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

EVM, remove EEI: cleanup statemanager #2702

Merged
merged 43 commits into from
Jun 1, 2023
Merged

Conversation

jochem-brouwer
Copy link
Member

@jochem-brouwer jochem-brouwer commented May 15, 2023

Follow-up of #2649

This PR intends to remove all EVM-related logic from state manager, in particular:

  • Touched accounts
  • Warm addresses
  • Warm slots

This PR will also:

  • Optimize getOriginalContractStorage
  • Cleanup the EVMStateManagerInterface in common
  • Ensure EthersStateManager is compatible with EVMStateManagerInterface and is thus able to also run VM (@holgerd77 could you check this?)
    • (fixes the TODO tests in the ethers state manager tests)

Super WIP

@jochem-brouwer jochem-brouwer added PR state: WIP package: vm type: test all hardforks This special label enables VM state and blockchain tests for all hardforks on the respective PR. package: statemanager package: evm labels May 15, 2023
@codecov
Copy link

codecov bot commented May 15, 2023

Codecov Report

Merging #2702 (25105e9) into master (238b1eb) will increase coverage by 0.35%.
The diff coverage is 88.73%.

Additional details and impacted files

Impacted file tree graph

Flag Coverage Δ
block 90.82% <ø> (ø)
blockchain 90.72% <ø> (ø)
client 86.82% <ø> (ø)
common 97.00% <100.00%> (-0.06%) ⬇️
devp2p 89.40% <ø> (+0.12%) ⬆️
ethash ∅ <ø> (∅)
rlp ?
statemanager 86.28% <100.00%> (+5.74%) ⬆️
trie 89.59% <ø> (-0.34%) ⬇️
tx 95.76% <ø> (ø)
util 81.13% <ø> (ø)
vm 81.07% <77.77%> (-0.30%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

@jochem-brouwer
Copy link
Member Author

Will use this comment as a scratchpad otherwise I will lose my line of thinking, so ignore this comment.

For _accessedStorageReverted we only use this in generate access list, this should not be a Map, it should just be a Set and each time a frame is reverted, put all items on the _accessedStorageReverted. (Also most likely add a flag to disable this behavior since we only need it to generate the access list).

Maybe for the access list just change the behavior: keep track of a set, each time a new slot is touched (whether it is reverted or not) just put it on the access list, this simplifies it a lot.

st.deepEqual(origRes, value)

st.end()
})

t.test("getOriginalContractStorage should validate the key's length", async (st) => {
try {
await (<any>stateManager).getOriginalContractStorage(address, new Uint8Array(12))
await (<any>stateManager).originalStorageCache.getOriginalContractStorage(
Copy link
Contributor

Choose a reason for hiding this comment

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

Same

Comment on lines 150 to 133
state.addWarmedStorage(address, toBytes(storageKey))
this.evm.evmJournal.addPreWarmedSlot(accessListItem.address, storageKey, true)
Copy link
Contributor

@gabrocheleau gabrocheleau May 30, 2023

Choose a reason for hiding this comment

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

I don't fully grasp the accessListItem logic of this code section, but is it intentional that we're refactoring addWarmedStorage to addPreWarmedSlot (since we have a addWarmedStorage method on the evmJournal)?

EDIT: nevermind, seems fine based on other comments.

Copy link
Member Author

Choose a reason for hiding this comment

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

I will explain at the call tomorrow, but the pre-warmed addresses and "normal" warmed addresses behave differently, in the sense that pre-warmed addresses can never be marked cold again, but "normal" warmed addresses can (if a call frame reverts).

@@ -474,7 +474,7 @@ tape('runTx() -> runtime behavior', async (t) => {
await vm.runTx({ tx }) // this tx will fail, but we have to ensure that the cache is cleared

t.equal(
(<any>vm.stateManager)._originalStorageCache.size,
(<any>vm.stateManager).originalStorageCache.map.size,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the ` necessary?

;(<any>state).touchedJournal.clear()
//;(<any>state).touchedJournal.clear()
Copy link
Contributor

Choose a reason for hiding this comment

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

Intentional?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah yes, in this method the state is setup via StateManager, not EVM (so there are no touched accounts). Therefore this cleanup action is not necessary. Should remove anyways.

clearOriginalStorageCache(): void {
this.map = new Map()
}
}
Copy link
Member

Choose a reason for hiding this comment

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

I would have a tendency to drastically shorten the names here, so just use get, put and clear. 😋

Think that makes the API more elegant and readable and what this does can be taken very much from the context, so e.g. this._stateManager.originalStorageCache.get(...) (still long enough 🙂).

//AddressString | Map<AddressString, SlotString>
type JournalHeight = number

export class EvmJournal {
Copy link
Member

Choose a reason for hiding this comment

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

Here as well, I would suggest to just name Journal and also simplify the file name evmJournal.ts -> journal.ts.

Copy link
Member Author

Choose a reason for hiding this comment

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

Should I rename evm.evmJournal to evm.journal as well?

Copy link
Member

Choose a reason for hiding this comment

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

I would vote yes! 🙂

@jochem-brouwer
Copy link
Member Author

Ok, I should have resolved most review items except if I should rename evm.evmJournal to evm.journal (I think I have the tendency to do so).

Furthermore, I have removed accountExists and accountIsEmptyOrNonExistent from the interface. However, accountExists is still in EthersStateManager, since this is rather educational: it shows how to know, from eth_getProof if an account exists in the trie or not. You cannot use eth_getAccount for this, since it will always return an empty account if the account does not exist in the trie, or it exists in the trie but is empty.

I have also cleaned up the method names of originalStorageCache.

@jochem-brouwer
Copy link
Member Author

And possibly preWarmed -> alwaysWarm?

@holgerd77
Copy link
Member

And possibly preWarmed -> alwaysWarm?

Was very much a quick-shot 😋, I think I still find it substantially easier to grasp though, also on second thought (preWarmed can lead thoughts somewhat in a wrong direction).

@jochem-brouwer
Copy link
Member Author

Yup, have addressed!

@holgerd77
Copy link
Member

Short in-between note: I now synced with this branch > block 1Mio with the client, no anomalies to detect. 🙂

@@ -10,6 +10,7 @@ import { trap } from './opcodes'
import { Stack } from './stack'

import type { EVM, EVMResult } from './evm'
import type { Journal } from './journal'
import type { AsyncOpHandler, OpHandler, Opcode } from './opcodes'
import type { Block, Blockchain, Log } from './types'
import type { Common, EVMStateManagerInterface } from '@ethereumjs/common'
Copy link
Member

Choose a reason for hiding this comment

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

Debug logger from below, currently evm:eei:gas (so annying this untouched-lines-comment-deactivation), should be renamed.

Simply evm:gas?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, evm:gas is perfect. I will do a quick check to see if there are any other eei leftovers.

@jochem-brouwer
Copy link
Member Author

Short in-between note: I now synced with this branch > block 1Mio with the client, no anomalies to detect. 🙂

Cool! I also wonder slightly about performance, did you notice anything?

We could also do a quick test with disk reads before/after this PR. It should decrease (and hopefully a lot! :) )

@holgerd77
Copy link
Member

Short in-between note: I now synced with this branch > block 1Mio with the client, no anomalies to detect. 🙂

Cool! I also wonder slightly about performance, did you notice anything?

We could also do a quick test with disk reads before/after this PR. It should decrease (and hopefully a lot! :) )

Performance is always hard to grasp, so I am getting more and more cautious to do any early statements here.

Doing catch-up-execution right now (by deactivating block sync), at ~1.2 Mio (Homestead) atm, everything still running smoothly atm, though block execution has gotten a bit slower, but that's also always dependent of the respective usage of the respective block parts.

I wanted to sync into the "problematic ranges" again, that start in the ~ 1.6 Mio or so block numbers. These are always easier to compare, since base execution numbers for a single block are already pretty high.

Also not totally meaningful then (since single blocks/txs are often targeting very specfic EVM functionality). So at the end best is always to do 2-4 different ranges.

@gabrocheleau
Copy link
Contributor

Ok, I should have resolved most review items except if I should rename evm.evmJournal to evm.journal (I think I have the tendency to do so).

Furthermore, I have removed accountExists and accountIsEmptyOrNonExistent from the interface. However, accountExists is still in EthersStateManager, since this is rather educational: it shows how to know, from eth_getProof if an account exists in the trie or not. You cannot use eth_getAccount for this, since it will always return an empty account if the account does not exist in the trie, or it exists in the trie but is empty.

I have also cleaned up the method names of originalStorageCache.

Nice, I really like the API simplifications!

Copy link
Contributor

@acolytec3 acolytec3 left a comment

Choose a reason for hiding this comment

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

Looks great with the additional edits!

@jochem-brouwer jochem-brouwer merged commit 02df7c8 into master Jun 1, 2023
@holgerd77 holgerd77 deleted the cleanup-statemanager-v2 branch June 1, 2023 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: common package: evm package: statemanager package: vm PR state: needs review type: test all hardforks This special label enables VM state and blockchain tests for all hardforks on the respective PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants