core/vm: 64 bit memory and gas calculations (#19210)
* core/vm: remove function call for stack validation from evm runloop * core/vm: separate gas calc into static + dynamic * core/vm: optimize push1 * core/vm: reuse pooled bigints for ADDRESS, ORIGIN and CALLER * core/vm: use generic error message for jump/jumpi, to avoid string interpolation * testdata: fix tests for new error message * core/vm: use 64-bit memory calculations * core/vm: fix error in memory calculation * core/vm: address review concerns * core/vm: avoid unnecessary use of big.Int:BitLen()
This commit is contained in:
committed by
Péter Szilágyi
parent
da5de012c3
commit
7504dbd6eb
@ -18,7 +18,6 @@ package vm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@ -35,6 +34,7 @@ var (
|
||||
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
||||
errExecutionReverted = errors.New("evm: execution reverted")
|
||||
errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded")
|
||||
errInvalidJump = errors.New("evm: invalid jump destination")
|
||||
)
|
||||
|
||||
func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
@ -405,7 +405,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
|
||||
}
|
||||
|
||||
func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(contract.Address().Big())
|
||||
stack.push(interpreter.intPool.get().SetBytes(contract.Address().Bytes()))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -416,12 +416,12 @@ func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
|
||||
}
|
||||
|
||||
func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.evm.Origin.Big())
|
||||
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes()))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(contract.Caller().Big())
|
||||
stack.push(interpreter.intPool.get().SetBytes(contract.Caller().Bytes()))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -467,7 +467,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac
|
||||
)
|
||||
defer interpreter.intPool.put(memOffset, dataOffset, length, end)
|
||||
|
||||
if end.BitLen() > 64 || uint64(len(interpreter.returnData)) < end.Uint64() {
|
||||
if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() {
|
||||
return nil, errReturnDataOutOfBounds
|
||||
}
|
||||
memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()])
|
||||
@ -572,7 +572,7 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, me
|
||||
}
|
||||
|
||||
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
stack.push(interpreter.evm.Coinbase.Big())
|
||||
stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes()))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -645,8 +645,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
|
||||
func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
pos := stack.pop()
|
||||
if !contract.validJumpdest(pos) {
|
||||
nop := contract.GetOp(pos.Uint64())
|
||||
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
|
||||
return nil, errInvalidJump
|
||||
}
|
||||
*pc = pos.Uint64()
|
||||
|
||||
@ -658,8 +657,7 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
|
||||
pos, cond := stack.pop(), stack.pop()
|
||||
if cond.Sign() != 0 {
|
||||
if !contract.validJumpdest(pos) {
|
||||
nop := contract.GetOp(pos.Uint64())
|
||||
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
|
||||
return nil, errInvalidJump
|
||||
}
|
||||
*pc = pos.Uint64()
|
||||
} else {
|
||||
@ -711,7 +709,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
|
||||
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else {
|
||||
stack.push(addr.Big())
|
||||
stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
interpreter.intPool.put(value, offset, size)
|
||||
@ -739,7 +737,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
|
||||
if suberr != nil {
|
||||
stack.push(interpreter.intPool.getZero())
|
||||
} else {
|
||||
stack.push(addr.Big())
|
||||
stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
|
||||
}
|
||||
contract.Gas += returnGas
|
||||
interpreter.intPool.put(endowment, offset, size, salt)
|
||||
@ -912,6 +910,21 @@ func makeLog(size int) executionFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// opPush1 is a specialized version of pushN
|
||||
func opPush1(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
var (
|
||||
codeLen = uint64(len(contract.Code))
|
||||
integer = interpreter.intPool.get()
|
||||
)
|
||||
*pc += 1
|
||||
if *pc < codeLen {
|
||||
stack.push(integer.SetUint64(uint64(contract.Code[*pc])))
|
||||
} else {
|
||||
stack.push(integer.SetUint64(0))
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// make push instruction function
|
||||
func makePush(size uint64, pushByteSize int) executionFunc {
|
||||
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||
|
Reference in New Issue
Block a user