Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ type CompilationOptions struct {
type Executor interface {
check.NilInterfaceChecker

// SetOpcodeCosts sets gas costs globally inside an executor.
SetOpcodeCosts(opcodeCosts *WASMOpcodeCost)
// SetOpcodeConfig sets gas costs globally inside an executor.
SetOpcodeConfig(opcodeVersion OpcodeVersion, wasmOps *WASMOpcodeCost)

// FunctionNames return the low-level function names provided to contracts.
FunctionNames() vmcommon.FunctionNames
Expand Down
1 change: 1 addition & 0 deletions executor/executorFactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "github.com/multiversx/mx-chain-core-go/core/check"
// ExecutorFactoryArgs define the Executor configurations that come from the VM, especially the hooks and the gas costs.
type ExecutorFactoryArgs struct {
VMHooks VMHooks
OpcodeVersion OpcodeVersion
OpcodeCosts *WASMOpcodeCost
RkyvSerializationEnabled bool
WasmerSIGSEGVPassthrough bool
Expand Down
8 changes: 8 additions & 0 deletions executor/executorOpcodeVersion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package executor

type OpcodeVersion uint32

const (
OpcodeVersionV1 OpcodeVersion = iota
OpcodeVersionV2
)
6 changes: 3 additions & 3 deletions executor/wrapper/wrapperExecutor.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ type WrapperExecutor struct {
WrappedInstances map[string][]executor.Instance
}

// SetOpcodeCosts wraps the call to the underlying executor.
func (wexec *WrapperExecutor) SetOpcodeCosts(opcodeCosts *executor.WASMOpcodeCost) {
wexec.wrappedExecutor.SetOpcodeCosts(opcodeCosts)
// SetOpcodeConfig wraps the call to the underlying executor.
func (wexec *WrapperExecutor) SetOpcodeConfig(opcodeVersion executor.OpcodeVersion, wasmOps *executor.WASMOpcodeCost) {
wexec.wrappedExecutor.SetOpcodeConfig(opcodeVersion, wasmOps)
}

// FunctionNames wraps the call to the underlying executor.
Expand Down
11 changes: 11 additions & 0 deletions integrationTests/json/scenariosFeatures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,17 @@ func TestRustPayableFeatures(t *testing.T) {
CheckNoError()
}

func TestRustPanicMessageFeatures(t *testing.T) {
if testing.Short() {
t.Skip("not a short test")
}

ScenariosTest(t).
Folder("features/panic-message-features/scenarios").
Run().
CheckNoError()
}

func TestRustComposability(t *testing.T) {
ScenariosTest(t).
Folder("features/composability/scenarios").
Expand Down
4 changes: 2 additions & 2 deletions mock/context/executorMock.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ func NewExecutorMock(world *worldmock.MockWorld) *ExecutorMock {
}
}

// SetOpcodeCosts should set gas costs, but it does nothing in the case of this mock.
func (executorMock *ExecutorMock) SetOpcodeCosts(_ *executor.WASMOpcodeCost) {
// SetOpcodeConfig should set gas costs, but it does nothing in the case of this mock.
func (executorMock *ExecutorMock) SetOpcodeConfig(_ executor.OpcodeVersion, _ *executor.WASMOpcodeCost) {
}

// FunctionNames mocked method
Expand Down
5 changes: 3 additions & 2 deletions vmhost/contexts/async_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package contexts

import (
"errors"
"github.com/multiversx/mx-chain-vm-go/wasmer2"
"math/big"
"testing"

"github.com/multiversx/mx-chain-vm-go/wasmer2"

"github.com/multiversx/mx-chain-core-go/data/vm"
"github.com/multiversx/mx-chain-core-go/marshal"
"github.com/multiversx/mx-chain-scenario-go/worldmock"
Expand Down Expand Up @@ -59,7 +60,7 @@ func initializeVMAndWasmerAsyncContextWithBuiltIn(tb testing.TB, isBuiltinFunc b
gasCostConfig, err := config.CreateGasConfig(gasSchedule)
require.Nil(tb, err)
wasmerExecutor, _ := wasmer2.CreateExecutor()
wasmerExecutor.SetOpcodeCosts(gasCostConfig.WASMOpcodeCost)
wasmerExecutor.SetOpcodeConfig(executor.OpcodeVersionV2, gasCostConfig.WASMOpcodeCost)

host := &contextmock.VMHostMock{
EnableEpochsHandlerField: &worldmock.EnableEpochsHandlerStub{},
Expand Down
2 changes: 1 addition & 1 deletion vmhost/contexts/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func InitializeVMAndWasmer() *contextmock.VMHostMock {
gasSchedule := config.MakeGasMapForTests()
gasCostConfig, _ := config.CreateGasConfig(gasSchedule)
wasmerExecutor, _ := wasmer2.CreateExecutor()
wasmerExecutor.SetOpcodeCosts(gasCostConfig.WASMOpcodeCost)
wasmerExecutor.SetOpcodeConfig(executor.OpcodeVersionV2, gasCostConfig.WASMOpcodeCost)

host := &contextmock.VMHostMock{}

Expand Down
14 changes: 13 additions & 1 deletion vmhost/hostCore/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@ func (host *vmHost) createExecutor(hostParameters *vmhost.VMHostParameters) (exe
} else {
vmExecutorFactory = wasmer2.ExecutorFactory()
}

vmExecutorFactoryArgs := executor.ExecutorFactoryArgs{
VMHooks: vmHooks,
OpcodeVersion: host.getOpcodeVersionForCurrentEpoch(),
OpcodeCosts: gasCostConfig.WASMOpcodeCost,
RkyvSerializationEnabled: true,
WasmerSIGSEGVPassthrough: hostParameters.WasmerSIGSEGVPassthrough,
Expand Down Expand Up @@ -348,6 +350,14 @@ func (host *vmHost) ClearContextStateStack() {
host.blockchainContext.ClearStateStack()
}

func (host *vmHost) getOpcodeVersionForCurrentEpoch() executor.OpcodeVersion {
if host.enableEpochsHandler.IsFlagEnabled(vmhost.AsyncV3Flag) {
return executor.OpcodeVersionV2
}

return executor.OpcodeVersionV1
}

// GasScheduleChange applies a new gas schedule to the host
func (host *vmHost) GasScheduleChange(newGasSchedule config.GasScheduleMap) {
host.mutExecution.Lock()
Expand All @@ -360,7 +370,9 @@ func (host *vmHost) GasScheduleChange(newGasSchedule config.GasScheduleMap) {
return
}

host.runtimeContext.GetVMExecutor().SetOpcodeCosts(gasCostConfig.WASMOpcodeCost)
opcodeVersion := host.getOpcodeVersionForCurrentEpoch()

host.runtimeContext.GetVMExecutor().SetOpcodeConfig(opcodeVersion, gasCostConfig.WASMOpcodeCost)

host.meteringContext.SetGasSchedule(newGasSchedule)
host.runtimeContext.ClearWarmInstanceCache()
Expand Down
37 changes: 36 additions & 1 deletion vmhost/hosttest/forbidden_opcodes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func TestForbiddenOps_BulkAndSIMD(t *testing.T) {
wasmModules := []string{"data-drop", "memory-init", "memory-fill", "memory-copy", "simd"}
wasmModules := []string{"data-drop", "memory-init", "simd"}

for _, moduleName := range wasmModules {
testCase := testcommon.BuildInstanceCallTest(t).
Expand Down Expand Up @@ -61,3 +61,38 @@ func TestBarnardOpcodesActivation(t *testing.T) {
ContractInvalid()
})
}

func TestBulkMemoryOpcodesActivation(t *testing.T) {
wasmModules := []string{"memory-copy", "memory-fill"}

for _, moduleName := range wasmModules {
testcommon.BuildInstanceCreatorTest(t).
WithInput(testcommon.CreateTestContractCreateInputBuilder().
WithGasProvided(100000000).
WithContractCode(testcommon.GetTestSCCodeModule("forbidden-opcodes/"+moduleName, moduleName, "../../")).
Build()).
WithEnableEpochsHandler(&worldmock.EnableEpochsHandlerStub{
IsFlagEnabledCalled: func(flag core.EnableEpochFlag) bool {
return flag != vmhost.AsyncV3Flag
},
}).
AndAssertResults(func(stubBlockchainHook *contextmock.BlockchainHookStub, verify *testcommon.VMOutputVerifier) {
verify.
ContractInvalid()
})

testcommon.BuildInstanceCreatorTest(t).
WithInput(testcommon.CreateTestContractCreateInputBuilder().
WithGasProvided(100000000).
WithContractCode(testcommon.GetTestSCCodeModule("forbidden-opcodes/"+moduleName, moduleName, "../../")).
Build()).
WithEnableEpochsHandler(&worldmock.EnableEpochsHandlerStub{
IsFlagEnabledCalled: func(flag core.EnableEpochFlag) bool {
return true
},
}).
AndAssertResults(func(stubBlockchainHook *contextmock.BlockchainHookStub, verify *testcommon.VMOutputVerifier) {
verify.FunctionNotFound()
})
}
}
6 changes: 5 additions & 1 deletion vmhost/vmhooks/generate/cmd/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# generated files that belong to other repos:
output

# optional path where to copy rust files
# optional path where to copy rust files (deprecated)
wasm-vm-executor-rs-path.txt

# optional path where to copy rust files
path-to-mx-sdk-rs.txt
path-to-vm-executor-rs.txt
77 changes: 59 additions & 18 deletions vmhost/vmhooks/generate/cmd/eiGenMain.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
)

const pathToApiPackage = "./"
const pathToRustRepoConfigFile = "wasm-vm-executor-rs-path.txt"
const pathVmExecutorRsFile = "path-to-vm-executor-rs.txt"
const pathToMxSdkRsFile = "path-to-mx-sdk-rs.txt"

func initEIMetadata() *eapigen.EIMetadata {
return &eapigen.EIMetadata{
Expand Down Expand Up @@ -56,6 +57,7 @@ func main() {
writeRustVMHooksTrait(eiMetadata)
writeRustVMHooksLegacyTrait(eiMetadata)
writeRustVMHooksLegacyAdapter(eiMetadata)
writeRustVMHooksSignatures(eiMetadata)
writeRustCapiVMHooks(eiMetadata)
writeRustCapiVMHooksPointers(eiMetadata)
writeRustWasmerProdImports(eiMetadata)
Expand All @@ -68,13 +70,15 @@ func main() {
writeWasmer2OpcodeCost()
writeWASMOpcodeCostFuncHelpers()
writeWASMOpcodeCostConfigHelpers()
writeOpcodeCostFuncHelpers()
writeRustOpcodeCost()
writeRustWasmerMeteringHelpers()
writeRustWasmerOpcodeCost()
writeOpcodeWhitelisted()
writeRustWasmerExperimentalOpcodeCost()

fmt.Println("Generated code for opcodes and metering helpers.")

tryCopyFilesToRustExecutorRepo()
tryCopyFilesToMxExecutorRsRepo()
tryCopyFilesToMxSdkRsRepo()
}

func writeVMHooks(eiMetadata *eapigen.EIMetadata) {
Expand Down Expand Up @@ -174,6 +178,12 @@ func writeRustVHDispatcherLegacy(eiMetadata *eapigen.EIMetadata) {
eapigen.WriteRustVHDispatcherLegacy(out, eiMetadata)
}

func writeRustVMHooksSignatures(eiMetadata *eapigen.EIMetadata) {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/vm_hook_signature_list.rs")
defer out.Close()
eapigen.WriteRustVMHooksSignatures(out, eiMetadata)
}

func writeExecutorOpcodeCosts() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "../../executor/gasCostWASM.go")
defer out.Close()
Expand All @@ -198,27 +208,33 @@ func writeWasmer2OpcodeCost() {
eapigen.WriteWasmer2OpcodeCost(out)
}

func writeOpcodeCostFuncHelpers() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/extractOpcodeCost.txt")
defer out.Close()
eapigen.WriteOpcodeCostFuncHelpers(out)
}

func writeRustOpcodeCost() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/opcode_cost.rs")
defer out.Close()
eapigen.WriteRustOpcodeCost(out)
}

func writeRustWasmerMeteringHelpers() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/wasmer_metering_helpers.rs")
func writeRustWasmerOpcodeCost() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/wasmer_opcode_cost.rs")
defer out.Close()
eapigen.WriteRustWasmerOpcodeCost(out)
}

func writeOpcodeWhitelisted() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/opcode_whitelist.rs")
defer out.Close()
eapigen.WriteRustWasmerMeteringHelpers(out)
eapigen.WriteOpcodeWhitelisted(out)
}

func tryCopyFilesToRustExecutorRepo() {
fullPathToRustRepoConfigFile := filepath.Join(pathToApiPackage, "generate/cmd/", pathToRustRepoConfigFile)
contentBytes, err := os.ReadFile(fullPathToRustRepoConfigFile)
func writeRustWasmerExperimentalOpcodeCost() {
out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/we_opcode_cost.rs")
defer out.Close()
eapigen.WriteRustWasmerExperimentalOpcodeCost(out)
}

func tryCopyFilesToMxExecutorRsRepo() {
fullPathToConfigFile := filepath.Join(pathToApiPackage, "generate/cmd/", pathVmExecutorRsFile)
contentBytes, err := os.ReadFile(fullPathToConfigFile)
if err != nil {
// this feature is optional
fmt.Println("Rust files not copied to wasm-vm-executor-rs. Add a wasm-vm-executor-rs-path.txt with the path to enable feature.")
Expand Down Expand Up @@ -260,8 +276,33 @@ func tryCopyFilesToRustExecutorRepo() {
filepath.Join(rustExecutorPath, "vm-executor-experimental/src/we_imports.rs"),
)
copyFile(
filepath.Join(pathToApiPackage, "generate/cmd/output/wasmer_metering_helpers.rs"),
filepath.Join(rustExecutorPath, "vm-executor-wasmer/src/wasmer_metering_helpers.rs"),
filepath.Join(pathToApiPackage, "generate/cmd/output/wasmer_opcode_cost.rs"),
filepath.Join(rustExecutorPath, "vm-executor-wasmer/src/wasmer_opcode_cost.rs"),
)
copyFile(
filepath.Join(pathToApiPackage, "generate/cmd/output/we_opcode_cost.rs"),
filepath.Join(rustExecutorPath, "vm-executor-experimental/src/middlewares/we_opcode_cost.rs"),
)
}

func tryCopyFilesToMxSdkRsRepo() {
fullPathToConfigFile := filepath.Join(pathToApiPackage, "generate/cmd/", pathToMxSdkRsFile)
contentBytes, err := os.ReadFile(fullPathToConfigFile)
if err != nil {
// this feature is optional
fmt.Println("Rust files not copied to wasm-vm-executor-rs. Add a wasm-vm-executor-rs-path.txt with the path to enable feature.")
return
}
rustExecutorPath := strings.Trim(string(contentBytes), " \n\t")

fmt.Printf("Copying generated Rust files to '%s':\n", rustExecutorPath)
copyFile(
filepath.Join(pathToApiPackage, "generate/cmd/output/opcode_whitelist.rs"),
filepath.Join(rustExecutorPath, "framework/meta-lib/src/tools/wasm_extractor/opcode_whitelist.rs"),
)
copyFile(
filepath.Join(pathToApiPackage, "generate/cmd/output/vm_hook_signature_list.rs"),
filepath.Join(rustExecutorPath, "framework/meta-lib/src/ei/vm_hook_signature_list.rs"),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ If
LocalGet
LocalSet
LocalTee
LocalAllocate
Loop
MemoryGrow
MemorySize
Expand Down
Loading
Loading