-
Notifications
You must be signed in to change notification settings - Fork 13
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
Verkle EXTCODECOPY implementation #55
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you actually need to do the analysis here, nor to charge the gas at this point, or to know what in the code is pushdata and what is code. As long as you know the start offset, you can divide it into 31-byte chunks. I might be missing something, so we can have a call about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok, now I get it: one needs to know what the value of the pushdata offset it. Hmmm.... |
||
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) | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why add an extra parameter here? You could add a
Code()
method toAnalyzedContract
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because then I will need to add a
Code()
method toContract
for it to beAnalyzedContract
which is redundant b/cContract.Code
is public. or create a separate object that wrapsContract
and implementsCode()
, pass that object every time I calltouchEachChunksAndChargeGas
.The former option isn't too bad but it's also kind of awkward.