Skip to content

Commit 8a392f5

Browse files
committed
add activation flag for bulk mem opcodes
1 parent b5b8d65 commit 8a392f5

18 files changed

+156
-0
lines changed

executor/executorInstance.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Instance interface {
2020
MemGrow(pages uint32) error
2121
MemDump() []byte
2222
IsFunctionImported(name string) bool
23+
IsOpcodeUsed(opcode OpcodeUsed) bool
2324
IsInterfaceNil() bool
2425
Reset() bool
2526
SetVMHooksPtr(vmHooksPtr uintptr)

executor/executorUsedOpcode.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package executor
2+
3+
type OpcodeUsed uint32
4+
5+
const (
6+
OpcodeUsedMemoryCopy OpcodeUsed = iota
7+
OpcodeUsedMemoryFill
8+
)

executor/wrapper/wrapperInstance.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ func (inst *WrapperInstance) IsFunctionImported(name string) bool {
131131
return result
132132
}
133133

134+
// IsOpcodeUsed wraps the call to the underlying instance.
135+
func (inst *WrapperInstance) IsOpcodeUsed(opcode executor.OpcodeUsed) bool {
136+
result := inst.wrappedInstance.IsOpcodeUsed(opcode)
137+
return result
138+
}
139+
134140
// IsInterfaceNil returns true if there is no value under the interface.
135141
func (inst *WrapperInstance) IsInterfaceNil() bool {
136142
return inst == nil

mock/context/instanceMock.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type InstanceMock struct {
2020
Exports map[string]string
2121
DefaultErrors map[string]error
2222
Methods map[string]mockMethod
23+
OpcodeUsed map[executor.OpcodeUsed]bool
2324
Points uint64
2425
Data executor.VMHooks
2526
GasLimit uint64
@@ -183,6 +184,12 @@ func (instance *InstanceMock) IsFunctionImported(name string) bool {
183184
return ok
184185
}
185186

187+
// IsOpcodeUsed mocked method
188+
func (instance *InstanceMock) IsOpcodeUsed(opcode executor.OpcodeUsed) bool {
189+
used, ok := instance.OpcodeUsed[opcode]
190+
return ok && used
191+
}
192+
186193
// GetMockInstance gets the mock instance from the runtime of the provided host
187194
func GetMockInstance(host vmhost.VMHost) *InstanceMock {
188195
instance := host.Runtime().GetInstance().(*InstanceMock)

mock/context/runtimeContextMock.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,11 @@ func (r *RuntimeContextMock) IsFunctionImported(_ string) bool {
332332
return true
333333
}
334334

335+
// IsOpcodeUsed mocked method
336+
func (r *RuntimeContextMock) IsOpcodeUsed(_ executor.OpcodeUsed) bool {
337+
return false
338+
}
339+
335340
// AddError mocked method
336341
func (r *RuntimeContextMock) AddError(_ error, _ ...string) {
337342
}

mock/context/runtimeContextWrapper.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ type RuntimeContextWrapper struct {
6868
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
6969
IsFunctionImportedFunc func(name string) bool
7070
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
71+
IsOpcodeUsedFunc func(opcode executor.OpcodeUsed) bool
72+
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
7173
ReadOnlyFunc func() bool
7274
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
7375
SetReadOnlyFunc func(readOnly bool)
@@ -216,6 +218,10 @@ func NewRuntimeContextWrapper(inputRuntimeContext *vmhost.RuntimeContext) *Runti
216218
return runtimeWrapper.runtimeContext.IsFunctionImported(name)
217219
}
218220

221+
runtimeWrapper.IsOpcodeUsedFunc = func(opcode executor.OpcodeUsed) bool {
222+
return runtimeWrapper.runtimeContext.IsOpcodeUsed(opcode)
223+
}
224+
219225
runtimeWrapper.ReadOnlyFunc = func() bool {
220226
return runtimeWrapper.runtimeContext.ReadOnly()
221227
}
@@ -419,6 +425,11 @@ func (contextWrapper *RuntimeContextWrapper) IsFunctionImported(name string) boo
419425
return contextWrapper.IsFunctionImportedFunc(name)
420426
}
421427

428+
// IsOpcodeUsed calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
429+
func (contextWrapper *RuntimeContextWrapper) IsOpcodeUsed(opcode executor.OpcodeUsed) bool {
430+
return contextWrapper.IsOpcodeUsedFunc(opcode)
431+
}
432+
422433
// ReadOnly calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
423434
func (contextWrapper *RuntimeContextWrapper) ReadOnly() bool {
424435
return contextWrapper.ReadOnlyFunc()

mock/mockery/Instance.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,24 @@ func (_m *MockInstance) IsFunctionImported(name string) bool {
240240
return r0
241241
}
242242

243+
// IsOpcodeUsed provides a mock function with given fields: opcode
244+
func (_m *MockInstance) IsOpcodeUsed(opcode executor.OpcodeUsed) bool {
245+
ret := _m.Called(opcode)
246+
247+
if len(ret) == 0 {
248+
return false
249+
}
250+
251+
var r0 bool
252+
if rf, ok := ret.Get(0).(func(executor.OpcodeUsed) bool); ok {
253+
r0 = rf(opcode)
254+
} else {
255+
r0 = ret.Get(0).(bool)
256+
}
257+
258+
return r0
259+
}
260+
243261
// IsInterfaceNil provides a mock function with no fields
244262
func (_m *MockInstance) IsInterfaceNil() bool {
245263
ret := _m.Called()

mock/mockery/RuntimeContext.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,24 @@ func (_m *MockRuntimeContext) IsFunctionImported(name string) bool {
562562
return r0
563563
}
564564

565+
// IsOpcodeUsed provides a mock function with given fields: opcode
566+
func (_m *MockRuntimeContext) IsOpcodeUsed(opcode executor.OpcodeUsed) bool {
567+
ret := _m.Called(opcode)
568+
569+
if len(ret) == 0 {
570+
return false
571+
}
572+
573+
var r0 bool
574+
if rf, ok := ret.Get(0).(func(executor.OpcodeUsed) bool); ok {
575+
r0 = rf(opcode)
576+
} else {
577+
r0 = ret.Get(0).(bool)
578+
}
579+
580+
return r0
581+
}
582+
565583
// IsReservedFunctionName provides a mock function with given fields: functionName
566584
func (_m *MockRuntimeContext) IsReservedFunctionName(functionName string) bool {
567585
ret := _m.Called(functionName)

vmhost/contexts/runtime.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,14 @@ func (context *runtimeContext) VerifyContractCode() error {
704704
}
705705
}
706706

707+
if !enableEpochsHandler.IsFlagEnabled(vmhost.AsyncV3Flag) {
708+
err = context.checkIfContainsBulkMemoryOpcodes()
709+
if err != nil {
710+
logRuntime.Trace("verify contract code", "error", err)
711+
return err
712+
}
713+
}
714+
707715
logRuntime.Trace("verified contract code")
708716

709717
return nil
@@ -727,6 +735,18 @@ func (context *runtimeContext) checkIfContainsBarnardOpcodes() error {
727735
return nil
728736
}
729737

738+
func (context *runtimeContext) checkIfContainsBulkMemoryOpcodes() error {
739+
if context.iTracker.Instance().IsOpcodeUsed(executor.OpcodeUsedMemoryCopy) {
740+
return vmhost.ErrContractInvalid
741+
}
742+
743+
if context.iTracker.Instance().IsOpcodeUsed(executor.OpcodeUsedMemoryFill) {
744+
return vmhost.ErrContractInvalid
745+
}
746+
747+
return nil
748+
}
749+
730750
// UseGasBoundedShouldFailExecution returns true when flag activated
731751
func (context *runtimeContext) UseGasBoundedShouldFailExecution() bool {
732752
return context.host.EnableEpochsHandler().IsFlagEnabled(vmhost.UseGasBoundedShouldFailExecutionFlag)
@@ -831,6 +851,11 @@ func (context *runtimeContext) IsFunctionImported(name string) bool {
831851
return context.iTracker.Instance().IsFunctionImported(name)
832852
}
833853

854+
// IsOpcodeUsed returns true if the WASM module uses the specified opcode.
855+
func (context *runtimeContext) IsOpcodeUsed(opcode executor.OpcodeUsed) bool {
856+
return context.iTracker.Instance().IsOpcodeUsed(opcode)
857+
}
858+
834859
// AddError adds an error to the global error list on runtime context
835860
func (context *runtimeContext) AddError(err error, otherInfo ...string) {
836861
if err == nil {

vmhost/hosttest/forbidden_opcodes_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,38 @@ func TestBarnardOpcodesActivation(t *testing.T) {
6161
ContractInvalid()
6262
})
6363
}
64+
65+
func TestBulkMemoryOpcodesActivation(t *testing.T) {
66+
wasmModules := []string{"memory-copy", "memory-fill"}
67+
68+
for _, moduleName := range wasmModules {
69+
testcommon.BuildInstanceCreatorTest(t).
70+
WithInput(testcommon.CreateTestContractCreateInputBuilder().
71+
WithGasProvided(100000000).
72+
WithContractCode(testcommon.GetTestSCCodeModule("forbidden-opcodes/"+moduleName, moduleName, "../../")).
73+
Build()).
74+
WithEnableEpochsHandler(&worldmock.EnableEpochsHandlerStub{
75+
IsFlagEnabledCalled: func(flag core.EnableEpochFlag) bool {
76+
return flag != vmhost.AsyncV3Flag
77+
},
78+
}).
79+
AndAssertResults(func(stubBlockchainHook *contextmock.BlockchainHookStub, verify *testcommon.VMOutputVerifier) {
80+
verify.
81+
ContractInvalid()
82+
})
83+
84+
testcommon.BuildInstanceCreatorTest(t).
85+
WithInput(testcommon.CreateTestContractCreateInputBuilder().
86+
WithGasProvided(100000000).
87+
WithContractCode(testcommon.GetTestSCCodeModule("forbidden-opcodes/"+moduleName, moduleName, "../../")).
88+
Build()).
89+
WithEnableEpochsHandler(&worldmock.EnableEpochsHandlerStub{
90+
IsFlagEnabledCalled: func(flag core.EnableEpochFlag) bool {
91+
return true
92+
},
93+
}).
94+
AndAssertResults(func(stubBlockchainHook *contextmock.BlockchainHookStub, verify *testcommon.VMOutputVerifier) {
95+
verify.FunctionNotFound()
96+
})
97+
}
98+
}

0 commit comments

Comments
 (0)