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: verkle updates #3832

Merged
merged 4 commits into from
Jan 13, 2025
Merged

evm: verkle updates #3832

merged 4 commits into from
Jan 13, 2025

Conversation

gabrocheleau
Copy link
Contributor

@gabrocheleau gabrocheleau commented Jan 12, 2025

This PR extracts some Verkle-related updates and fixes from #3716:

  • Adds a systemVerkleAccessWiness to the EVM class.
  • Adds a codeHash read access when creating a contract (for collision checking)
  • Adds conditions that skips some accesses when interacting with system contracts and precompiles, as specified by the EIP-4762 EIP.
  • Clarifies and fixes code chunk handling in the statefulVerkleStateManager
  • Adjusts some miner/account reward logic so that it uses the systemVerkleAccessWitness and not the tx-level verkleAccessWitness, and skips access witness for miner when reward is 0

Copy link

codecov bot commented Jan 12, 2025

Codecov Report

Attention: Patch coverage is 29.03226% with 44 lines in your changes missing coverage. Please review.

Project coverage is 75.65%. Comparing base (e15b73b) to head (dd2e850).
Report is 1 commits behind head on master.

Additional details and impacted files

Impacted file tree graph

Flag Coverage Δ
block 73.74% <ø> (ø)
blockchain 83.23% <ø> (ø)
client 73.70% <ø> (?)
common 89.82% <0.00%> (ø)
devp2p 71.95% <ø> (ø)
evm 64.95% <15.00%> (-0.09%) ⬇️
genesis 100.00% <ø> (ø)
mpt 52.30% <ø> (+0.18%) ⬆️
rlp 95.11% <ø> (ø)
statemanager 67.64% <37.50%> (-0.13%) ⬇️
tx 76.56% <ø> (ø)
util 72.81% <ø> (ø)
vm 56.97% <36.00%> (-0.21%) ⬇️
wallet 79.67% <ø> (ø)

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

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.

Can you be more explicit about what these changes are targeting? If I understand it correctly, you're dealing with the following items:

  • Checking to see if an accessed address is a system contract/precompile so we don't charge AccessWitness read for the account header fields
  • Verifying that we only add the miner to the write portion of the System Verkle Witness if the miner actually get a reward for the transaction

Is that correct or is there more being covered here?

@gabrocheleau
Copy link
Contributor Author

Can you be more explicit about what these changes are targeting? If I understand it correctly, you're dealing with the following items:

  • Checking to see if an accessed address is a system contract/precompile so we don't charge AccessWitness read for the account header fields
  • Verifying that we only add the miner to the write portion of the System Verkle Witness if the miner actually get a reward for the transaction

Is that correct or is there more being covered here?

Just clarified the description to be more explicit about the changes

@@ -166,7 +166,8 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
let charge2929Gas = true
if (
common.isActivatedEIP(6800) &&
runState.interpreter._evm.getPrecompile(address) === undefined
runState.interpreter._evm.getPrecompile(address) === undefined &&
!address.equals(createAddressFromStackBigInt(common.param('systemAddress')))
Copy link
Contributor

Choose a reason for hiding this comment

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

My only concern with this is that should consider the larger picture, mentioned by @g11tech, that it makes sense to store system contract address, codehash, and code, in memory the way we do for precompiles. I think we should go ahead and merge this as is but then do some work to make the system contract (plus any future ones) available in memory so we don't need to read code from storage for them.

Copy link
Contributor

@g11tech g11tech Jan 13, 2025

Choose a reason for hiding this comment

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

yea we need to address this both for system calls which will have address equal to system address as well as normal contract calls into system contracts

(same comment for similar handling in below changes)

Comment on lines +755 to +772
if (common.isActivatedEIP(6800) === true && reward !== BIGINT_0) {
if (evm.systemVerkleAccessWitness === undefined) {
throw Error(`verkleAccessWitness required if verkle (EIP-6800) is activated`)
}
evm.verkleAccessWitness.readAccountHeader(address)
evm.systemVerkleAccessWitness.writeAccountHeader(address)
}
account = new Account()
}
account.balance += reward
await evm.journal.putAccount(address, account)

if (common.isActivatedEIP(6800) === true) {
if (evm.verkleAccessWitness === undefined) {
if (common.isActivatedEIP(6800) === true && reward !== BIGINT_0) {
if (evm.systemVerkleAccessWitness === undefined) {
throw Error(`verkleAccessWitness required if verkle (EIP-6800) is activated`)
}
// use vm utility to build access but the computed gas is not charged and hence free
evm.verkleAccessWitness.writeAccountBasicData(address)
evm.verkleAccessWitness.readAccountCodeHash(address)
evm.systemVerkleAccessWitness.writeAccountBasicData(address)
evm.systemVerkleAccessWitness.readAccountCodeHash(address)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we consolidate all this down? Instead of having a whole code block to check to write the account header when we have account non-existence and then a second check, can we just do (this is pseudo code but you get the idea)

let accountExists = true
if (account === undefined) {
    accountExists = false
    account = new Account()
}

if (6800 is active and reward > 0)
  accountExists ?  writeAccountData/readCodHash : writeAccountHeader

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah thanks, this makes total sense and is simpler + more efficient

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.

This looks good. I'm going to test out my proposed simplification of the miner address AW in runTx logic locally and it the tests are still passing the same way, will add a commit so we can merge.

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.

LGTM. Please review my last commit before merging

} else if (chargeGas && common.isActivatedEIP(6800)) {
// If Verkle is active, then the warmstoragereadGas should still be charged
// This is because otherwise opcodes will have cost 0 (this is thus the base fee)
return common.param('warmstoragereadGas')
Copy link
Contributor

Choose a reason for hiding this comment

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

we have a check for warm in L26, so this should just be cold gas segment no?

@@ -318,7 +318,7 @@ export class StatefulVerkleStateManager implements StateManagerInterface {
chunkStems[0],
chunkSuffixes.slice(
0,
codeChunks.length <= VERKLE_CODE_OFFSET ? codeChunks.length : VERKLE_CODE_OFFSET,
chunkSuffixes.length <= VERKLE_CODE_OFFSET ? chunkSuffixes.length : VERKLE_CODE_OFFSET,
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a difference in code chunks and suffixes length?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, but it seemed more correct to actually use chunkSuffixes for this slice rather than implicitly relying that codeChunks.length === codeSuffixes.length

@gabrocheleau gabrocheleau merged commit 15994b9 into master Jan 13, 2025
40 of 41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants