Skip to content

Commit

Permalink
Save code section bounds in Contract instead of EOF header
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed Nov 8, 2022
1 parent 4913c1d commit d5cf7a2
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 41 deletions.
6 changes: 3 additions & 3 deletions core/vm/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,16 @@ func codeBitmap(c *Contract) bitvec {
// The bitmap is 4 bytes longer than necessary, in case the code
// ends with a PUSH32, the algorithm will push zeroes onto the
// bitvector outside the bounds of the actual code.
bits := make(bitvec, c.CodeSize()/8+1+4)
bits := make(bitvec, c.CodeSize/8+1+4)
return codeBitmapInternal(c, bits)
}

// codeBitmapInternal is the internal implementation of codeBitmap.
// It exists for the purpose of being able to run benchmark tests
// without dynamic allocations affecting the results.
func codeBitmapInternal(c *Contract, bits bitvec) bitvec {
codeBegin := c.CodeBeginOffset()
for pc := uint64(0); pc < c.CodeSize(); {
codeBegin := c.CodeBeginOffset
for pc := uint64(0); pc < c.CodeSize; {
op := OpCode(c.Code[codeBegin+pc])
pc++
if int8(op) < int8(PUSH1) { // If not PUSH (the int8(op) > int(PUSH32) is always false).
Expand Down
52 changes: 18 additions & 34 deletions core/vm/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ type Contract struct {
caller ContractRef
self ContractRef

header EOF1Header
CodeBeginOffset uint64 // starting offset of the code section if EOF or 0 if legacy
CodeSize uint64 // size of the code section if EOF or bytecode size if legacy

jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis.
analysis bitvec // Locally cached result of JUMPDEST analysis
Expand Down Expand Up @@ -90,7 +91,7 @@ func (c *Contract) validJumpdest(dest *uint256.Int) bool {
udest, overflow := dest.Uint64WithOverflow()
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
if overflow || udest >= c.CodeSize() {
if overflow || udest >= c.CodeSize {
return false
}
// Only JUMPDESTs allowed for destinations
Expand Down Expand Up @@ -148,8 +149,8 @@ func (c *Contract) AsDelegate() *Contract {
// GetOp returns the n'th element in the contract's byte array
// n is offset inside code section in case of EOF contract
func (c *Contract) GetOp(n uint64) OpCode {
if n < c.CodeSize() {
return OpCode(c.Code[c.CodeBeginOffset()+n])
if n < c.CodeSize {
return OpCode(c.Code[c.CodeBeginOffset+n])
}

return STOP
Expand Down Expand Up @@ -182,34 +183,19 @@ func (c *Contract) Value() *big.Int {
return c.value
}

// IsLegacy returns true if contract is not EOF
func (c *Contract) IsLegacy() bool {
// getCodeBounds returns beginning offset and size of the code section if EOF
// or 0 and bytecode length if legacy
func getCodeBounds(container []byte, header *EOF1Header) (begin uint64, size uint64) {
// EOF1 doesn't allow contracts without code section
return c.header.codeSize == 0
}

// CodeBeginOffset returns starting offset of the code section
func (c *Contract) CodeBeginOffset() uint64 {
if c.IsLegacy() {
return 0
}
return c.header.CodeBeginOffset()
}

// CodeEndOffset returns offset of the code section end
func (c *Contract) CodeEndOffset() uint64 {
if c.IsLegacy() {
return uint64(len(c.Code))
}
return c.header.CodeEndOffset()
}

// CodeSize returns the size of the code (if legacy) or code section (if EOF)
func (c *Contract) CodeSize() uint64 {
if c.IsLegacy() {
return uint64(len(c.Code))
isLegacy := (header.codeSize == 0)
if isLegacy {
begin = 0
size = uint64(len(container))
} else {
begin = header.CodeBeginOffset()
size = uint64(header.codeSize)
}
return uint64(c.header.codeSize)
return
}

// SetCallCode sets the code of the contract and address of the backing data
Expand All @@ -219,8 +205,7 @@ func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []by
c.CodeHash = hash
c.CodeAddr = addr

c.header.codeSize = header.codeSize
c.header.dataSize = header.dataSize
c.CodeBeginOffset, c.CodeSize = getCodeBounds(code, header)
}

// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash.
Expand All @@ -230,6 +215,5 @@ func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAn
c.CodeHash = codeAndHash.hash
c.CodeAddr = addr

c.header.codeSize = header.codeSize
c.header.dataSize = header.dataSize
c.CodeBeginOffset, c.CodeSize = getCodeBounds(codeAndHash.code, header)
}
8 changes: 4 additions & 4 deletions core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -867,11 +867,11 @@ func makeLog(size int) executionFunc {
// opPush1 is a specialized version of pushN
func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
var (
codeEnd = scope.Contract.CodeEndOffset()
codeEnd = scope.Contract.CodeBeginOffset + scope.Contract.CodeSize
integer = new(uint256.Int)
)
*pc += 1
dataPos := scope.Contract.CodeBeginOffset() + *pc
dataPos := scope.Contract.CodeBeginOffset + *pc
if dataPos < codeEnd {
scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[dataPos])))
} else {
Expand All @@ -883,10 +883,10 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
// make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
codeEnd := int(scope.Contract.CodeEndOffset())
codeEnd := int(scope.Contract.CodeBeginOffset + scope.Contract.CodeSize)

startMin := codeEnd
pcAbsolute := scope.Contract.CodeBeginOffset() + *pc
pcAbsolute := scope.Contract.CodeBeginOffset + *pc
if int(pcAbsolute+1) < startMin {
startMin = int(pcAbsolute + 1)
}
Expand Down
1 change: 1 addition & 0 deletions eth/tracers/js/tracer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
if contractCode != nil {
contract.Code = contractCode
}
contract.CodeSize = uint64(len(contract.Code))

tracer.CaptureTxStart(gasLimit)
tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
Expand Down
1 change: 1 addition & 0 deletions eth/tracers/logger/logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func TestStoreCapture(t *testing.T) {
contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000)
)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
contract.CodeSize = uint64(len(contract.Code))
var index common.Hash
logger.CaptureStart(env, common.Address{}, contract.Address(), false, nil, 0, nil)
_, err := env.Interpreter().Run(contract, []byte{}, false)
Expand Down

0 comments on commit d5cf7a2

Please sign in to comment.