Skip to content

Commit

Permalink
evm: simplify verkle access witness methods (#3830)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrocheleau authored Jan 8, 2025
1 parent 3f0f3b5 commit e15b73b
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 209 deletions.
45 changes: 10 additions & 35 deletions packages/common/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,41 +102,16 @@ export interface VerkleAccessWitnessInterface {
accesses(): Generator<VerkleAccessedStateWithAddress>
rawAccesses(): Generator<RawVerkleAccessedState>
debugWitnessCost(): void
touchAndChargeProofOfAbsence(address: Address): bigint
touchAndChargeMessageCall(address: Address): bigint
touchAndChargeValueTransfer(target: Address): bigint
touchAndChargeContractCreateInit(address: Address): bigint
touchAndChargeContractCreateCompleted(address: Address): bigint
touchTxOriginAndComputeGas(origin: Address): bigint
touchTxTargetAndComputeGas(target: Address, { sendsValue }: { sendsValue?: boolean }): bigint
touchCodeChunksRangeOnReadAndComputeGas(contract: Address, startPc: number, endPc: number): bigint
touchCodeChunksRangeOnWriteAndComputeGas(
contract: Address,
startPc: number,
endPc: number,
): bigint
touchAddressOnWriteAndComputeGas(
address: Address,
treeIndex: number | bigint,
subIndex: number | Uint8Array,
): bigint
touchAddressOnReadAndComputeGas(
address: Address,
treeIndex: number | bigint,
subIndex: number | Uint8Array,
): bigint
touchAddressAndComputeGas(
address: Address,
treeIndex: number | bigint,
subIndex: number | Uint8Array,
{ isWrite }: { isWrite?: boolean },
): bigint
touchAddress(
address: Address,
treeIndex: number | bigint,
subIndex: number | Uint8Array,
{ isWrite }: { isWrite?: boolean },
): AccessEventFlags
readAccountBasicData(address: Address): bigint
writeAccountBasicData(address: Address): bigint
readAccountCodeHash(address: Address): bigint
writeAccountCodeHash(address: Address): bigint
readAccountHeader(address: Address): bigint
writeAccountHeader(address: Address): bigint
readAccountCodeChunks(contract: Address, startPc: number, endPc: number): bigint
writeAccountCodeChunks(contract: Address, startPc: number, endPc: number): bigint
readAccountStorage(contract: Address, storageSlot: bigint): bigint
writeAccountStorage(contract: Address, storageSlot: bigint): bigint
merge(accessWitness: VerkleAccessWitnessInterface): void
commit(): void
revert(): void
Expand Down
44 changes: 20 additions & 24 deletions packages/evm/src/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,18 +269,22 @@ export class EVM implements EVMInterface {
}
const sendsValue = message.value !== BIGINT_0
if (message.depth === 0) {
const originAccessGas = message.accessWitness.touchTxOriginAndComputeGas(fromAddress)
const originAccessGas = message.accessWitness.readAccountHeader(fromAddress)
debugGas(`originAccessGas=${originAccessGas} waived off for origin at depth=0`)

const destAccessGas = message.accessWitness.touchTxTargetAndComputeGas(message.to, {
sendsValue,
})
let destAccessGas = message.accessWitness.readAccountCodeHash(message.to)
if (sendsValue) {
destAccessGas += message.accessWitness.writeAccountBasicData(message.to)
} else {
destAccessGas += message.accessWitness.readAccountBasicData(message.to)
}

debugGas(`destAccessGas=${destAccessGas} waived off for target at depth=0`)
}

let callAccessGas = message.accessWitness.touchAndChargeMessageCall(message.to)
let callAccessGas = message.accessWitness.readAccountBasicData(message.to)
if (sendsValue) {
callAccessGas += message.accessWitness.touchAndChargeValueTransfer(message.to)
callAccessGas += message.accessWitness.writeAccountBasicData(message.to)
}
gasLimit -= callAccessGas
if (gasLimit < BIGINT_0) {
Expand Down Expand Up @@ -315,9 +319,7 @@ export class EVM implements EVMInterface {
let toAccount = await this.stateManager.getAccount(message.to)
if (!toAccount) {
if (this.common.isActivatedEIP(6800)) {
const absenceProofAccessGas = message.accessWitness!.touchAndChargeProofOfAbsence(
message.to,
)
const absenceProofAccessGas = message.accessWitness!.readAccountHeader(message.to)
gasLimit -= absenceProofAccessGas
if (gasLimit < BIGINT_0) {
if (this.DEBUG) {
Expand Down Expand Up @@ -418,7 +420,7 @@ export class EVM implements EVMInterface {

if (this.common.isActivatedEIP(6800)) {
if (message.depth === 0) {
const originAccessGas = message.accessWitness!.touchTxOriginAndComputeGas(fromAddress)
const originAccessGas = message.accessWitness!.readAccountHeader(fromAddress)
debugGas(`originAccessGas=${originAccessGas} waived off for origin at depth=0`)
}
}
Expand Down Expand Up @@ -464,9 +466,7 @@ export class EVM implements EVMInterface {
}

if (this.common.isActivatedEIP(6800)) {
const contractCreateAccessGas = message.accessWitness!.touchAndChargeContractCreateInit(
message.to,
)
const contractCreateAccessGas = message.accessWitness!.writeAccountBasicData(message.to)
gasLimit -= contractCreateAccessGas
if (gasLimit < BIGINT_0) {
if (this.DEBUG) {
Expand Down Expand Up @@ -550,8 +550,7 @@ export class EVM implements EVMInterface {

if (exit) {
if (this.common.isActivatedEIP(6800)) {
const createCompleteAccessGas =
message.accessWitness!.touchAndChargeContractCreateCompleted(message.to)
const createCompleteAccessGas = message.accessWitness!.writeAccountHeader(message.to)
gasLimit -= createCompleteAccessGas
if (gasLimit < BIGINT_0) {
if (this.DEBUG) {
Expand Down Expand Up @@ -671,9 +670,7 @@ export class EVM implements EVMInterface {
// get the fresh gas limit for the rest of the ops
gasLimit = message.gasLimit - result.executionGasUsed
if (!result.exceptionError && this.common.isActivatedEIP(6800)) {
const createCompleteAccessGas = message.accessWitness!.touchAndChargeContractCreateCompleted(
message.to,
)
const createCompleteAccessGas = message.accessWitness!.writeAccountHeader(message.to)
gasLimit -= createCompleteAccessGas
if (gasLimit < BIGINT_0) {
if (this.DEBUG) {
Expand All @@ -699,12 +696,11 @@ export class EVM implements EVMInterface {
) {
// Add access charges for writing this code to the state
if (this.common.isActivatedEIP(6800)) {
const byteCodeWriteAccessfee =
message.accessWitness!.touchCodeChunksRangeOnWriteAndComputeGas(
message.to,
0,
result.returnValue.length - 1,
)
const byteCodeWriteAccessfee = message.accessWitness!.writeAccountCodeChunks(
message.to,
0,
result.returnValue.length - 1,
)
gasLimit -= byteCodeWriteAccessfee
if (gasLimit < BIGINT_0) {
if (this.DEBUG) {
Expand Down
11 changes: 5 additions & 6 deletions packages/evm/src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,12 +386,11 @@ export class Interpreter {

if (this.common.isActivatedEIP(6800) && this._env.chargeCodeAccesses === true) {
const contract = this._runState.interpreter.getAddress()
const statelessGas =
this._runState.env.accessWitness!.touchCodeChunksRangeOnReadAndComputeGas(
contract,
this._runState.programCounter,
this._runState.programCounter,
)
const statelessGas = this._runState.env.accessWitness!.readAccountCodeChunks(
contract,
this._runState.programCounter,
this._runState.programCounter,
)
gas += statelessGas
debugGas(`codechunk accessed statelessGas=${statelessGas} (-> ${gas})`)
}
Expand Down
9 changes: 3 additions & 6 deletions packages/evm/src/opcodes/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
bytesToInt,
concatBytes,
equalsBytes,
getVerkleTreeIndicesForStorageSlot,
setLengthLeft,
} from '@ethereumjs/util'
import { keccak256 } from 'ethereum-cryptography/keccak.js'
Expand Down Expand Up @@ -667,12 +666,10 @@ export const handlers: Map<number, OpHandler> = new Map([
const key = setLengthLeft(bigIntToBytes(number % historyServeWindow), 32)

if (common.isActivatedEIP(6800)) {
const { treeIndex, subIndex } = getVerkleTreeIndicesForStorageSlot(number)
// create witnesses and charge gas
const statelessGas = runState.env.accessWitness!.touchAddressOnReadAndComputeGas(
const statelessGas = runState.env.accessWitness!.readAccountStorage(
historyAddress,
treeIndex,
subIndex,
number,
)
runState.interpreter.useGas(statelessGas, `BLOCKHASH`)
}
Expand Down Expand Up @@ -959,7 +956,7 @@ export const handlers: Map<number, OpHandler> = new Map([
const contract = runState.interpreter.getAddress()
const startOffset = Math.min(runState.code.length, runState.programCounter + 1)
const endOffset = Math.min(runState.code.length, startOffset + numToPush - 1)
const statelessGas = runState.env.accessWitness!.touchCodeChunksRangeOnReadAndComputeGas(
const statelessGas = runState.env.accessWitness!.readAccountCodeChunks(
contract,
startOffset,
endOffset,
Expand Down
85 changes: 18 additions & 67 deletions packages/evm/src/opcodes/gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ import {
BIGINT_31,
BIGINT_32,
BIGINT_64,
VERKLE_BASIC_DATA_LEAF_KEY,
VERKLE_CODE_HASH_LEAF_KEY,
bigIntToBytes,
equalsBytes,
getVerkleTreeIndicesForStorageSlot,
setLengthLeft,
} from '@ethereumjs/util'

Expand Down Expand Up @@ -106,11 +103,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
const address = createAddressFromStackBigInt(runState.stack.peek()[0])
let charge2929Gas = true
if (common.isActivatedEIP(6800)) {
const coldAccessGas = runState.env.accessWitness!.touchAddressOnReadAndComputeGas(
address,
0,
VERKLE_BASIC_DATA_LEAF_KEY,
)
const coldAccessGas = runState.env.accessWitness!.readAccountBasicData(address)

gas += coldAccessGas
charge2929Gas = coldAccessGas === BIGINT_0
Expand Down Expand Up @@ -154,7 +147,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
codeEnd = codeSize
}

gas += runState.env.accessWitness!.touchCodeChunksRangeOnReadAndComputeGas(
gas += runState.env.accessWitness!.readAccountCodeChunks(
contract,
Number(_codeOffset),
Number(codeEnd),
Expand All @@ -176,11 +169,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
runState.interpreter._evm.getPrecompile(address) === undefined
) {
let coldAccessGas = BIGINT_0
coldAccessGas += runState.env.accessWitness!.touchAddressOnReadAndComputeGas(
address,
0,
VERKLE_BASIC_DATA_LEAF_KEY,
)
coldAccessGas += runState.env.accessWitness!.readAccountBasicData(address)

gas += coldAccessGas
// if cold access gas has been charged 2929 gas shouldn't be charged
Expand Down Expand Up @@ -213,11 +202,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
runState.interpreter._evm.getPrecompile(address) === undefined
) {
let coldAccessGas = BIGINT_0
coldAccessGas += runState.env.accessWitness!.touchAddressOnReadAndComputeGas(
address,
0,
VERKLE_BASIC_DATA_LEAF_KEY,
)
coldAccessGas += runState.env.accessWitness!.readAccountBasicData(address)

gas += coldAccessGas
// if cold access gas has been charged 2929 gas shouldn't be charged
Expand All @@ -242,7 +227,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
codeEnd = codeSize
}

gas += runState.env.accessWitness!.touchCodeChunksRangeOnReadAndComputeGas(
gas += runState.env.accessWitness!.readAccountCodeChunks(
address,
Number(_codeOffset),
Number(codeEnd),
Expand Down Expand Up @@ -283,11 +268,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami

if (common.isActivatedEIP(6800)) {
let coldAccessGas = BIGINT_0
coldAccessGas += runState.env.accessWitness!.touchAddressOnReadAndComputeGas(
address,
0,
VERKLE_CODE_HASH_LEAF_KEY,
)
coldAccessGas += runState.env.accessWitness!.readAccountCodeHash(address)

gas += coldAccessGas
charge2929Gas = coldAccessGas === BIGINT_0
Expand Down Expand Up @@ -341,12 +322,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
let charge2929Gas = true
if (common.isActivatedEIP(6800)) {
const address = runState.interpreter.getAddress()
const { treeIndex, subIndex } = getVerkleTreeIndicesForStorageSlot(key)
const coldAccessGas = runState.env.accessWitness!.touchAddressOnReadAndComputeGas(
address,
treeIndex,
subIndex,
)
const coldAccessGas = runState.env.accessWitness!.readAccountStorage(address, key)

gas += coldAccessGas
charge2929Gas = coldAccessGas === BIGINT_0
Expand Down Expand Up @@ -409,12 +385,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
let charge2929Gas = true
if (common.isActivatedEIP(6800)) {
const contract = runState.interpreter.getAddress()
const { treeIndex, subIndex } = getVerkleTreeIndicesForStorageSlot(key)
const coldAccessGas = runState.env.accessWitness!.touchAddressOnWriteAndComputeGas(
contract,
treeIndex,
subIndex,
)
const coldAccessGas = runState.env.accessWitness!.writeAccountStorage(contract, key)

gas += coldAccessGas
charge2929Gas = coldAccessGas === BIGINT_0
Expand Down Expand Up @@ -592,15 +563,11 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
runState.interpreter._evm.getPrecompile(toAddress) === undefined
) {
// TODO: add check if toAddress is not a precompile
const coldAccessGas = runState.env.accessWitness!.touchAndChargeMessageCall(toAddress)
const coldAccessGas = runState.env.accessWitness!.readAccountBasicData(toAddress)
if (value !== BIGINT_0) {
const contractAddress = runState.interpreter.getAddress()
gas += runState.env.accessWitness!.touchAddressOnWriteAndComputeGas(
contractAddress,
0,
VERKLE_BASIC_DATA_LEAF_KEY,
)
gas += runState.env.accessWitness!.touchAndChargeValueTransfer(toAddress)
gas += runState.env.accessWitness!.writeAccountBasicData(contractAddress)
gas += runState.env.accessWitness!.writeAccountBasicData(toAddress)
}

gas += coldAccessGas
Expand Down Expand Up @@ -674,7 +641,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
common.isActivatedEIP(6800) &&
runState.interpreter._evm.getPrecompile(toAddress) === undefined
) {
const coldAccessGas = runState.env.accessWitness!.touchAndChargeMessageCall(toAddress)
const coldAccessGas = runState.env.accessWitness!.readAccountBasicData(toAddress)

gas += coldAccessGas
charge2929Gas = coldAccessGas === BIGINT_0
Expand Down Expand Up @@ -739,7 +706,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
runState.interpreter._evm.getPrecompile(toAddress) === undefined
) {
// TODO: add check if toAddress is not a precompile
const coldAccessGas = runState.env.accessWitness!.touchAndChargeMessageCall(toAddress)
const coldAccessGas = runState.env.accessWitness!.readAccountBasicData(toAddress)

gas += coldAccessGas
charge2929Gas = coldAccessGas === BIGINT_0
Expand Down Expand Up @@ -950,7 +917,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
if (common.isActivatedEIP(6800)) {
const toAddress = createAddressFromStackBigInt(toAddr)
// TODO: add check if toAddress is not a precompile
const coldAccessGas = runState.env.accessWitness!.touchAndChargeMessageCall(toAddress)
const coldAccessGas = runState.env.accessWitness!.readAccountBasicData(toAddress)

gas += coldAccessGas
charge2929Gas = coldAccessGas === BIGINT_0
Expand Down Expand Up @@ -1085,32 +1052,16 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami

let selfDestructToCharge2929Gas = true
if (common.isActivatedEIP(6800)) {
gas += runState.env.accessWitness!.touchAddressOnReadAndComputeGas(
contractAddress,
0,
VERKLE_BASIC_DATA_LEAF_KEY,
)
gas += runState.env.accessWitness!.readAccountBasicData(contractAddress)
if (balance > BIGINT_0) {
gas += runState.env.accessWitness!.touchAddressOnWriteAndComputeGas(
contractAddress,
0,
VERKLE_BASIC_DATA_LEAF_KEY,
)
gas += runState.env.accessWitness!.writeAccountBasicData(contractAddress)
}

let selfDestructToColdAccessGas =
runState.env.accessWitness!.touchAddressOnReadAndComputeGas(
selfdestructToAddress,
0,
VERKLE_BASIC_DATA_LEAF_KEY,
)
runState.env.accessWitness!.readAccountBasicData(selfdestructToAddress)
if (balance > BIGINT_0) {
selfDestructToColdAccessGas +=
runState.env.accessWitness!.touchAddressOnWriteAndComputeGas(
selfdestructToAddress,
0,
VERKLE_BASIC_DATA_LEAF_KEY,
)
runState.env.accessWitness!.writeAccountBasicData(selfdestructToAddress)
}

gas += selfDestructToColdAccessGas
Expand Down
Loading

0 comments on commit e15b73b

Please sign in to comment.