Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions executor/vmHooks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions executor/wrapper/wrapperVMHooks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions mock/context/executorMockFunc.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions mock/context/runtimeContextMock.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type RuntimeContextMock struct {
CallFunction string
VMType []byte
ReadOnlyFlag bool
UnsafeModeFlag bool
VerifyCode bool
CurrentBreakpointValue vmhost.BreakpointValue
PointsUsed uint64
Expand Down Expand Up @@ -314,6 +315,16 @@ func (r *RuntimeContextMock) UseGasBoundedShouldFailExecution() bool {
return true
}

// IsUnsafeMode mocked method
func (r *RuntimeContextMock) IsUnsafeMode() bool {
return r.UnsafeModeFlag
}

// SetUnsafeMode mocked method
func (r *RuntimeContextMock) SetUnsafeMode(unsafeMode bool) {
r.UnsafeModeFlag = unsafeMode
}

// FailExecution mocked method
func (r *RuntimeContextMock) FailExecution(_ error) {
}
Expand Down
22 changes: 22 additions & 0 deletions mock/context/runtimeContextWrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ type RuntimeContextWrapper struct {
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
SetReadOnlyFunc func(readOnly bool)
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
IsUnsafeModeFunc func() bool
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
SetUnsafeModeFunc func(readOnly bool)
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
StartWasmerInstanceFunc func(contract []byte, gasLimit uint64, newCode bool) error
// function that will be called by the corresponding RuntimeContext function implementation (by default this will call the same wrapped context function)
ClearWarmInstanceCacheFunc func()
Expand Down Expand Up @@ -224,6 +228,14 @@ func NewRuntimeContextWrapper(inputRuntimeContext *vmhost.RuntimeContext) *Runti
runtimeWrapper.runtimeContext.SetReadOnly(readOnly)
}

runtimeWrapper.IsUnsafeModeFunc = func() bool {
return runtimeWrapper.runtimeContext.IsUnsafeMode()
}

runtimeWrapper.SetUnsafeModeFunc = func(unSafe bool) {
runtimeWrapper.runtimeContext.SetUnsafeMode(unSafe)
}

runtimeWrapper.StartWasmerInstanceFunc = func(contract []byte, gasLimit uint64, newCode bool) error {
return runtimeWrapper.runtimeContext.StartWasmerInstance(contract, gasLimit, newCode)
}
Expand Down Expand Up @@ -429,6 +441,16 @@ func (contextWrapper *RuntimeContextWrapper) SetReadOnly(readOnly bool) {
contextWrapper.SetReadOnlyFunc(readOnly)
}

// IsUnsafeMode calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
func (contextWrapper *RuntimeContextWrapper) IsUnsafeMode() bool {
return contextWrapper.IsUnsafeModeFunc()
}

// SetUnsafeMode calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
func (contextWrapper *RuntimeContextWrapper) SetUnsafeMode(unsafeMode bool) {
contextWrapper.SetUnsafeModeFunc(unsafeMode)
}

// StartWasmerInstance calls corresponding xxxFunc function, that by default in turn calls the original method of the wrapped RuntimeContext
func (contextWrapper *RuntimeContextWrapper) StartWasmerInstance(contract []byte, gasLimit uint64, newCode bool) error {
return contextWrapper.StartWasmerInstanceFunc(contract, gasLimit, newCode)
Expand Down
11 changes: 10 additions & 1 deletion mock/mockery/RuntimeContext.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@ type MockRuntimeContext struct {
mock.Mock
}

// RemoveCodeUpgradeFromArgs -
// RemoveCodeUpgradeFromArgs provides a mock function with given fields
func (_m *MockRuntimeContext) RemoveCodeUpgradeFromArgs() {
}

// IsUnsafeMode provides a mock function with given fields
func (_m *MockRuntimeContext) IsUnsafeMode() bool {
return false
}

// SetUnsafeMode provides a mock function with given fields
func (_m *MockRuntimeContext) SetUnsafeMode(_ bool) {
}

// AddError provides a mock function with given fields: err, otherInfo
func (_m *MockRuntimeContext) AddError(err error, otherInfo ...string) {
_va := make([]interface{}, len(otherInfo))
Expand Down
24 changes: 24 additions & 0 deletions test/contracts/unsafeOps/unsafeOps.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "../mxvm/context.h"

// Forward declaration of the C functions, assuming they are linked externally
void mx_activate_unsafe_mode(void);
void mx_deactivate_unsafe_mode(void);
void bigIntTDiv(int, int, int);

void activateUnsafeMode(void) {
mx_activate_unsafe_mode();
}

void deactivateUnsafeMode(void) {
mx_deactivate_unsafe_mode();
}

void testDivByZero(void) {
int a = bigIntNew(1);
int b = bigIntNew(0);
int c = bigIntNew(0);
bigIntTDiv(c, a, b);
}

// Dummy function to satisfy the build system
void _start() {}
3 changes: 3 additions & 0 deletions test/contracts/unsafeOps/unsafeOps.export
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
activateUnsafeMode
deactivateUnsafeMode
testDivByZero
49 changes: 49 additions & 0 deletions vmhost/contexts/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ var mapBarnardOpcodes = map[string]struct{}{
"managedGetESDTTokenType": {},
}

var mapFailConditionalOpcodes = map[string]struct{}{
"ActivateUnsafeMode": {},
"DeactivateUnsafeMode": {},
}

const warmCacheSize = 100

type runtimeContext struct {
Expand All @@ -56,6 +61,7 @@ type runtimeContext struct {
readOnly bool
verifyCode bool
maxInstanceStackSize uint64
unsafeMode bool

vmExecutor executor.Executor

Expand Down Expand Up @@ -124,6 +130,7 @@ func (context *runtimeContext) InitState() {
context.callFunction = ""
context.verifyCode = false
context.readOnly = false
context.unsafeMode = false
context.iTracker.InitState()
context.errors = nil

Expand Down Expand Up @@ -398,6 +405,7 @@ func (context *runtimeContext) PushState() {
codeAddress: context.codeAddress,
callFunction: context.callFunction,
readOnly: context.readOnly,
unsafeMode: context.unsafeMode,
}
newState.SetVMInput(context.vmInput)

Expand Down Expand Up @@ -426,6 +434,7 @@ func (context *runtimeContext) PopSetActiveState() {
context.codeAddress = prevState.codeAddress
context.callFunction = prevState.callFunction
context.readOnly = prevState.readOnly
context.unsafeMode = prevState.unsafeMode
}

// PopDiscard removes the latest entry from the state stack
Expand Down Expand Up @@ -638,6 +647,29 @@ func (context *runtimeContext) FailExecution(err error) {
logRuntime.Trace("execution failed", "message", traceMessage)
}

// FailExecutionConditionally informs Wasmer to immediately stop the execution of the contract
// with BreakpointExecutionFailed and sets the corresponding VMOutput fields accordingly, if the unsafe mode is not active.
// If unsafe mode is active, it just logs the error.
func (context *runtimeContext) FailExecutionConditionally(err error) {
if context.IsUnsafeMode() {
logRuntime.Trace("execution would have failed, but unsafe mode is active", "err", err)
context.AddError(err)
return
}

context.FailExecution(err)
}

// IsUnsafeMode returns true if mode is unsafe
func (context *runtimeContext) IsUnsafeMode() bool {
return context.unsafeMode
}

// SetUnsafeMode sets the current mode of running
func (context *runtimeContext) SetUnsafeMode(unsafeMode bool) {
context.unsafeMode = unsafeMode
}

// SignalUserError informs Wasmer to immediately stop the execution of the contract
// with BreakpointSignalError and sets the corresponding VMOutput fields accordingly
func (context *runtimeContext) SignalUserError(message string) {
Expand Down Expand Up @@ -704,6 +736,14 @@ func (context *runtimeContext) VerifyContractCode() error {
}
}

if !enableEpochsHandler.IsFlagEnabled(vmhost.FailConditionallyFlag) {
err = context.checkIfContainsFailConditionalOpcodes()
if err != nil {
logRuntime.Trace("verify contract code", "error", err)
return err
}
}

logRuntime.Trace("verified contract code")

return nil
Expand All @@ -727,6 +767,15 @@ func (context *runtimeContext) checkIfContainsBarnardOpcodes() error {
return nil
}

func (context *runtimeContext) checkIfContainsFailConditionalOpcodes() error {
for funcName := range mapFailConditionalOpcodes {
if context.iTracker.Instance().IsFunctionImported(funcName) {
return vmhost.ErrContractInvalid
}
}
return nil
}

// UseGasBoundedShouldFailExecution returns true when flag activated
func (context *runtimeContext) UseGasBoundedShouldFailExecution() bool {
return context.host.EnableEpochsHandler().IsFlagEnabled(vmhost.UseGasBoundedShouldFailExecutionFlag)
Expand Down
3 changes: 3 additions & 0 deletions vmhost/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,6 @@ var ErrTooManyTransfersFromBuiltInFunction = errors.New("too many transfers from

// ErrTimeLockExpired signals that timelock has expired
var ErrTimeLockExpired = errors.New("time lock expired")

// ErrWrongType signals that wrong type is read from buffer
var ErrWrongType = errors.New("incompatible type")
3 changes: 3 additions & 0 deletions vmhost/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,8 @@ const (
// AsyncV3Flag defines the flag that activates the fix for get balance from the Barnard release
AsyncV3Flag core.EnableEpochFlag = "AsyncV3Flag"

// FailConditionallyFlag defines the flag that activates the new opcodes and possibility for failing conditionally
FailConditionallyFlag core.EnableEpochFlag = "FailConditionallyFlag"

// all new flags must be added to allFlags slice from hostCore/host
)
4 changes: 2 additions & 2 deletions vmhost/hostCore/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var allFlags = []core.EnableEpochFlag{
vmhost.FixGetBalanceFlag,
vmhost.AsyncV3FixesFlag,
vmhost.AsyncV3Flag,
vmhost.FailConditionallyFlag,
}

// vmHost implements HostContext interface.
Expand All @@ -56,8 +57,7 @@ type vmHost struct {
mutExecution sync.RWMutex
closingInstance bool
executionTimeout time.Duration

ethInput []byte
ethInput []byte

blockchainContext vmhost.BlockchainContext
runtimeContext vmhost.RuntimeContext
Expand Down
2 changes: 2 additions & 0 deletions vmhost/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ type RuntimeContext interface {
IsFunctionImported(name string) bool
ReadOnly() bool
SetReadOnly(readOnly bool)
IsUnsafeMode() bool
SetUnsafeMode(unsafeMode bool)
StartWasmerInstance(contract []byte, gasLimit uint64, newCode bool) error
ClearWarmInstanceCache()
SetMaxInstanceStackSize(uint64)
Expand Down
Loading
Loading