Verkle EXTCODECOPY implementation (#55)
* core/vm: verkle extcodecopy naive way (do jumpdest analysis on target contract every EXTCODECOPY) * no double-charge * address edge-case in touchEachChunksAndChargeGas * simplify line Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com>
This commit is contained in:
@ -19,7 +19,6 @@ package vm
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
trieUtils "github.com/ethereum/go-ethereum/trie/utils"
|
||||
"github.com/holiman/uint256"
|
||||
@ -373,21 +372,21 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||
|
||||
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
||||
if interpreter.evm.Accesses != nil {
|
||||
touchEachChunksAndChargeGas(copyOffset, nonPaddedCopyLength, scope.Contract.Address().Bytes()[:], scope.Contract, interpreter.evm.Accesses)
|
||||
touchEachChunksAndChargeGas(copyOffset, nonPaddedCopyLength, scope.Contract.Address().Bytes()[:], scope.Contract.Code, scope.Contract, interpreter.evm.Accesses)
|
||||
}
|
||||
scope.Memory.Set(memOffset.Uint64(), uint64(len(paddedCodeCopy)), paddedCodeCopy)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
func touchEachChunksAndChargeGas(offset, size uint64, address []byte, code []byte, contract AnalyzedContract, accesses *types.AccessWitness) uint64 {
|
||||
// note that in the case where the copied code is outside the range of the
|
||||
// contract code but touches the last leaf with contract code in it,
|
||||
// we don't include the last leaf of code in the AccessWitness. The
|
||||
// reason that we do not need the last leaf is the account's code size
|
||||
// is already in the AccessWitness so a stateless verifier can see that
|
||||
// the code from the last leaf is not needed.
|
||||
if contract != nil && (size == 0 || offset > uint64(len(contract.Code))) {
|
||||
if contract != nil && (size == 0 || offset > uint64(len(code))) {
|
||||
return 0
|
||||
}
|
||||
var (
|
||||
@ -397,17 +396,13 @@ func touchEachChunksAndChargeGas(offset, size uint64, address []byte, contract *
|
||||
startOffset uint64
|
||||
endOffset uint64
|
||||
numLeaves uint64
|
||||
code []byte
|
||||
index [32]byte
|
||||
)
|
||||
if contract != nil {
|
||||
code = contract.Code[:]
|
||||
}
|
||||
// startLeafOffset, endLeafOffset is the evm code offset of the first byte in the first leaf touched
|
||||
// and the evm code offset of the last byte in the last leaf touched
|
||||
startOffset = offset - (offset % 31)
|
||||
if contract != nil && startOffset+size > uint64(len(contract.Code)) {
|
||||
endOffset = uint64(len(contract.Code))
|
||||
if contract != nil && startOffset+size > uint64(len(code)) {
|
||||
endOffset = uint64(len(code))
|
||||
} else {
|
||||
endOffset = startOffset + size
|
||||
}
|
||||
@ -431,11 +426,11 @@ func touchEachChunksAndChargeGas(offset, size uint64, address []byte, contract *
|
||||
index[31] = subIndex
|
||||
|
||||
var value []byte
|
||||
if contract != nil {
|
||||
if len(code) > 0 {
|
||||
// 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 ; firstPushOffset < 31 && firstPushOffset+uint64(i)*31 < uint64(len(contract.Code)) && !contract.IsCode(uint64(i)*31+firstPushOffset); firstPushOffset++ {
|
||||
for ; firstPushOffset < 31 && firstPushOffset+uint64(i)*31 < uint64(len(code)) && !contract.IsCode(uint64(i)*31+firstPushOffset); firstPushOffset++ {
|
||||
}
|
||||
curEnd := (uint64(i) + 1) * 31
|
||||
if curEnd > endOffset {
|
||||
@ -472,7 +467,11 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||
}
|
||||
addr := common.Address(a.Bytes20())
|
||||
if interpreter.evm.Accesses != nil {
|
||||
log.Warn("setting witness values for extcodecopy is not currently implemented")
|
||||
code := interpreter.evm.StateDB.GetCode(addr)
|
||||
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
|
||||
cb := codeBitmap(code)
|
||||
touchEachChunksAndChargeGas(copyOffset, nonPaddedCopyLength, addr[:], code, &cb, interpreter.evm.Accesses)
|
||||
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), paddedCodeCopy)
|
||||
} else {
|
||||
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
|
||||
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
@ -977,7 +976,7 @@ func makePush(size uint64, pushByteSize int) executionFunc {
|
||||
}
|
||||
|
||||
if interpreter.evm.Accesses != nil {
|
||||
statelessGas := touchEachChunksAndChargeGas(uint64(startMin), uint64(pushByteSize), scope.Contract.Address().Bytes()[:], scope.Contract, interpreter.evm.Accesses)
|
||||
statelessGas := touchEachChunksAndChargeGas(uint64(startMin), uint64(pushByteSize), scope.Contract.Address().Bytes()[:], scope.Contract.Code, scope.Contract, interpreter.evm.Accesses)
|
||||
scope.Contract.UseGas(statelessGas)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user