From b2edbf10ff93c5868634e359c6acdfc6f68fa314 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Fri, 10 Dec 2021 07:10:32 +0000 Subject: [PATCH] make push dynamically-charged. charge witness gas costs for push. refactor evm witness gas charging to move logic for touching a range of bytecode into a helper method 'touchEachChunksAndChargeGas' --- consensus/ethash/consensus.go | 12 ++- core/state_processor.go | 4 +- core/vm/common.go | 12 +++ core/vm/evm.go | 22 ++--- core/vm/gas_table.go | 113 ++------------------- core/vm/instructions.go | 179 ++++++++++++++++------------------ core/vm/interpreter.go | 52 ++-------- core/vm/jump_table.go | 2 - 8 files changed, 133 insertions(+), 263 deletions(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 56b35d72f2d7..6eff8d9055f1 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -661,14 +661,20 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header r.Sub(r, header.Number) r.Mul(r, blockReward) r.Div(r, big8) - uncleCoinbase := utils.GetTreeKeyBalance(uncle.Coinbase.Bytes()) - state.Witness().TouchAddress(uncleCoinbase, state.GetBalance(uncle.Coinbase).Bytes()) + + if state.Witness() != nil { + uncleCoinbase := utils.GetTreeKeyBalance(uncle.Coinbase.Bytes()) + state.Witness().TouchAddress(uncleCoinbase, state.GetBalance(uncle.Coinbase).Bytes()) + } state.AddBalance(uncle.Coinbase, r) r.Div(blockReward, big32) reward.Add(reward, r) } coinbase := utils.GetTreeKeyBalance(header.Coinbase.Bytes()) - state.Witness().TouchAddress(coinbase, state.GetBalance(header.Coinbase).Bytes()) + + if state.Witness() != nil { + state.Witness().TouchAddress(coinbase, state.GetBalance(header.Coinbase).Bytes()) + } state.AddBalance(header.Coinbase, reward) } diff --git a/core/state_processor.go b/core/state_processor.go index fcebeffce5a8..174ec77ff34e 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -128,7 +128,9 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) } - statedb.Witness().Merge(txContext.Accesses) + if config.IsCancun(blockNumber) { + statedb.Witness().Merge(txContext.Accesses) + } // Set the receipt logs and create the bloom filter. receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash) diff --git a/core/vm/common.go b/core/vm/common.go index 90ba4a4ad15b..b79186c24513 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -63,6 +63,18 @@ func getData(data []byte, start uint64, size uint64) []byte { return common.RightPadBytes(data[start:end], int(size)) } +func getDataAndAdjustedBounds(data []byte, start uint64, size uint64) (codeCopyPadded []byte, actualStart uint64, sizeNonPadded uint64) { + length := uint64(len(data)) + if start > length { + start = length + } + end := start + size + if end > length { + end = length + } + return common.RightPadBytes(data[start:end], int(size)), start, end +} + // toWordSize returns the ceiled word size required for memory expansion. func toWordSize(size uint64) uint64 { if size > math.MaxUint64-31 { diff --git a/core/vm/evm.go b/core/vm/evm.go index f5bdff8303f2..81570ed86ea5 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -125,8 +125,6 @@ type EVM struct { // available gas is calculated in gasCall* according to the 63/64 rule and later // applied in opCall*. callGasTemp uint64 - - accesses map[common.Hash]common.Hash } // NewEVM returns a new EVM. The returned EVM is not thread safe and should @@ -232,15 +230,17 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if len(code) == 0 { ret, err = nil, nil // gas is unchanged } else { - // Touch the account data - var data [32]byte - evm.Accesses.TouchAddress(utils.GetTreeKeyVersion(addr.Bytes()), data[:]) - binary.BigEndian.PutUint64(data[:], evm.StateDB.GetNonce(addr)) - evm.Accesses.TouchAddress(utils.GetTreeKeyNonce(addr[:]), data[:]) - evm.Accesses.TouchAddress(utils.GetTreeKeyBalance(addr[:]), evm.StateDB.GetBalance(addr).Bytes()) - binary.BigEndian.PutUint64(data[:], uint64(len(code))) - evm.Accesses.TouchAddress(utils.GetTreeKeyCodeSize(addr[:]), data[:]) - evm.Accesses.TouchAddress(utils.GetTreeKeyCodeKeccak(addr[:]), evm.StateDB.GetCodeHash(addr).Bytes()) + if evm.Accesses != nil { + // Touch the account data + var data [32]byte + evm.Accesses.TouchAddress(utils.GetTreeKeyVersion(addr.Bytes()), data[:]) + binary.BigEndian.PutUint64(data[:], evm.StateDB.GetNonce(addr)) + evm.Accesses.TouchAddress(utils.GetTreeKeyNonce(addr[:]), data[:]) + evm.Accesses.TouchAddress(utils.GetTreeKeyBalance(addr[:]), evm.StateDB.GetBalance(addr).Bytes()) + binary.BigEndian.PutUint64(data[:], uint64(len(code))) + evm.Accesses.TouchAddress(utils.GetTreeKeyCodeSize(addr[:]), data[:]) + evm.Accesses.TouchAddress(utils.GetTreeKeyCodeKeccak(addr[:]), evm.StateDB.GetCodeHash(addr).Bytes()) + } addrCopy := addr // If the account has no code, we can abort here diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index c42f0e61152d..19d2198af6bd 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -22,8 +22,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/params" - trieUtils "github.com/ethereum/go-ethereum/trie/utils" - "github.com/holiman/uint256" ) // memoryGasCost calculates the quadratic gas for memory expansion. It does so @@ -88,102 +86,14 @@ func memoryCopierGas(stackpos int) gasFunc { } } -func gasExtCodeSize(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - usedGas := uint64(0) - slot := stack.Back(0) - if evm.accesses != nil { - index := trieUtils.GetTreeKeyCodeSize(slot.Bytes()) - usedGas += evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) - } - - return usedGas, nil -} - var ( - gasCallDataCopy = memoryCopierGas(2) - gasCodeCopyStateful = memoryCopierGas(2) - gasExtCodeCopyStateful = memoryCopierGas(3) - gasReturnDataCopy = memoryCopierGas(2) + gasCallDataCopy = memoryCopierGas(2) + gasCodeCopy = memoryCopierGas(2) + gasExtCodeCopy = memoryCopierGas(3) + gasReturnDataCopy = memoryCopierGas(2) ) -func gasCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var statelessGas uint64 - if evm.accesses != nil { - var ( - codeOffset = stack.Back(1) - length = stack.Back(2) - ) - uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() - if overflow { - uint64CodeOffset = 0xffffffffffffffff - } - uint64CodeEnd, overflow := new(uint256.Int).Add(codeOffset, length).Uint64WithOverflow() - if overflow { - uint64CodeEnd = 0xffffffffffffffff - } - addr := contract.Address() - chunk := uint64CodeOffset / 31 - endChunk := uint64CodeEnd / 31 - // XXX uint64 overflow in condition check - for ; chunk < endChunk; chunk++ { - - // TODO make a version of GetTreeKeyCodeChunk without the bigint - index := trieUtils.GetTreeKeyCodeChunk(addr[:], uint256.NewInt(chunk)) - statelessGas += evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) - } - - } - usedGas, err := gasCodeCopyStateful(evm, contract, stack, mem, memorySize) - return usedGas + statelessGas, err -} - -func gasExtCodeCopy(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var statelessGas uint64 - if evm.accesses != nil { - var ( - a = stack.Back(0) - codeOffset = stack.Back(2) - length = stack.Back(3) - ) - uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() - if overflow { - uint64CodeOffset = 0xffffffffffffffff - } - uint64CodeEnd, overflow := new(uint256.Int).Add(codeOffset, length).Uint64WithOverflow() - if overflow { - uint64CodeEnd = 0xffffffffffffffff - } - addr := common.Address(a.Bytes20()) - chunk := uint64CodeOffset / 31 - endChunk := uint64CodeEnd / 31 - // XXX uint64 overflow in condition check - for ; chunk < endChunk; chunk++ { - // TODO(@gballet) make a version of GetTreeKeyCodeChunk without the bigint - index := trieUtils.GetTreeKeyCodeChunk(addr[:], uint256.NewInt(chunk)) - statelessGas += evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) - } - - } - usedGas, err := gasExtCodeCopyStateful(evm, contract, stack, mem, memorySize) - return usedGas + statelessGas, err -} - -func gasSLoad(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - usedGas := uint64(0) - - if evm.accesses != nil { - where := stack.Back(0) - addr := contract.Address() - index := trieUtils.GetTreeKeyStorageSlot(addr[:], where) - usedGas += evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) - } - - return usedGas, nil -} - func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - // Apply the witness access costs, err is nil - accessGas, _ := gasSLoad(evm, contract, stack, mem, memorySize) var ( y, x = stack.Back(1), stack.Back(0) current = evm.StateDB.GetState(contract.Address(), x.Bytes32()) @@ -199,15 +109,14 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi // 3. From a non-zero to a non-zero (CHANGE) switch { case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0 - return params.SstoreSetGas + accessGas, nil + return params.SstoreSetGas, nil case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0 evm.StateDB.AddRefund(params.SstoreRefundGas) - return params.SstoreClearGas + accessGas, nil + return params.SstoreClearGas, nil default: // non 0 => non 0 (or 0 => 0) - return params.SstoreResetGas + accessGas, nil + return params.SstoreResetGas, nil } } - // The new gas metering is based on net gas costs (EIP-1283): // // 1. If current value equals new value (this is a no-op), 200 gas is deducted. @@ -422,14 +331,6 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize transfersValue = !stack.Back(2).IsZero() address = common.Address(stack.Back(1).Bytes20()) ) - if evm.accesses != nil { - // Charge witness costs - for i := trieUtils.VersionLeafKey; i <= trieUtils.CodeSizeLeafKey; i++ { - index := trieUtils.GetTreeKeyAccountLeaf(address[:], byte(i)) - gas += evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) - } - } - if evm.chainRules.IsEIP158 { if transfersValue && evm.StateDB.Empty(address) { gas += params.CallNewAccountGas diff --git a/core/vm/instructions.go b/core/vm/instructions.go index fdc6e3a37c27..fc914ae048e3 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -343,9 +343,10 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() cs := uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())) - if interpreter.evm.accesses != nil { + if interpreter.evm.TxContext.Accesses != nil { index := trieUtils.GetTreeKeyCodeSize(slot.Bytes()) - interpreter.evm.TxContext.Accesses.TouchAddress(index, uint256.NewInt(cs).Bytes()) + statelessGas := interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, uint256.NewInt(cs).Bytes()) + scope.Contract.UseGas(statelessGas) } slot.SetUint64(cs) return nil, nil @@ -368,63 +369,80 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ if overflow { uint64CodeOffset = 0xffffffffffffffff } - uint64CodeEnd, overflow := new(uint256.Int).Add(&codeOffset, &length).Uint64WithOverflow() - if overflow { - uint64CodeEnd = 0xffffffffffffffff - } - if interpreter.evm.accesses != nil { - copyCodeFromAccesses(scope.Contract.Address(), uint64CodeOffset, uint64CodeEnd, memOffset.Uint64(), interpreter, scope) - } else { - codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64()) - scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - touchEachChunks(uint64CodeOffset, uint64CodeEnd, codeCopy, scope.Contract, interpreter.evm) + paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(scope.Contract.Code, uint64CodeOffset, length.Uint64()) + if interpreter.evm.TxContext.Accesses != nil { + statelessGas := touchEachChunksAndChargeGas(copyOffset, nonPaddedCopyLength, scope.Contract.Address().Bytes()[:], scope.Contract, interpreter.evm.Accesses) + scope.Contract.UseGas(statelessGas) } - + scope.Memory.Set(memOffset.Uint64(), uint64(len(paddedCodeCopy)), paddedCodeCopy) return nil, nil } -// Helper function to touch every chunk in a code range -func touchEachChunks(start, end uint64, code []byte, contract *Contract, evm *EVM) { - for chunk := start / 31; chunk <= end/31 && chunk <= uint64(len(code))/31; chunk++ { - index := trieUtils.GetTreeKeyCodeChunk(contract.Address().Bytes(), uint256.NewInt(chunk)) - count := uint64(0) - end := (chunk + 1) * 31 +// touchEachChunksAndChargeGas is a helper function to touch every chunk in a code range and charge witness gas costs +func touchEachChunksAndChargeGas(offset, size uint64, address []byte, contract *Contract, accesses *types.AccessWitness) uint64 { + if size == 0 || offset > uint64(len(contract.Code)) { + return 0 + } + var statelessGasCharged uint64 + // start:end encompasses the range between the offset of + // the first byte in the first leaf of the code range that is touched + // and the last byte in the last leaf that is touched. If the contract + // code does not fill the last leaf, 'end' is the final byte of contract code + // in the last leaf that is touched + start := offset - (offset % 31) + var end uint64 + if start+size > uint64(len(contract.Code)) { + end = uint64(len(contract.Code)) + } else { + end = start + size + (start+size)%31 + } + code := contract.Code[:] + numLeaves := (end - start) / 31 + index := make([]byte, 32, 32) + + chunkOffset := new(uint256.Int) + treeIndex := new(uint256.Int) + + for i := 0; i < int(numLeaves); i++ { + chunkOffset.Add(trieUtils.CodeOffset, uint256.NewInt(uint64(i))) + treeIndex.Div(chunkOffset, trieUtils.VerkleNodeWidth) + var subIndex byte + subIndexMod := chunkOffset.Mod(chunkOffset, trieUtils.VerkleNodeWidth).Bytes() + if len(subIndexMod) == 0 { + subIndex = 0 + } else { + subIndex = subIndexMod[0] + } + treeKey := trieUtils.GetTreeKey(address, treeIndex, subIndex) + copy(index[0:31], treeKey) + index[31] = subIndex + + var value []byte + // the offset into the leaf that the first PUSH occurs + var firstPushOffset uint64 = 0 // Look for the first code byte (i.e. no pushdata) - for ; count < 31 && end+count < uint64(len(contract.Code)) && !contract.IsCode(chunk*31+count); count++ { + for ; firstPushOffset < 31 && firstPushOffset+uint64(i)*31 < uint64(len(contract.Code)) && !contract.IsCode(uint64(i)*31+firstPushOffset); firstPushOffset++ { } - var value [32]byte - value[0] = byte(count) - if end > uint64(len(code)) { - end = uint64(len(code)) + curEnd := (uint64(i) + 1) * 31 + if curEnd > end { + curEnd = end } - copy(value[1:], code[chunk*31:end]) - evm.Accesses.TouchAddress(index, value[:]) - } -} - -// copyCodeFromAccesses perform codecopy from the witness, not from the db. -func copyCodeFromAccesses(addr common.Address, codeOffset, codeEnd, memOffset uint64, in *EVMInterpreter, scope *ScopeContext) { - chunk := codeOffset / 31 - endChunk := codeEnd / 31 - start := codeOffset % 31 // start inside the first code chunk - offset := uint64(0) // memory offset to write to - // XXX uint64 overflow in condition check - for end := uint64(31); chunk < endChunk; chunk, start = chunk+1, 0 { - // case of the last chunk: figure out how many bytes need to - // be extracted from the last chunk. - if chunk+1 == endChunk { - end = codeEnd % 31 + valueSize := curEnd - (uint64(i) * 31) + value = make([]byte, 32, 32) + value[0] = byte(firstPushOffset) + + copy(value[1:valueSize+1], code[i*31:curEnd]) + if valueSize < 31 { + padding := make([]byte, 31-valueSize, 31-valueSize) + copy(value[valueSize+1:], padding) } - // TODO make a version of GetTreeKeyCodeChunk without the bigint - index := common.BytesToHash(trieUtils.GetTreeKeyCodeChunk(addr[:], uint256.NewInt(chunk))) - h := in.evm.accesses[index] - //in.evm.Accesses.TouchAddress(index.Bytes(), h[1+start:1+end]) - scope.Memory.Set(memOffset+offset, end-start, h[1+start:end]) - offset += 31 - start + statelessGasCharged += accesses.TouchAddressAndChargeGas(index, value) } + + return statelessGasCharged } func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { @@ -439,18 +457,12 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) if overflow { uint64CodeOffset = 0xffffffffffffffff } - uint64CodeEnd, overflow := new(uint256.Int).Add(&codeOffset, &length).Uint64WithOverflow() - if overflow { - uint64CodeEnd = 0xffffffffffffffff - } addr := common.Address(a.Bytes20()) - if interpreter.evm.accesses != nil { - copyCodeFromAccesses(addr, uint64CodeOffset, uint64CodeEnd, memOffset.Uint64(), interpreter, scope) + if interpreter.evm.TxContext.Accesses != nil { + panic("extcodecopy not implemented for verkle") } else { codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64()) scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) - - touchEachChunks(uint64CodeOffset, uint64CodeEnd, codeCopy, scope.Contract, interpreter.evm) } return nil, nil @@ -579,10 +591,12 @@ func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by hash := common.Hash(loc.Bytes32()) val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash) loc.SetBytes(val.Bytes()) - // Get the initial value as it might not be present - index := trieUtils.GetTreeKeyStorageSlot(scope.Contract.Address().Bytes(), loc) - interpreter.evm.TxContext.Accesses.TouchAddress(index, val.Bytes()) + if interpreter.evm.TxContext.Accesses != nil { + index := trieUtils.GetTreeKeyStorageSlot(scope.Contract.Address().Bytes(), loc) + statelessGas := interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, val.Bytes()) + scope.Contract.UseGas(statelessGas) + } return nil, nil } @@ -907,9 +921,11 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by *pc += 1 if *pc < codeLen { scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc]))) - // touch next chunk if PUSH1 is at the boundary. if so, *pc has - // advanced past this boundary. - if *pc%31 == 0 { + + if interpreter.evm.Accesses != nil && *pc%31 == 0 { + // touch next chunk if PUSH1 is at the boundary. if so, *pc has + // advanced past this boundary. + // touch push data by adding the last byte of the pushdata var value [32]byte chunk := *pc / 31 @@ -924,7 +940,8 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by } copy(value[1:], scope.Contract.Code[chunk*31:endMin]) index := trieUtils.GetTreeKeyCodeChunk(scope.Contract.Address().Bytes(), uint256.NewInt(chunk)) - interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) + statelessGas := interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) + scope.Contract.UseGas(statelessGas) } } else { scope.Stack.push(integer.Clear()) @@ -947,43 +964,15 @@ func makePush(size uint64, pushByteSize int) executionFunc { endMin = startMin + pushByteSize } + if interpreter.evm.TxContext.Accesses != nil { + statelessGas := touchEachChunksAndChargeGas(uint64(startMin), uint64(pushByteSize), scope.Contract.Address().Bytes()[:], scope.Contract, interpreter.evm.TxContext.Accesses) + scope.Contract.UseGas(statelessGas) + } + integer := new(uint256.Int) scope.Stack.push(integer.SetBytes(common.RightPadBytes( scope.Contract.Code[startMin:endMin], pushByteSize))) - // touch push data by adding the last byte of the pushdata - var value [32]byte - chunk := uint64(endMin-1) / 31 - count := uint64(0) - // Look for the first code byte (i.e. no pushdata) - for ; count < 31 && !scope.Contract.IsCode(chunk*31+count); count++ { - } - value[0] = byte(count) - copy(value[1:], scope.Contract.Code[chunk*31:endMin]) - index := trieUtils.GetTreeKeyCodeChunk(scope.Contract.Address().Bytes(), uint256.NewInt(chunk)) - interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) - - // in the case of PUSH32, the end data might be two chunks away, - // so also get the middle chunk. There is a boundary condition - // check (endMin > 2) in the case the code is a single PUSH32 - // insctruction, whose immediate are just 0s. - if pushByteSize == 32 && endMin > 2 { - chunk = uint64(endMin-2) / 31 - count = uint64(0) - // Look for the first code byte (i.e. no pushdata) - for ; count < 31 && !scope.Contract.IsCode(chunk*31+count); count++ { - } - value[0] = byte(count) - end := (chunk + 1) * 31 - if end > uint64(len(scope.Contract.Code)) { - end = uint64(len(scope.Contract.Code)) - } - copy(value[1:], scope.Contract.Code[chunk*31:end]) - index := trieUtils.GetTreeKeyCodeChunk(scope.Contract.Address().Bytes(), uint256.NewInt(chunk)) - interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil) - - } - *pc += size return nil, nil } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 68a1f33794e6..9352d342fc1e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -17,15 +17,12 @@ package vm import ( - "errors" "hash" "sync/atomic" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/log" - trieUtils "github.com/ethereum/go-ethereum/trie/utils" - "github.com/holiman/uint256" ) // Config are the configuration options for the Interpreter @@ -194,50 +191,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( logged, pcCopy, gasCopy = false, pc, contract.Gas } - // if the PC ends up in a new "page" of verkleized code, charge the - // associated witness costs. - inWitness := false - var codePage common.Hash - if in.evm.chainRules.IsCancun { - index := trieUtils.GetTreeKeyCodeChunk(contract.Address().Bytes(), uint256.NewInt(pc/31)) - - var value [32]byte - if in.evm.accesses != nil { - codePage, inWitness = in.evm.accesses[common.BytesToHash(index)] - // Return an error if we're in stateless mode - // and the code isn't in the witness. It means - // that if code is read beyond the actual code - // size, pages of 0s need to be added to the - // witness. - if !inWitness { - return nil, errors.New("code chunk missing from proof") - } - copy(value[:], codePage[:]) - } else { - // Calculate the chunk - chunk := pc / 31 - end := (chunk + 1) * 31 - if end >= uint64(len(contract.Code)) { - end = uint64(len(contract.Code)) - } - count := uint64(0) - // Look for the first code byte (i.e. no pushdata) - for ; chunk*31+count < end && count < 31 && !contract.IsCode(chunk*31+count); count++ { - } - value[0] = byte(count) - copy(value[1:], contract.Code[chunk*31:end]) - } - contract.Gas -= in.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, value[:]) + if in.evm.TxContext.Accesses != nil { + // if the PC ends up in a new "page" of verkleized code, charge the + // associated witness costs. + contract.Gas -= touchEachChunksAndChargeGas(pc, 1, contract.Address().Bytes()[:], contract, in.evm.TxContext.Accesses) } - if inWitness { - // Get the op from the tree, skipping the header byte - op = OpCode(codePage[1+pc%31]) - } else { - // If we are in witness mode, then raise an error - op = contract.GetOp(pc) - - } + // TODO how can we tell if we are in stateless mode here and need to get the op from the witness + // If we are in witness mode, then raise an error + op = contract.GetOp(pc) // Get the operation from the jump table and validate the stack to ensure there are // enough stack items available to perform the operation. diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 15250f15a8d0..329ad77cbf83 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -433,7 +433,6 @@ func newFrontierInstructionSet() JumpTable { EXTCODESIZE: { execute: opExtCodeSize, constantGas: params.ExtcodeSizeGasFrontier, - dynamicGas: gasExtCodeSize, minStack: minStack(1, 1), maxStack: maxStack(1, 1), }, @@ -514,7 +513,6 @@ func newFrontierInstructionSet() JumpTable { SLOAD: { execute: opSload, constantGas: params.SloadGasFrontier, - dynamicGas: gasSLoad, minStack: minStack(1, 1), maxStack: maxStack(1, 1), },