Skip to content

Commit 46d5b71

Browse files
authored
Merge pull request #962 from multiversx/unsafe-operations-code
initial implementation of unSafe mode
2 parents 9fe7642 + dd2861b commit 46d5b71

34 files changed

+904
-399
lines changed

executor/vmHooks.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

executor/wrapper/wrapperVMHooks.go

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mock/context/executorMockFunc.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mock/context/runtimeContextMock.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type RuntimeContextMock struct {
1919
CallFunction string
2020
VMType []byte
2121
ReadOnlyFlag bool
22+
UnsafeModeFlag bool
2223
VerifyCode bool
2324
CurrentBreakpointValue vmhost.BreakpointValue
2425
PointsUsed uint64
@@ -314,6 +315,16 @@ func (r *RuntimeContextMock) UseGasBoundedShouldFailExecution() bool {
314315
return true
315316
}
316317

318+
// IsUnsafeMode mocked method
319+
func (r *RuntimeContextMock) IsUnsafeMode() bool {
320+
return r.UnsafeModeFlag
321+
}
322+
323+
// SetUnsafeMode mocked method
324+
func (r *RuntimeContextMock) SetUnsafeMode(unsafeMode bool) {
325+
r.UnsafeModeFlag = unsafeMode
326+
}
327+
317328
// FailExecution mocked method
318329
func (r *RuntimeContextMock) FailExecution(_ error) {
319330
}

mock/context/runtimeContextWrapper.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ type RuntimeContextWrapper struct {
7272
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
7373
SetReadOnlyFunc func(readOnly bool)
7474
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
75+
IsUnsafeModeFunc func() bool
76+
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
77+
SetUnsafeModeFunc func(readOnly bool)
78+
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
7579
StartWasmerInstanceFunc func(contract []byte, gasLimit uint64, newCode bool) error
7680
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
7781
ClearWarmInstanceCacheFunc func()
@@ -224,6 +228,14 @@ func NewRuntimeContextWrapper(inputRuntimeContext *vmhost.RuntimeContext) *Runti
224228
runtimeWrapper.runtimeContext.SetReadOnly(readOnly)
225229
}
226230

231+
runtimeWrapper.IsUnsafeModeFunc = func() bool {
232+
return runtimeWrapper.runtimeContext.IsUnsafeMode()
233+
}
234+
235+
runtimeWrapper.SetUnsafeModeFunc = func(unSafe bool) {
236+
runtimeWrapper.runtimeContext.SetUnsafeMode(unSafe)
237+
}
238+
227239
runtimeWrapper.StartWasmerInstanceFunc = func(contract []byte, gasLimit uint64, newCode bool) error {
228240
return runtimeWrapper.runtimeContext.StartWasmerInstance(contract, gasLimit, newCode)
229241
}
@@ -429,6 +441,16 @@ func (contextWrapper *RuntimeContextWrapper) SetReadOnly(readOnly bool) {
429441
contextWrapper.SetReadOnlyFunc(readOnly)
430442
}
431443

444+
// IsUnsafeMode calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
445+
func (contextWrapper *RuntimeContextWrapper) IsUnsafeMode() bool {
446+
return contextWrapper.IsUnsafeModeFunc()
447+
}
448+
449+
// SetUnsafeMode calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
450+
func (contextWrapper *RuntimeContextWrapper) SetUnsafeMode(unsafeMode bool) {
451+
contextWrapper.SetUnsafeModeFunc(unsafeMode)
452+
}
453+
432454
// StartWasmerInstance calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
433455
func (contextWrapper *RuntimeContextWrapper) StartWasmerInstance(contract []byte, gasLimit uint64, newCode bool) error {
434456
return contextWrapper.StartWasmerInstanceFunc(contract, gasLimit, newCode)

mock/mockery/RuntimeContext.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,32 @@ type MockRuntimeContext struct {
1414
mock.Mock
1515
}
1616

17-
// RemoveCodeUpgradeFromArgs -
17+
// RemoveCodeUpgradeFromArgs provides a mock function with given fields
1818
func (_m *MockRuntimeContext) RemoveCodeUpgradeFromArgs() {
1919
}
2020

21+
// IsUnsafeMode provides a mock function with given fields
22+
func (_m *MockRuntimeContext) IsUnsafeMode() bool {
23+
ret := _m.Called()
24+
25+
if len(ret) == 0 {
26+
return true
27+
}
28+
29+
var r0 bool
30+
if rf, ok := ret.Get(0).(func() bool); ok {
31+
r0 = rf()
32+
} else {
33+
r0 = ret.Get(0).(bool)
34+
}
35+
36+
return r0
37+
}
38+
39+
// SetUnsafeMode provides a mock function with given fields
40+
func (_m *MockRuntimeContext) SetUnsafeMode(_ bool) {
41+
}
42+
2143
// AddError provides a mock function with given fields: err, otherInfo
2244
func (_m *MockRuntimeContext) AddError(err error, otherInfo ...string) {
2345
_va := make([]interface{}, len(otherInfo))
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "../mxvm/context.h"
2+
3+
// Forward declaration of the C functions, assuming they are linked externally
4+
void mx_activate_unsafe_mode(void);
5+
void mx_deactivate_unsafe_mode(void);
6+
void bigIntTDiv(int, int, int);
7+
8+
void activateUnsafeMode(void) {
9+
mx_activate_unsafe_mode();
10+
}
11+
12+
void deactivateUnsafeMode(void) {
13+
mx_deactivate_unsafe_mode();
14+
}
15+
16+
void testDivByZero(void) {
17+
int a = bigIntNew(1);
18+
int b = bigIntNew(0);
19+
int c = bigIntNew(0);
20+
bigIntTDiv(c, a, b);
21+
}
22+
23+
// Dummy function to satisfy the build system
24+
void _start() {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
activateUnsafeMode
2+
deactivateUnsafeMode
3+
testDivByZero

vmhost/contexts/runtime.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ var mapBarnardOpcodes = map[string]struct{}{
4545
"managedGetESDTTokenType": {},
4646
}
4747

48+
var mapFailConditionalOpcodes = map[string]struct{}{
49+
"ActivateUnsafeMode": {},
50+
"DeactivateUnsafeMode": {},
51+
}
52+
4853
const warmCacheSize = 100
4954

5055
type runtimeContext struct {
@@ -56,6 +61,7 @@ type runtimeContext struct {
5661
readOnly bool
5762
verifyCode bool
5863
maxInstanceStackSize uint64
64+
unsafeMode bool
5965

6066
vmExecutor executor.Executor
6167

@@ -124,6 +130,7 @@ func (context *runtimeContext) InitState() {
124130
context.callFunction = ""
125131
context.verifyCode = false
126132
context.readOnly = false
133+
context.unsafeMode = false
127134
context.iTracker.InitState()
128135
context.errors = nil
129136

@@ -398,6 +405,7 @@ func (context *runtimeContext) PushState() {
398405
codeAddress: context.codeAddress,
399406
callFunction: context.callFunction,
400407
readOnly: context.readOnly,
408+
unsafeMode: context.unsafeMode,
401409
}
402410
newState.SetVMInput(context.vmInput)
403411

@@ -426,6 +434,7 @@ func (context *runtimeContext) PopSetActiveState() {
426434
context.codeAddress = prevState.codeAddress
427435
context.callFunction = prevState.callFunction
428436
context.readOnly = prevState.readOnly
437+
context.unsafeMode = prevState.unsafeMode
429438
}
430439

431440
// PopDiscard removes the latest entry from the state stack
@@ -638,6 +647,16 @@ func (context *runtimeContext) FailExecution(err error) {
638647
logRuntime.Trace("execution failed", "message", traceMessage)
639648
}
640649

650+
// IsUnsafeMode returns true if mode is unsafe
651+
func (context *runtimeContext) IsUnsafeMode() bool {
652+
return context.unsafeMode
653+
}
654+
655+
// SetUnsafeMode sets the current mode of running
656+
func (context *runtimeContext) SetUnsafeMode(unsafeMode bool) {
657+
context.unsafeMode = unsafeMode
658+
}
659+
641660
// SignalUserError informs Wasmer to immediately stop the execution of the contract
642661
// with BreakpointSignalError and sets the corresponding VMOutput fields accordingly
643662
func (context *runtimeContext) SignalUserError(message string) {
@@ -704,6 +723,14 @@ func (context *runtimeContext) VerifyContractCode() error {
704723
}
705724
}
706725

726+
if !enableEpochsHandler.IsFlagEnabled(vmhost.FailConditionallyFlag) {
727+
err = context.checkIfContainsFailConditionalOpcodes()
728+
if err != nil {
729+
logRuntime.Trace("verify contract code", "error", err)
730+
return err
731+
}
732+
}
733+
707734
logRuntime.Trace("verified contract code")
708735

709736
return nil
@@ -727,6 +754,15 @@ func (context *runtimeContext) checkIfContainsBarnardOpcodes() error {
727754
return nil
728755
}
729756

757+
func (context *runtimeContext) checkIfContainsFailConditionalOpcodes() error {
758+
for funcName := range mapFailConditionalOpcodes {
759+
if context.iTracker.Instance().IsFunctionImported(funcName) {
760+
return vmhost.ErrContractInvalid
761+
}
762+
}
763+
return nil
764+
}
765+
730766
// UseGasBoundedShouldFailExecution returns true when flag activated
731767
func (context *runtimeContext) UseGasBoundedShouldFailExecution() bool {
732768
return context.host.EnableEpochsHandler().IsFlagEnabled(vmhost.UseGasBoundedShouldFailExecutionFlag)

vmhost/contexts/runtime_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,3 +839,24 @@ func TestRuntimeContext_PopInstanceIfStackIsEmptyShouldNotPanic(t *testing.T) {
839839

840840
require.Equal(t, 0, len(runtimeCtx.stateStack))
841841
}
842+
843+
func TestRuntimeContext_UnSafeMode(t *testing.T) {
844+
host := InitializeVMAndWasmer()
845+
runtimeCtx := makeDefaultRuntimeContext(t, host)
846+
defer runtimeCtx.ClearWarmInstanceCache()
847+
848+
runtimeCtx.vmInput = nil
849+
runtimeCtx.codeAddress = []byte("some address")
850+
runtimeCtx.callFunction = "a function"
851+
runtimeCtx.iTracker.codeSize = 1024
852+
853+
runtimeCtx.InitState()
854+
855+
require.False(t, runtimeCtx.IsUnsafeMode())
856+
runtimeCtx.SetUnsafeMode(true)
857+
858+
require.True(t, runtimeCtx.IsUnsafeMode())
859+
860+
runtimeCtx.SetUnsafeMode(false)
861+
require.False(t, runtimeCtx.IsUnsafeMode())
862+
}

0 commit comments

Comments
 (0)