diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 4f181a6e69..ccc3e383b2 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -514,6 +514,9 @@ func opSload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]b } func opSstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } loc := callContext.stack.pop() val := callContext.stack.pop() 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) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } var ( value = 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) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } var ( endowment = 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. args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + if interpreter.readOnly && !value.IsZero() { + return nil, ErrWriteProtection + } if !value.IsZero() { 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) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } beneficiary := callContext.stack.pop() balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address()) 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 func makeLog(size int) executionFunc { return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } topics := make([]common.Hash, size) stack := callContext.stack mStart, mSize := stack.pop(), stack.pop() diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 582957262b..eabf1dce19 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -216,17 +216,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } else if sLen > 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 cost = operation.constantGas // For tracing if !contract.UseGas(operation.constantGas) { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index a5b5445d80..c1b9fd8470 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -40,8 +40,6 @@ type operation struct { // memorySize returns the memory size required for the operation memorySize memorySizeFunc - - writes bool // determines whether this a state modifying operation } var ( @@ -104,7 +102,6 @@ func newConstantinopleInstructionSet() JumpTable { minStack: minStack(4, 1), maxStack: maxStack(4, 1), memorySize: memoryCreate2, - writes: true, } return instructionSet } @@ -492,7 +489,6 @@ func newFrontierInstructionSet() JumpTable { dynamicGas: gasSStore, minStack: minStack(2, 0), maxStack: maxStack(2, 0), - writes: true, }, JUMP: { execute: opJump, @@ -920,7 +916,6 @@ func newFrontierInstructionSet() JumpTable { minStack: minStack(2, 0), maxStack: maxStack(2, 0), memorySize: memoryLog, - writes: true, }, LOG1: { execute: makeLog(1), @@ -928,7 +923,6 @@ func newFrontierInstructionSet() JumpTable { minStack: minStack(3, 0), maxStack: maxStack(3, 0), memorySize: memoryLog, - writes: true, }, LOG2: { execute: makeLog(2), @@ -936,7 +930,6 @@ func newFrontierInstructionSet() JumpTable { minStack: minStack(4, 0), maxStack: maxStack(4, 0), memorySize: memoryLog, - writes: true, }, LOG3: { execute: makeLog(3), @@ -944,7 +937,6 @@ func newFrontierInstructionSet() JumpTable { minStack: minStack(5, 0), maxStack: maxStack(5, 0), memorySize: memoryLog, - writes: true, }, LOG4: { execute: makeLog(4), @@ -952,7 +944,6 @@ func newFrontierInstructionSet() JumpTable { minStack: minStack(6, 0), maxStack: maxStack(6, 0), memorySize: memoryLog, - writes: true, }, CREATE: { execute: opCreate, @@ -961,7 +952,6 @@ func newFrontierInstructionSet() JumpTable { minStack: minStack(3, 1), maxStack: maxStack(3, 1), memorySize: memoryCreate, - writes: true, }, CALL: { execute: opCall, @@ -991,7 +981,6 @@ func newFrontierInstructionSet() JumpTable { dynamicGas: gasSelfdestruct, minStack: minStack(1, 0), maxStack: maxStack(1, 0), - writes: true, }, } } diff --git a/core/vm/logger_json.go b/core/vm/logger_json.go index 4fbd4fd75f..4a63120a3d 100644 --- a/core/vm/logger_json.go +++ b/core/vm/logger_json.go @@ -74,7 +74,7 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint // 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 { - return nil + return l.CaptureState(env, pc, op, gas, cost, memory, stack, contract, depth, err) } // CaptureEnd is triggered at end of execution.