mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-09 06:24:27 +00:00
core/vm: move interpreter.ReadOnly check into the opcode implementations (#23970)
* core/vm: Move interpreter.ReadOnly check into the opcode implementations Also remove the same check from the interpreter inner loop. * core/vm: Remove obsolete operation.writes flag * core/vm: Capture fault states in logger Co-authored-by: Martin Holst Swende <martin@swende.se> * core/vm: Remove panic added for testing Co-authored-by: Martin Holst Swende <martin@swende.se>
This commit is contained in:
parent
002be52ae9
commit
bfbb678309
4 changed files with 19 additions and 23 deletions
|
|
@ -514,6 +514,9 @@ func opSload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]b
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
||||||
|
if interpreter.readOnly {
|
||||||
|
return nil, ErrWriteProtection
|
||||||
|
}
|
||||||
loc := callContext.stack.pop()
|
loc := callContext.stack.pop()
|
||||||
val := callContext.stack.pop()
|
val := callContext.stack.pop()
|
||||||
interpreter.evm.StateDB.SetState(callContext.contract.Address(),
|
interpreter.evm.StateDB.SetState(callContext.contract.Address(),
|
||||||
|
|
@ -561,6 +564,9 @@ func opGas(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byt
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
||||||
|
if interpreter.readOnly {
|
||||||
|
return nil, ErrWriteProtection
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
value = callContext.stack.pop()
|
value = callContext.stack.pop()
|
||||||
offset, size = callContext.stack.pop(), callContext.stack.pop()
|
offset, size = callContext.stack.pop(), callContext.stack.pop()
|
||||||
|
|
@ -598,6 +604,9 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
||||||
|
if interpreter.readOnly {
|
||||||
|
return nil, ErrWriteProtection
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
endowment = callContext.stack.pop()
|
endowment = callContext.stack.pop()
|
||||||
offset, size = callContext.stack.pop(), callContext.stack.pop()
|
offset, size = callContext.stack.pop(), callContext.stack.pop()
|
||||||
|
|
@ -642,6 +651,9 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]by
|
||||||
// Get the arguments from the memory.
|
// Get the arguments from the memory.
|
||||||
args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
||||||
|
|
||||||
|
if interpreter.readOnly && !value.IsZero() {
|
||||||
|
return nil, ErrWriteProtection
|
||||||
|
}
|
||||||
if !value.IsZero() {
|
if !value.IsZero() {
|
||||||
gas += params.CallStipend
|
gas += params.CallStipend
|
||||||
}
|
}
|
||||||
|
|
@ -772,6 +784,9 @@ func opStop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]by
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
||||||
|
if interpreter.readOnly {
|
||||||
|
return nil, ErrWriteProtection
|
||||||
|
}
|
||||||
beneficiary := callContext.stack.pop()
|
beneficiary := callContext.stack.pop()
|
||||||
balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address())
|
balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address())
|
||||||
interpreter.evm.StateDB.AddBalance(common.Address(beneficiary.Bytes20()), balance)
|
interpreter.evm.StateDB.AddBalance(common.Address(beneficiary.Bytes20()), balance)
|
||||||
|
|
@ -784,6 +799,9 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([
|
||||||
// make log instruction function
|
// make log instruction function
|
||||||
func makeLog(size int) executionFunc {
|
func makeLog(size int) executionFunc {
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
||||||
|
if interpreter.readOnly {
|
||||||
|
return nil, ErrWriteProtection
|
||||||
|
}
|
||||||
topics := make([]common.Hash, size)
|
topics := make([]common.Hash, size)
|
||||||
stack := callContext.stack
|
stack := callContext.stack
|
||||||
mStart, mSize := stack.pop(), stack.pop()
|
mStart, mSize := stack.pop(), stack.pop()
|
||||||
|
|
|
||||||
|
|
@ -216,17 +216,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
} else if sLen > operation.maxStack {
|
} else if sLen > operation.maxStack {
|
||||||
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
|
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
|
||||||
}
|
}
|
||||||
// If the operation is valid, enforce write restrictions
|
|
||||||
if in.readOnly && in.evm.chainRules.IsByzantium {
|
|
||||||
// If the interpreter is operating in readonly mode, make sure no
|
|
||||||
// state-modifying operation is performed. The 3rd stack item
|
|
||||||
// for a call operation is the value. Transferring value from one
|
|
||||||
// account to the others means the state is modified and should also
|
|
||||||
// return with an error.
|
|
||||||
if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) {
|
|
||||||
return nil, ErrWriteProtection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Static portion of gas
|
// Static portion of gas
|
||||||
cost = operation.constantGas // For tracing
|
cost = operation.constantGas // For tracing
|
||||||
if !contract.UseGas(operation.constantGas) {
|
if !contract.UseGas(operation.constantGas) {
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,6 @@ type operation struct {
|
||||||
|
|
||||||
// memorySize returns the memory size required for the operation
|
// memorySize returns the memory size required for the operation
|
||||||
memorySize memorySizeFunc
|
memorySize memorySizeFunc
|
||||||
|
|
||||||
writes bool // determines whether this a state modifying operation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -104,7 +102,6 @@ func newConstantinopleInstructionSet() JumpTable {
|
||||||
minStack: minStack(4, 1),
|
minStack: minStack(4, 1),
|
||||||
maxStack: maxStack(4, 1),
|
maxStack: maxStack(4, 1),
|
||||||
memorySize: memoryCreate2,
|
memorySize: memoryCreate2,
|
||||||
writes: true,
|
|
||||||
}
|
}
|
||||||
return instructionSet
|
return instructionSet
|
||||||
}
|
}
|
||||||
|
|
@ -492,7 +489,6 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
dynamicGas: gasSStore,
|
dynamicGas: gasSStore,
|
||||||
minStack: minStack(2, 0),
|
minStack: minStack(2, 0),
|
||||||
maxStack: maxStack(2, 0),
|
maxStack: maxStack(2, 0),
|
||||||
writes: true,
|
|
||||||
},
|
},
|
||||||
JUMP: {
|
JUMP: {
|
||||||
execute: opJump,
|
execute: opJump,
|
||||||
|
|
@ -920,7 +916,6 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
minStack: minStack(2, 0),
|
minStack: minStack(2, 0),
|
||||||
maxStack: maxStack(2, 0),
|
maxStack: maxStack(2, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
writes: true,
|
|
||||||
},
|
},
|
||||||
LOG1: {
|
LOG1: {
|
||||||
execute: makeLog(1),
|
execute: makeLog(1),
|
||||||
|
|
@ -928,7 +923,6 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
minStack: minStack(3, 0),
|
minStack: minStack(3, 0),
|
||||||
maxStack: maxStack(3, 0),
|
maxStack: maxStack(3, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
writes: true,
|
|
||||||
},
|
},
|
||||||
LOG2: {
|
LOG2: {
|
||||||
execute: makeLog(2),
|
execute: makeLog(2),
|
||||||
|
|
@ -936,7 +930,6 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
minStack: minStack(4, 0),
|
minStack: minStack(4, 0),
|
||||||
maxStack: maxStack(4, 0),
|
maxStack: maxStack(4, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
writes: true,
|
|
||||||
},
|
},
|
||||||
LOG3: {
|
LOG3: {
|
||||||
execute: makeLog(3),
|
execute: makeLog(3),
|
||||||
|
|
@ -944,7 +937,6 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
minStack: minStack(5, 0),
|
minStack: minStack(5, 0),
|
||||||
maxStack: maxStack(5, 0),
|
maxStack: maxStack(5, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
writes: true,
|
|
||||||
},
|
},
|
||||||
LOG4: {
|
LOG4: {
|
||||||
execute: makeLog(4),
|
execute: makeLog(4),
|
||||||
|
|
@ -952,7 +944,6 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
minStack: minStack(6, 0),
|
minStack: minStack(6, 0),
|
||||||
maxStack: maxStack(6, 0),
|
maxStack: maxStack(6, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
writes: true,
|
|
||||||
},
|
},
|
||||||
CREATE: {
|
CREATE: {
|
||||||
execute: opCreate,
|
execute: opCreate,
|
||||||
|
|
@ -961,7 +952,6 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
minStack: minStack(3, 1),
|
minStack: minStack(3, 1),
|
||||||
maxStack: maxStack(3, 1),
|
maxStack: maxStack(3, 1),
|
||||||
memorySize: memoryCreate,
|
memorySize: memoryCreate,
|
||||||
writes: true,
|
|
||||||
},
|
},
|
||||||
CALL: {
|
CALL: {
|
||||||
execute: opCall,
|
execute: opCall,
|
||||||
|
|
@ -991,7 +981,6 @@ func newFrontierInstructionSet() JumpTable {
|
||||||
dynamicGas: gasSelfdestruct,
|
dynamicGas: gasSelfdestruct,
|
||||||
minStack: minStack(1, 0),
|
minStack: minStack(1, 0),
|
||||||
maxStack: maxStack(1, 0),
|
maxStack: maxStack(1, 0),
|
||||||
writes: true,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
|
||||||
|
|
||||||
// CaptureFault outputs state information on the logger.
|
// CaptureFault outputs state information on the logger.
|
||||||
func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
|
func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
|
||||||
return nil
|
return l.CaptureState(env, pc, op, gas, cost, memory, stack, contract, depth, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is triggered at end of execution.
|
// CaptureEnd is triggered at end of execution.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue