Skip to content

Commit 9393d1f

Browse files
axicholiman
andauthored
core/vm: Move interpreter.ReadOnly check into the opcode implementations (ethereum#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 <[email protected]> * core/vm: Remove panic added for testing Co-authored-by: Martin Holst Swende <[email protected]>
1 parent 1988b47 commit 9393d1f

File tree

4 files changed

+22
-23
lines changed

4 files changed

+22
-23
lines changed

core/vm/instructions.go

+18
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,9 @@ func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
514514
}
515515

516516
func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
517+
if interpreter.readOnly {
518+
return nil, ErrWriteProtection
519+
}
517520
loc := scope.Stack.pop()
518521
val := scope.Stack.pop()
519522
interpreter.evm.StateDB.SetState(scope.Contract.Address(),
@@ -561,6 +564,9 @@ func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
561564
}
562565

563566
func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
567+
if interpreter.readOnly {
568+
return nil, ErrWriteProtection
569+
}
564570
var (
565571
value = scope.Stack.pop()
566572
offset, size = scope.Stack.pop(), scope.Stack.pop()
@@ -604,6 +610,9 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
604610
}
605611

606612
func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
613+
if interpreter.readOnly {
614+
return nil, ErrWriteProtection
615+
}
607616
var (
608617
endowment = scope.Stack.pop()
609618
offset, size = scope.Stack.pop(), scope.Stack.pop()
@@ -653,6 +662,9 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
653662
// Get the arguments from the memory.
654663
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
655664

665+
if interpreter.readOnly && !value.IsZero() {
666+
return nil, ErrWriteProtection
667+
}
656668
var bigVal = big0
657669
//TODO: use uint256.Int instead of converting with toBig()
658670
// By using big0 here, we save an alloc for the most common case (non-ether-transferring contract calls),
@@ -794,6 +806,9 @@ func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
794806
}
795807

796808
func opSuicide(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
809+
if interpreter.readOnly {
810+
return nil, ErrWriteProtection
811+
}
797812
beneficiary := scope.Stack.pop()
798813
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
799814
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
@@ -810,6 +825,9 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
810825
// make log instruction function
811826
func makeLog(size int) executionFunc {
812827
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
828+
if interpreter.readOnly {
829+
return nil, ErrWriteProtection
830+
}
813831
topics := make([]common.Hash, size)
814832
stack := scope.Stack
815833
mStart, mSize := stack.pop(), stack.pop()

core/vm/interpreter.go

-11
Original file line numberDiff line numberDiff line change
@@ -202,17 +202,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
202202
} else if sLen > operation.maxStack {
203203
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
204204
}
205-
// If the operation is valid, enforce write restrictions
206-
if in.readOnly && in.evm.chainRules.IsByzantium {
207-
// If the interpreter is operating in readonly mode, make sure no
208-
// state-modifying operation is performed. The 3rd stack item
209-
// for a call operation is the value. Transferring value from one
210-
// account to the others means the state is modified and should also
211-
// return with an error.
212-
if operation.writes || (op == CALL && stack.Back(2).Sign() != 0) {
213-
return nil, ErrWriteProtection
214-
}
215-
}
216205
// Static portion of gas
217206
cost = operation.constantGas // For tracing
218207
if !contract.UseGas(operation.constantGas) {

core/vm/jump_table.go

-11
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ type operation struct {
4040

4141
// memorySize returns the memory size required for the operation
4242
memorySize memorySizeFunc
43-
44-
writes bool // determines whether this a state modifying operation
4543
}
4644

4745
var (
@@ -123,7 +121,6 @@ func newConstantinopleInstructionSet() JumpTable {
123121
minStack: minStack(4, 1),
124122
maxStack: maxStack(4, 1),
125123
memorySize: memoryCreate2,
126-
writes: true,
127124
}
128125
return instructionSet
129126
}
@@ -511,7 +508,6 @@ func newFrontierInstructionSet() JumpTable {
511508
dynamicGas: gasSStore,
512509
minStack: minStack(2, 0),
513510
maxStack: maxStack(2, 0),
514-
writes: true,
515511
},
516512
JUMP: {
517513
execute: opJump,
@@ -939,39 +935,34 @@ func newFrontierInstructionSet() JumpTable {
939935
minStack: minStack(2, 0),
940936
maxStack: maxStack(2, 0),
941937
memorySize: memoryLog,
942-
writes: true,
943938
},
944939
LOG1: {
945940
execute: makeLog(1),
946941
dynamicGas: makeGasLog(1),
947942
minStack: minStack(3, 0),
948943
maxStack: maxStack(3, 0),
949944
memorySize: memoryLog,
950-
writes: true,
951945
},
952946
LOG2: {
953947
execute: makeLog(2),
954948
dynamicGas: makeGasLog(2),
955949
minStack: minStack(4, 0),
956950
maxStack: maxStack(4, 0),
957951
memorySize: memoryLog,
958-
writes: true,
959952
},
960953
LOG3: {
961954
execute: makeLog(3),
962955
dynamicGas: makeGasLog(3),
963956
minStack: minStack(5, 0),
964957
maxStack: maxStack(5, 0),
965958
memorySize: memoryLog,
966-
writes: true,
967959
},
968960
LOG4: {
969961
execute: makeLog(4),
970962
dynamicGas: makeGasLog(4),
971963
minStack: minStack(6, 0),
972964
maxStack: maxStack(6, 0),
973965
memorySize: memoryLog,
974-
writes: true,
975966
},
976967
CREATE: {
977968
execute: opCreate,
@@ -980,7 +971,6 @@ func newFrontierInstructionSet() JumpTable {
980971
minStack: minStack(3, 1),
981972
maxStack: maxStack(3, 1),
982973
memorySize: memoryCreate,
983-
writes: true,
984974
},
985975
CALL: {
986976
execute: opCall,
@@ -1010,7 +1000,6 @@ func newFrontierInstructionSet() JumpTable {
10101000
dynamicGas: gasSelfdestruct,
10111001
minStack: minStack(1, 0),
10121002
maxStack: maxStack(1, 0),
1013-
writes: true,
10141003
},
10151004
}
10161005
}

eth/tracers/logger/logger_json.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ func (l *JSONLogger) CaptureStart(env *vm.EVM, from, to common.Address, create b
4747
l.env = env
4848
}
4949

50-
func (l *JSONLogger) CaptureFault(uint64, vm.OpCode, uint64, uint64, *vm.ScopeContext, int, error) {}
50+
func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) {
51+
// TODO: Add rData to this interface as well
52+
l.CaptureState(pc, op, gas, cost, scope, nil, depth, err)
53+
}
5154

5255
// CaptureState outputs state information on the logger.
5356
func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {

0 commit comments

Comments
 (0)