mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 19:15:54 +00:00
1
.github/actions/dependencies/action.yml
vendored
1
.github/actions/dependencies/action.yml
vendored
@@ -17,6 +17,7 @@ runs:
|
|||||||
conan export external/rocksdb rocksdb/9.7.3@
|
conan export external/rocksdb rocksdb/9.7.3@
|
||||||
conan export external/soci soci/4.0.3@
|
conan export external/soci soci/4.0.3@
|
||||||
conan export external/nudb nudb/2.0.8@
|
conan export external/nudb nudb/2.0.8@
|
||||||
|
conan export -k external/wamr wamr/2.2.0@
|
||||||
- name: add Ripple Conan remote
|
- name: add Ripple Conan remote
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
1
.github/workflows/nix.yml
vendored
1
.github/workflows/nix.yml
vendored
@@ -351,6 +351,7 @@ jobs:
|
|||||||
conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default
|
conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default
|
||||||
conan export external/snappy snappy/1.1.10@
|
conan export external/snappy snappy/1.1.10@
|
||||||
conan export external/soci soci/4.0.3@
|
conan export external/soci soci/4.0.3@
|
||||||
|
conan export -k external/wamr wamr/2.2.0@
|
||||||
|
|
||||||
- name: build dependencies
|
- name: build dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
11
BUILD.md
11
BUILD.md
@@ -204,6 +204,17 @@ It fixes some source files to add missing `#include`s.
|
|||||||
conan export --version 2.0.8 external/nudb
|
conan export --version 2.0.8 external/nudb
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Export our [Conan recipe for WAMR](./external/wamr).
|
||||||
|
It add metering and expose some internal structures.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
# Conan 1.x
|
||||||
|
conan export external/wamr wamr/2.2.0@
|
||||||
|
# Conan 2.x
|
||||||
|
conan export --version 2.2.0 external/wamr
|
||||||
|
```
|
||||||
|
|
||||||
### Build and Test
|
### Build and Test
|
||||||
|
|
||||||
1. Create a build directory and move into it.
|
1. Create a build directory and move into it.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ endif()
|
|||||||
find_package(nudb REQUIRED)
|
find_package(nudb REQUIRED)
|
||||||
find_package(date REQUIRED)
|
find_package(date REQUIRED)
|
||||||
find_package(xxHash REQUIRED)
|
find_package(xxHash REQUIRED)
|
||||||
find_package(wasmedge REQUIRED)
|
find_package(wamr REQUIRED)
|
||||||
|
|
||||||
target_link_libraries(ripple_libs INTERFACE
|
target_link_libraries(ripple_libs INTERFACE
|
||||||
ed25519::ed25519
|
ed25519::ed25519
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ target_link_libraries(xrpl.imports.main
|
|||||||
xrpl.libpb
|
xrpl.libpb
|
||||||
xxHash::xxhash
|
xxHash::xxhash
|
||||||
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
|
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
|
||||||
wasmedge::wasmedge
|
wamr::wamr
|
||||||
)
|
)
|
||||||
|
|
||||||
include(add_module)
|
include(add_module)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Xrpl(ConanFile):
|
|||||||
'soci/4.0.3',
|
'soci/4.0.3',
|
||||||
'xxhash/0.8.2',
|
'xxhash/0.8.2',
|
||||||
'zlib/1.3.1',
|
'zlib/1.3.1',
|
||||||
'wasmedge/0.14.1',
|
'wamr/2.2.0',
|
||||||
]
|
]
|
||||||
|
|
||||||
tool_requires = [
|
tool_requires = [
|
||||||
|
|||||||
6
external/wamr/conandata.yml
vendored
Normal file
6
external/wamr/conandata.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
patches:
|
||||||
|
2.2.0:
|
||||||
|
- patch_description: add metering to iwasm interpreter
|
||||||
|
patch_file: patches/ripp_metering.patch
|
||||||
|
patch_type: conan
|
||||||
|
|
||||||
90
external/wamr/conanfile.py
vendored
Normal file
90
external/wamr/conanfile.py
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
from conans import ConanFile, tools
|
||||||
|
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout
|
||||||
|
from conan.tools.files import apply_conandata_patches, export_conandata_patches, get, copy
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
|
required_conan_version = ">=1.55.0"
|
||||||
|
|
||||||
|
class WamrConan(ConanFile):
|
||||||
|
name = "wamr"
|
||||||
|
version = "2.2.0"
|
||||||
|
license = "Apache License v2.0"
|
||||||
|
url = "https://github.com/bytecodealliance/wasm-micro-runtime.git"
|
||||||
|
description = "Webassembly micro runtime"
|
||||||
|
package_type = "library"
|
||||||
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
|
options = {"shared": [True, False], "fPIC": [True, False]}
|
||||||
|
default_options = {"shared": False, "fPIC": True}
|
||||||
|
generators = "CMakeToolchain", "CMakeDeps"
|
||||||
|
#requires = [("llvm/20.1.1@")]
|
||||||
|
|
||||||
|
def export_sources(self):
|
||||||
|
export_conandata_patches(self)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
#def build_requirements(self):
|
||||||
|
# self.tool_requires("llvm/20.1.1")
|
||||||
|
|
||||||
|
|
||||||
|
def config_options(self):
|
||||||
|
if self.settings.os == "Windows":
|
||||||
|
del self.options.fPIC
|
||||||
|
|
||||||
|
|
||||||
|
def layout(self):
|
||||||
|
cmake_layout(self, src_folder="src")
|
||||||
|
|
||||||
|
|
||||||
|
def source(self):
|
||||||
|
git = tools.Git()
|
||||||
|
git.clone("https://github.com/bytecodealliance/wasm-micro-runtime.git", "c883fafead005e87ad3122b05409886f507c1cb0",shallow=True)
|
||||||
|
#get(self, **self.conan_data["sources"][self.version], strip_root=True)
|
||||||
|
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
tc = CMakeToolchain(self)
|
||||||
|
|
||||||
|
tc.variables["WAMR_BUILD_INTERP"] = 1
|
||||||
|
tc.variables["WAMR_BUILD_FAST_INTERP"] = 1
|
||||||
|
tc.variables["WAMR_BUILD_INSTRUCTION_METERING"] = 1
|
||||||
|
tc.variables["WAMR_BUILD_AOT"] = 0
|
||||||
|
tc.variables["WAMR_BUILD_JIT"] = 0
|
||||||
|
tc.variables["WAMR_BUILD_FAST_JIT"] = 0
|
||||||
|
tc.variables["WAMR_DISABLE_HW_BOUND_CHECK"] = 1
|
||||||
|
tc.variables["WAMR_DISABLE_STACK_HW_BOUND_CHECK"] = 1
|
||||||
|
#tc.variables["WAMR_BUILD_FAST_JIT"] = 0 if self.settings.os == "Windows" else 1
|
||||||
|
#ll_dep = self.dependencies["llvm"]
|
||||||
|
#self.output.info(f"-----------package_folder: {type(ll_dep.__dict__)}")
|
||||||
|
#tc.variables["LLVM_DIR"] = os.path.join(ll_dep.package_folder, "lib", "cmake", "llvm")
|
||||||
|
tc.generate()
|
||||||
|
|
||||||
|
# This generates "foo-config.cmake" and "bar-config.cmake" in self.generators_folder
|
||||||
|
deps = CMakeDeps(self)
|
||||||
|
deps.generate()
|
||||||
|
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
apply_conandata_patches(self)
|
||||||
|
cmake = CMake(self)
|
||||||
|
cmake.verbose = True
|
||||||
|
cmake.configure()
|
||||||
|
cmake.build()
|
||||||
|
#self.run(f'echo {self.source_folder}')
|
||||||
|
# Explicit way:
|
||||||
|
# self.run('cmake %s/hello %s' % (self.source_folder, cmake.command_line))
|
||||||
|
# self.run("cmake --build . %s" % cmake.build_config)
|
||||||
|
|
||||||
|
|
||||||
|
def package(self):
|
||||||
|
cmake = CMake(self)
|
||||||
|
cmake.verbose = True
|
||||||
|
cmake.install()
|
||||||
|
|
||||||
|
|
||||||
|
def package_info(self):
|
||||||
|
self.cpp_info.libs = ["iwasm"]
|
||||||
|
self.cpp_info.names["cmake_find_package"] = "wamr"
|
||||||
|
self.cpp_info.names["cmake_find_package_multi"] = "wamr"
|
||||||
|
|
||||||
417
external/wamr/patches/ripp_metering.patch
vendored
Normal file
417
external/wamr/patches/ripp_metering.patch
vendored
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index 551991f8..5f48a0b8 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
-cmake_minimum_required (VERSION 3.14)
|
||||||
|
+cmake_minimum_required (VERSION 3.20)
|
||||||
|
|
||||||
|
option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
|
||||||
|
|
||||||
|
diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake
|
||||||
|
index 1cb50235..bd103022 100644
|
||||||
|
--- a/build-scripts/config_common.cmake
|
||||||
|
+++ b/build-scripts/config_common.cmake
|
||||||
|
@@ -669,6 +669,10 @@ if (WAMR_BUILD_AOT_VALIDATOR EQUAL 1)
|
||||||
|
message (" AOT validator enabled")
|
||||||
|
add_definitions (-DWASM_ENABLE_AOT_VALIDATOR=1)
|
||||||
|
endif ()
|
||||||
|
+if (WAMR_BUILD_INSTRUCTION_METERING EQUAL 1)
|
||||||
|
+ message (" Instruction metering enabled")
|
||||||
|
+ add_definitions (-DWASM_ENABLE_INSTRUCTION_METERING=1)
|
||||||
|
+endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Show Phase4 Wasm proposals status.
|
||||||
|
diff --git a/core/config.h b/core/config.h
|
||||||
|
index cb1189c9..a4e1499e 100644
|
||||||
|
--- a/core/config.h
|
||||||
|
+++ b/core/config.h
|
||||||
|
@@ -716,4 +716,8 @@ unless used elsewhere */
|
||||||
|
#define WASM_ENABLE_AOT_VALIDATOR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifndef WASM_ENABLE_INSTRUCTION_METERING
|
||||||
|
+#define WASM_ENABLE_INSTRUCTION_METERING 0
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#endif /* end of _CONFIG_H_ */
|
||||||
|
diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c
|
||||||
|
index 269ec577..bc6fd01b 100644
|
||||||
|
--- a/core/iwasm/common/wasm_c_api.c
|
||||||
|
+++ b/core/iwasm/common/wasm_c_api.c
|
||||||
|
@@ -5389,3 +5389,8 @@ wasm_instance_get_wasm_func_exec_time(const wasm_instance_t *instance,
|
||||||
|
return -1.0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+wasm_exec_env_t wasm_instance_exec_env(const wasm_instance_t*instance)
|
||||||
|
+{
|
||||||
|
+ return wasm_runtime_get_exec_env_singleton(instance->inst_comm_rt);
|
||||||
|
+}
|
||||||
|
diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c
|
||||||
|
index e33fd9f3..d1ff9c41 100644
|
||||||
|
--- a/core/iwasm/common/wasm_exec_env.c
|
||||||
|
+++ b/core/iwasm/common/wasm_exec_env.c
|
||||||
|
@@ -85,6 +85,12 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
|
||||||
|
wasm_runtime_dump_exec_env_mem_consumption(exec_env);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+ exec_env->instructions_to_execute = -1;
|
||||||
|
+ for(int i = 0; i < 256; ++i)
|
||||||
|
+ exec_env->instructions_schedule[i] = 1;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
return exec_env;
|
||||||
|
|
||||||
|
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||||
|
diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h
|
||||||
|
index ce0c1fa7..2713a092 100644
|
||||||
|
--- a/core/iwasm/common/wasm_exec_env.h
|
||||||
|
+++ b/core/iwasm/common/wasm_exec_env.h
|
||||||
|
@@ -87,6 +87,12 @@ typedef struct WASMExecEnv {
|
||||||
|
uint8 *bottom;
|
||||||
|
} wasm_stack;
|
||||||
|
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+ /* instructions to execute */
|
||||||
|
+ int64 instructions_to_execute;
|
||||||
|
+ int64 instructions_schedule[256];
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if WASM_ENABLE_FAST_JIT != 0
|
||||||
|
/**
|
||||||
|
* Cache for
|
||||||
|
diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c
|
||||||
|
index d33c0272..900fb536 100644
|
||||||
|
--- a/core/iwasm/common/wasm_runtime_common.c
|
||||||
|
+++ b/core/iwasm/common/wasm_runtime_common.c
|
||||||
|
@@ -2285,6 +2285,31 @@ wasm_runtime_access_exce_check_guard_page()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
|
||||||
|
+ int64 instructions_to_execute)
|
||||||
|
+{
|
||||||
|
+ exec_env->instructions_to_execute = instructions_to_execute;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int64
|
||||||
|
+wasm_runtime_get_instruction_count_limit(WASMExecEnv *exec_env)
|
||||||
|
+{
|
||||||
|
+ return exec_env->instructions_to_execute;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+wasm_runtime_set_instruction_schedule(WASMExecEnv *exec_env,
|
||||||
|
+ int64 const *instructions_schedule)
|
||||||
|
+{
|
||||||
|
+ for(int i = 0; i < 256; ++i)
|
||||||
|
+ exec_env->instructions_schedule[i] = instructions_schedule[i];
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
WASMFuncType *
|
||||||
|
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
|
||||||
|
uint32 module_type)
|
||||||
|
@@ -7803,7 +7828,7 @@ wasm_runtime_detect_native_stack_overflow(WASMExecEnv *exec_env)
|
||||||
|
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
|
||||||
|
boundary = boundary + page_size * guard_page_count;
|
||||||
|
#endif
|
||||||
|
- if ((uint8 *)&boundary < boundary) {
|
||||||
|
+ if (((uint8 *)&boundary < boundary) && ((uint8 *)&boundary > exec_env->native_stack_boundary)){
|
||||||
|
wasm_runtime_set_exception(wasm_runtime_get_module_inst(exec_env),
|
||||||
|
"native stack overflow");
|
||||||
|
return false;
|
||||||
|
diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h
|
||||||
|
index 8ac032bf..5ca5d489 100644
|
||||||
|
--- a/core/iwasm/common/wasm_runtime_common.h
|
||||||
|
+++ b/core/iwasm/common/wasm_runtime_common.h
|
||||||
|
@@ -791,9 +791,25 @@ WASM_RUNTIME_API_EXTERN void
|
||||||
|
wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env,
|
||||||
|
uint8 *native_stack_boundary);
|
||||||
|
|
||||||
|
-#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+
|
||||||
|
/* See wasm_export.h for description */
|
||||||
|
WASM_RUNTIME_API_EXTERN void
|
||||||
|
+wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
|
||||||
|
+ int64 instructions_to_execute);
|
||||||
|
+WASM_RUNTIME_API_EXTERN int64
|
||||||
|
+wasm_runtime_get_instruction_count_limit(WASMExecEnv *exec_env);
|
||||||
|
+
|
||||||
|
+WASM_RUNTIME_API_EXTERN void
|
||||||
|
+wasm_runtime_set_instruction_schedule(WASMExecEnv *exec_env,
|
||||||
|
+ int64 const *instructions_schedule);
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
|
||||||
|
+/* See wasm_export.h for description */
|
||||||
|
+WASM_RUNTIME_API_EXTERN
|
||||||
|
+void
|
||||||
|
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
|
||||||
|
bool enable);
|
||||||
|
|
||||||
|
diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h
|
||||||
|
index 241a0eec..82e048c0 100644
|
||||||
|
--- a/core/iwasm/include/wasm_c_api.h
|
||||||
|
+++ b/core/iwasm/include/wasm_c_api.h
|
||||||
|
@@ -701,6 +701,11 @@ WASM_API_EXTERN double wasm_instance_sum_wasm_exec_time(const wasm_instance_t*);
|
||||||
|
// func_name. If the function is not found, return 0.
|
||||||
|
WASM_API_EXTERN double wasm_instance_get_wasm_func_exec_time(const wasm_instance_t*, const char *);
|
||||||
|
|
||||||
|
+struct WASMExecEnv;
|
||||||
|
+typedef struct WASMExecEnv *wasm_exec_env_t;
|
||||||
|
+
|
||||||
|
+WASM_API_EXTERN wasm_exec_env_t wasm_instance_exec_env(const wasm_instance_t*);
|
||||||
|
+
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convenience
|
||||||
|
|
||||||
|
diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h
|
||||||
|
index b73a0364..f7e20b24 100644
|
||||||
|
--- a/core/iwasm/include/wasm_export.h
|
||||||
|
+++ b/core/iwasm/include/wasm_export.h
|
||||||
|
@@ -1821,6 +1821,27 @@ WASM_RUNTIME_API_EXTERN void
|
||||||
|
wasm_runtime_set_native_stack_boundary(wasm_exec_env_t exec_env,
|
||||||
|
uint8_t *native_stack_boundary);
|
||||||
|
|
||||||
|
+/**
|
||||||
|
+ * Set the instruction count limit to the execution environment.
|
||||||
|
+ * By default the instruction count limit is -1, which means no limit.
|
||||||
|
+ * However, if the instruction count limit is set to a positive value,
|
||||||
|
+ * the execution will be terminated when the instruction count reaches
|
||||||
|
+ * the limit.
|
||||||
|
+ *
|
||||||
|
+ * @param exec_env the execution environment
|
||||||
|
+ * @param instruction_count the instruction count limit
|
||||||
|
+ */
|
||||||
|
+WASM_RUNTIME_API_EXTERN void
|
||||||
|
+wasm_runtime_set_instruction_count_limit(wasm_exec_env_t exec_env,
|
||||||
|
+ int64_t instruction_count);
|
||||||
|
+
|
||||||
|
+WASM_RUNTIME_API_EXTERN int64_t
|
||||||
|
+wasm_runtime_get_instruction_count_limit(wasm_exec_env_t exec_env);
|
||||||
|
+
|
||||||
|
+WASM_RUNTIME_API_EXTERN void
|
||||||
|
+wasm_runtime_set_instruction_schedule(wasm_exec_env_t exec_env,
|
||||||
|
+ int64_t const *instructions_schedule);
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Dump runtime memory consumption, including:
|
||||||
|
* Exec env memory consumption
|
||||||
|
diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c
|
||||||
|
index 41ac4c72..1aa1fe1c 100644
|
||||||
|
--- a/core/iwasm/interpreter/wasm_interp_classic.c
|
||||||
|
+++ b/core/iwasm/interpreter/wasm_interp_classic.c
|
||||||
|
@@ -1516,10 +1516,13 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||||
|
} \
|
||||||
|
os_mutex_unlock(&exec_env->wait_lock); \
|
||||||
|
} \
|
||||||
|
+ CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
goto *handle_table[*frame_ip++]; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
-#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
|
||||||
|
+#define HANDLE_OP_END() \
|
||||||
|
+ CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
+ FETCH_OPCODE_AND_DISPATCH()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
|
||||||
|
@@ -1542,9 +1545,12 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||||
|
} \
|
||||||
|
os_mutex_unlock(&exec_env->wait_lock); \
|
||||||
|
} \
|
||||||
|
+ CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
continue;
|
||||||
|
#else
|
||||||
|
-#define HANDLE_OP_END() continue
|
||||||
|
+#define HANDLE_OP_END() \
|
||||||
|
+ CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
+ continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
|
||||||
|
@@ -1562,6 +1568,18 @@ get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+#define CHECK_INSTRUCTION_LIMIT() \
|
||||||
|
+ if (instructions_to_execute == 0) { \
|
||||||
|
+ wasm_set_exception(module, "instruction limit exceeded"); \
|
||||||
|
+ goto got_exception; \
|
||||||
|
+ } \
|
||||||
|
+ else if (instructions_to_execute > 0) \
|
||||||
|
+ instructions_to_execute--;
|
||||||
|
+#else
|
||||||
|
+#define CHECK_INSTRUCTION_LIMIT() (void)0
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
|
WASMExecEnv *exec_env,
|
||||||
|
@@ -1605,6 +1623,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
|
uint32 local_idx, local_offset, global_idx;
|
||||||
|
uint8 local_type, *global_addr;
|
||||||
|
uint32 cache_index, type_index, param_cell_num, cell_num;
|
||||||
|
+
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+ int64 instructions_to_execute = -1;
|
||||||
|
+ if(exec_env)
|
||||||
|
+ instructions_to_execute = exec_env->instructions_to_execute;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if WASM_ENABLE_EXCE_HANDLING != 0
|
||||||
|
int32_t exception_tag_index;
|
||||||
|
#endif
|
||||||
|
@@ -6859,6 +6884,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
|
FREE_FRAME(exec_env, frame);
|
||||||
|
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
|
||||||
|
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+ if(exec_env)
|
||||||
|
+ exec_env->instructions_to_execute = instructions_to_execute;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
if (!prev_frame->ip) {
|
||||||
|
/* Called from native. */
|
||||||
|
return;
|
||||||
|
@@ -6899,6 +6929,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
SYNC_ALL_TO_FRAME();
|
||||||
|
+
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+ if(exec_env)
|
||||||
|
+ exec_env->instructions_to_execute = instructions_to_execute;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if WASM_ENABLE_LABELS_AS_VALUES == 0
|
||||||
|
diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c
|
||||||
|
index f33ad60e..a7078fe8 100644
|
||||||
|
--- a/core/iwasm/interpreter/wasm_interp_fast.c
|
||||||
|
+++ b/core/iwasm/interpreter/wasm_interp_fast.c
|
||||||
|
@@ -105,6 +105,20 @@ typedef float64 CellType_F64;
|
||||||
|
goto unaligned_atomic; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+#define CHECK_INSTRUCTION_LIMIT() \
|
||||||
|
+ if (instructions_to_execute >= 0) \
|
||||||
|
+ { \
|
||||||
|
+ instructions_to_execute -= instructions_schedule[opc]; \
|
||||||
|
+ if (instructions_to_execute < 0) { \
|
||||||
|
+ wasm_set_exception(module, "instruction limit exceeded"); \
|
||||||
|
+ goto got_exception; \
|
||||||
|
+ } \
|
||||||
|
+ }
|
||||||
|
+#else
|
||||||
|
+#define CHECK_INSTRUCTION_LIMIT() (void)0
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
static inline uint32
|
||||||
|
rotl32(uint32 n, uint32 c)
|
||||||
|
{
|
||||||
|
@@ -1439,8 +1453,10 @@ wasm_interp_dump_op_count()
|
||||||
|
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
|
||||||
|
#define FETCH_OPCODE_AND_DISPATCH() \
|
||||||
|
do { \
|
||||||
|
+ const uint64 opc = *frame_ip; \
|
||||||
|
const void *p_label_addr = *(void **)frame_ip; \
|
||||||
|
frame_ip += sizeof(void *); \
|
||||||
|
+ CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
goto *p_label_addr; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
@@ -1450,8 +1466,10 @@ wasm_interp_dump_op_count()
|
||||||
|
const void *p_label_addr; \
|
||||||
|
bh_assert(((uintptr_t)frame_ip & 1) == 0); \
|
||||||
|
/* int32 relative offset was emitted in 64-bit target */ \
|
||||||
|
+ const uint64 opc = LOAD_U32_WITH_2U16S(frame_ip); \
|
||||||
|
p_label_addr = label_base + (int32)LOAD_U32_WITH_2U16S(frame_ip); \
|
||||||
|
frame_ip += sizeof(int32); \
|
||||||
|
+ CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
goto *p_label_addr; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
@@ -1460,8 +1478,10 @@ wasm_interp_dump_op_count()
|
||||||
|
const void *p_label_addr; \
|
||||||
|
bh_assert(((uintptr_t)frame_ip & 1) == 0); \
|
||||||
|
/* uint32 label address was emitted in 32-bit target */ \
|
||||||
|
+ const uint64 opc = LOAD_U32_WITH_2U16S(frame_ip); \
|
||||||
|
p_label_addr = (void *)(uintptr_t)LOAD_U32_WITH_2U16S(frame_ip); \
|
||||||
|
frame_ip += sizeof(int32); \
|
||||||
|
+ CHECK_INSTRUCTION_LIMIT(); \
|
||||||
|
goto *p_label_addr; \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
@@ -1538,6 +1558,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
|
uint8 *maddr = NULL;
|
||||||
|
uint32 local_idx, local_offset, global_idx;
|
||||||
|
uint8 opcode = 0, local_type, *global_addr;
|
||||||
|
+
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+ int64 instructions_to_execute = -1;
|
||||||
|
+ int64 const *instructions_schedule = NULL;
|
||||||
|
+ if(exec_env)
|
||||||
|
+ {
|
||||||
|
+ instructions_to_execute = exec_env->instructions_to_execute;
|
||||||
|
+ instructions_schedule = exec_env->instructions_schedule;
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|
||||||
|
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
|
||||||
|
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
|
||||||
|
@@ -7761,6 +7792,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
|
FREE_FRAME(exec_env, frame);
|
||||||
|
wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)prev_frame);
|
||||||
|
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+ if(exec_env)
|
||||||
|
+ exec_env->instructions_to_execute = instructions_to_execute;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
if (!prev_frame->ip)
|
||||||
|
/* Called from native. */
|
||||||
|
return;
|
||||||
|
@@ -7789,6 +7825,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||||
|
|
||||||
|
got_exception:
|
||||||
|
SYNC_ALL_TO_FRAME();
|
||||||
|
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
|
||||||
|
+ if(exec_env)
|
||||||
|
+ exec_env->instructions_to_execute = instructions_to_execute;
|
||||||
|
+#endif
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if WASM_ENABLE_LABELS_AS_VALUES == 0
|
||||||
|
diff --git a/doc/build_wamr.md b/doc/build_wamr.md
|
||||||
|
index 6425450b..94dd9628 100644
|
||||||
|
--- a/doc/build_wamr.md
|
||||||
|
+++ b/doc/build_wamr.md
|
||||||
|
@@ -327,6 +327,10 @@ And the wasm app can calls below APIs to allocate/free memory from/to the shared
|
||||||
|
- **WAMR_BUILD_SHRUNK_MEMORY**=1/0, default to enable if not set
|
||||||
|
> Note: When enabled, this feature will reduce memory usage by decreasing the size of the linear memory, particularly when the `memory.grow` opcode is not used and memory usage is somewhat predictable.
|
||||||
|
|
||||||
|
+## **Instruction metering**
|
||||||
|
+- **WAMR_BUILD_INSTRUCTION_METERING**=1/0, default to disable if not set
|
||||||
|
+> Note: Enabling this feature allows limiting the number of instructions a wasm module instance can execute. Use the `wasm_runtime_set_instruction_count_limit(...)` API before calling `wasm_runtime_call_*(...)` APIs to enforce this limit.
|
||||||
|
+
|
||||||
|
## **Combination of configurations:**
|
||||||
|
|
||||||
|
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <test/jtx.h>
|
#include <test/jtx.h>
|
||||||
|
|
||||||
|
#include <xrpld/app/misc/WasmVM.h>
|
||||||
#include <xrpld/app/tx/applySteps.h>
|
#include <xrpld/app/tx/applySteps.h>
|
||||||
#include <xrpld/ledger/Dir.h>
|
#include <xrpld/ledger/Dir.h>
|
||||||
|
|
||||||
@@ -1921,12 +1922,12 @@ struct Escrow_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
{
|
{
|
||||||
// not enough gas
|
// not enough gas
|
||||||
// This function takes 110 gas
|
// This function takes 4 gas
|
||||||
// In testing, 1 gas costs 1 drop
|
// In testing, 1 gas costs 1 drop
|
||||||
auto const finishFee = env.current()->fees().base + 108;
|
auto const finishFee = env.current()->fees().base + 4;
|
||||||
env(finish(carol, alice, seq),
|
env(finish(carol, alice, seq),
|
||||||
fee(finishFee),
|
fee(finishFee),
|
||||||
comp_allowance(108),
|
comp_allowance(2),
|
||||||
ter(tecFAILED_PROCESSING));
|
ter(tecFAILED_PROCESSING));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,105 +21,21 @@
|
|||||||
|
|
||||||
#include <xrpld/app/misc/WasmVM.h>
|
#include <xrpld/app/misc/WasmVM.h>
|
||||||
|
|
||||||
#include <wasmedge/wasmedge.h>
|
#include <iwasm/wasm_c_api.h>
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
/* Host function body definition. */
|
/* Host function body definition. */
|
||||||
WasmEdge_Result
|
using Add_proto = int32_t(int32_t, int32_t);
|
||||||
Add(void* Data,
|
wasm_trap_t*
|
||||||
const WasmEdge_CallingFrameContext* CallFrameCxt,
|
Add(void* env, const wasm_val_vec_t* params, wasm_val_vec_t* results)
|
||||||
const WasmEdge_Value* In,
|
|
||||||
WasmEdge_Value* Out)
|
|
||||||
{
|
{
|
||||||
int32_t Val1 = WasmEdge_ValueGetI32(In[0]);
|
int32_t Val1 = params->data[0].of.i32;
|
||||||
int32_t Val2 = WasmEdge_ValueGetI32(In[1]);
|
int32_t Val2 = params->data[1].of.i32;
|
||||||
// printf("Host function \"Add\": %d + %d\n", Val1, Val2);
|
// printf("Host function \"Add\": %d + %d\n", Val1, Val2);
|
||||||
Out[0] = WasmEdge_ValueGenI32(Val1 + Val2);
|
results->data[0] = WASM_I32_VAL(Val1 + Val2);
|
||||||
return WasmEdge_Result_Success;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
invokeAdd()
|
|
||||||
{
|
|
||||||
/* Create the VM context. */
|
|
||||||
WasmEdge_VMContext* VMCxt = WasmEdge_VMCreate(NULL, NULL);
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
/* The WASM module buffer. */
|
|
||||||
uint8_t WASM[] = {/* WASM header */
|
|
||||||
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
/* Type section */
|
|
||||||
0x01, 0x07, 0x01,
|
|
||||||
/* function type {i32, i32} -> {i32} */
|
|
||||||
0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F,
|
|
||||||
/* Import section */
|
|
||||||
0x02, 0x13, 0x01,
|
|
||||||
/* module name: "extern" */
|
|
||||||
0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E,
|
|
||||||
/* extern name: "func-add" */
|
|
||||||
0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64,
|
|
||||||
/* import desc: func 0 */
|
|
||||||
0x00, 0x00,
|
|
||||||
/* Function section */
|
|
||||||
0x03, 0x02, 0x01, 0x00,
|
|
||||||
/* Export section */
|
|
||||||
0x07, 0x0A, 0x01,
|
|
||||||
/* export name: "addTwo" */
|
|
||||||
0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F,
|
|
||||||
/* export desc: func 0 */
|
|
||||||
0x00, 0x01,
|
|
||||||
/* Code section */
|
|
||||||
0x0A, 0x0A, 0x01,
|
|
||||||
/* code body */
|
|
||||||
0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
/* Create the module instance. */
|
|
||||||
WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern");
|
|
||||||
WasmEdge_ModuleInstanceContext* HostModCxt =
|
|
||||||
WasmEdge_ModuleInstanceCreate(ExportName);
|
|
||||||
WasmEdge_ValType ParamList[2] = {
|
|
||||||
WasmEdge_ValTypeGenI32(), WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* HostFType =
|
|
||||||
WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* HostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0);
|
|
||||||
WasmEdge_FunctionTypeDelete(HostFType);
|
|
||||||
WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc);
|
|
||||||
WasmEdge_StringDelete(HostFuncName);
|
|
||||||
|
|
||||||
WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt);
|
|
||||||
|
|
||||||
/* The parameters and returns arrays. */
|
|
||||||
WasmEdge_Value Params[2] = {
|
|
||||||
WasmEdge_ValueGenI32(1234), WasmEdge_ValueGenI32(5678)};
|
|
||||||
WasmEdge_Value Returns[1];
|
|
||||||
/* Function name. */
|
|
||||||
WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo");
|
|
||||||
/* Run the WASM function from buffer. */
|
|
||||||
WasmEdge_Result Res = WasmEdge_VMRunWasmFromBuffer(
|
|
||||||
VMCxt, WASM, sizeof(WASM), FuncName, Params, 2, Returns, 1);
|
|
||||||
|
|
||||||
if (WasmEdge_ResultOK(Res))
|
|
||||||
{
|
|
||||||
// printf("invokeAdd get the result: %d\n",
|
|
||||||
// WasmEdge_ValueGetI32(Returns[0]));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resources deallocations. */
|
|
||||||
WasmEdge_VMDelete(VMCxt);
|
|
||||||
WasmEdge_StringDelete(FuncName);
|
|
||||||
WasmEdge_ModuleInstanceDelete(HostModCxt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Wasm_test : public beast::unit_test::suite
|
struct Wasm_test : public beast::unit_test::suite
|
||||||
@@ -128,8 +44,46 @@ struct Wasm_test : public beast::unit_test::suite
|
|||||||
testWasmtimeLib()
|
testWasmtimeLib()
|
||||||
{
|
{
|
||||||
testcase("wasmtime lib test");
|
testcase("wasmtime lib test");
|
||||||
invokeAdd();
|
// clang-format off
|
||||||
BEAST_EXPECT(true);
|
/* The WASM module buffer. */
|
||||||
|
wbytes const wasm = {/* WASM header */
|
||||||
|
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
/* Type section */
|
||||||
|
0x01, 0x07, 0x01,
|
||||||
|
/* function type {i32, i32} -> {i32} */
|
||||||
|
0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F,
|
||||||
|
/* Import section */
|
||||||
|
0x02, 0x13, 0x01,
|
||||||
|
/* module name: "extern" */
|
||||||
|
0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E,
|
||||||
|
/* extern name: "func-add" */
|
||||||
|
0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64,
|
||||||
|
/* import desc: func 0 */
|
||||||
|
0x00, 0x00,
|
||||||
|
/* Function section */
|
||||||
|
0x03, 0x02, 0x01, 0x00,
|
||||||
|
/* Export section */
|
||||||
|
0x07, 0x0A, 0x01,
|
||||||
|
/* export name: "addTwo" */
|
||||||
|
0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F,
|
||||||
|
/* export desc: func 0 */
|
||||||
|
0x00, 0x01,
|
||||||
|
/* Code section */
|
||||||
|
0x0A, 0x0A, 0x01,
|
||||||
|
/* code body */
|
||||||
|
0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B};
|
||||||
|
// clang-format on
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
|
||||||
|
std::vector<WasmImportFunc> imports;
|
||||||
|
WasmImpFunc<Add_proto>(
|
||||||
|
imports, "func-add", reinterpret_cast<void*>(&Add));
|
||||||
|
|
||||||
|
auto res = vm.run(wasm, "addTwo", imports, wasmParams(1234, 5678));
|
||||||
|
|
||||||
|
// if (res) printf("invokeAdd get the result: %d\n", res.value());
|
||||||
|
|
||||||
|
BEAST_EXPECT(res.has_value() && res.value() == 6912);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1412,9 +1366,9 @@ struct Wasm_test : public beast::unit_test::suite
|
|||||||
BadTestHostFunctions nfs(&env);
|
BadTestHostFunctions nfs(&env);
|
||||||
std::string funcName("ready");
|
std::string funcName("ready");
|
||||||
auto re = runEscrowWasm(wasm, funcName, &nfs, 100000);
|
auto re = runEscrowWasm(wasm, funcName, &nfs, 100000);
|
||||||
BEAST_EXPECT(re.error());
|
if (BEAST_EXPECT(!re))
|
||||||
std::cout << "bad case (more than MAX_PAGES) result " << re.error()
|
std::cout << "bad case (more than MAX_PAGES) result "
|
||||||
<< std::endl;
|
<< re.error() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // fail because recursion too deep
|
{ // fail because recursion too deep
|
||||||
@@ -2143,9 +2097,9 @@ struct Wasm_test : public beast::unit_test::suite
|
|||||||
TestHostFunctions nfs(&env);
|
TestHostFunctions nfs(&env);
|
||||||
std::string funcName("recursive");
|
std::string funcName("recursive");
|
||||||
auto re = runEscrowWasm(wasm, funcName, &nfs, 1000'000'000);
|
auto re = runEscrowWasm(wasm, funcName, &nfs, 1000'000'000);
|
||||||
BEAST_EXPECT(re.error());
|
if (BEAST_EXPECT(re.error()))
|
||||||
std::cout << "bad case (deep recursion) result " << re.error()
|
std::cout << "bad case (deep recursion) result " << re.error()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
754
src/xrpld/app/misc/WamrVM.cpp
Normal file
754
src/xrpld/app/misc/WamrVM.cpp
Normal file
@@ -0,0 +1,754 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2020 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <xrpld/app/misc/WamrVM.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_wasm_error(const char* message, wasm_trap_t* trap)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "WAMR error: %s\n", message);
|
||||||
|
wasm_byte_vec_t error_message;
|
||||||
|
|
||||||
|
if (trap)
|
||||||
|
{
|
||||||
|
wasm_trap_message(trap, &error_message);
|
||||||
|
wasm_trap_delete(trap);
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"WAMR trap: %.*s\n",
|
||||||
|
(int)error_message.size,
|
||||||
|
error_message.data);
|
||||||
|
wasm_byte_vec_delete(&error_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
InstancePtr
|
||||||
|
InstanceWrapper::init(
|
||||||
|
wasm_store_t* s,
|
||||||
|
wasm_module_t* m,
|
||||||
|
int32_t maxPages,
|
||||||
|
wasm_extern_vec_t* expt,
|
||||||
|
wasm_extern_vec_t const& imports)
|
||||||
|
{
|
||||||
|
wasm_trap_t* trap = nullptr;
|
||||||
|
InstantiationArgs inst_args{
|
||||||
|
128 * 1024,
|
||||||
|
256 * 1024,
|
||||||
|
static_cast<uint32_t>(maxPages > 0 ? maxPages : 0)};
|
||||||
|
|
||||||
|
InstancePtr mi = InstancePtr(
|
||||||
|
wasm_instance_new_with_args_ex(s, m, &imports, &trap, &inst_args),
|
||||||
|
&wasm_instance_delete);
|
||||||
|
|
||||||
|
if (!mi || trap)
|
||||||
|
{
|
||||||
|
print_wasm_error("can't create instance", trap);
|
||||||
|
throw std::runtime_error("WAMR: can't create instance");
|
||||||
|
}
|
||||||
|
wasm_instance_exports(mi.get(), expt);
|
||||||
|
return mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceWrapper::InstanceWrapper()
|
||||||
|
: exports{0, nullptr, 0, 0, nullptr}
|
||||||
|
, mod_inst(nullptr, &wasm_instance_delete)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceWrapper::InstanceWrapper(InstanceWrapper&& o)
|
||||||
|
: exports{0, nullptr, 0, 0, nullptr}
|
||||||
|
, mod_inst(nullptr, &wasm_instance_delete)
|
||||||
|
{
|
||||||
|
*this = std::move(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceWrapper&
|
||||||
|
InstanceWrapper::operator=(InstanceWrapper&& o)
|
||||||
|
{
|
||||||
|
if (this == &o)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
if (exports.size)
|
||||||
|
wasm_extern_vec_delete(&exports);
|
||||||
|
exports = o.exports;
|
||||||
|
o.exports = {0, nullptr, 0, 0, nullptr};
|
||||||
|
|
||||||
|
mod_inst = std::move(o.mod_inst);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceWrapper::InstanceWrapper(
|
||||||
|
wasm_store_t* s,
|
||||||
|
wasm_module_t* m,
|
||||||
|
int32_t maxPages,
|
||||||
|
wasm_extern_vec_t const& imports)
|
||||||
|
: exports WASM_EMPTY_VEC, mod_inst(init(s, m, maxPages, &exports, imports))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceWrapper::~InstanceWrapper()
|
||||||
|
{
|
||||||
|
if (exports.size)
|
||||||
|
wasm_extern_vec_delete(&exports);
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceWrapper::operator bool() const
|
||||||
|
{
|
||||||
|
return static_cast<bool>(mod_inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_func_t*
|
||||||
|
InstanceWrapper::getFunc(
|
||||||
|
std::string_view funcName,
|
||||||
|
wasm_exporttype_vec_t const& export_types) const
|
||||||
|
{
|
||||||
|
wasm_func_t* f = nullptr;
|
||||||
|
|
||||||
|
if (!export_types.size)
|
||||||
|
throw std::runtime_error("WAMR: no export");
|
||||||
|
if (export_types.size != exports.size)
|
||||||
|
throw std::runtime_error("WAMR: invalid export");
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < export_types.size; ++i)
|
||||||
|
{
|
||||||
|
auto const* exp_type(export_types.data[i]);
|
||||||
|
|
||||||
|
wasm_name_t const* name = wasm_exporttype_name(exp_type);
|
||||||
|
const wasm_externtype_t* exn_type = wasm_exporttype_type(exp_type);
|
||||||
|
if (wasm_externtype_kind(exn_type) == WASM_EXTERN_FUNC)
|
||||||
|
{
|
||||||
|
if (funcName == std::string_view(name->data, name->size - 1))
|
||||||
|
{
|
||||||
|
auto* exn(exports.data[i]);
|
||||||
|
if (wasm_extern_kind(exn) != WASM_EXTERN_FUNC)
|
||||||
|
throw std::runtime_error("WAMR: invalid export");
|
||||||
|
|
||||||
|
f = wasm_extern_as_func(exn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
throw std::runtime_error(
|
||||||
|
"WAMR: can't find function " + std::string(funcName));
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
wmem
|
||||||
|
InstanceWrapper::getMem() const
|
||||||
|
{
|
||||||
|
wasm_memory_t* mem = nullptr;
|
||||||
|
for (unsigned i = 0; i < exports.size; ++i)
|
||||||
|
{
|
||||||
|
auto* e(exports.data[i]);
|
||||||
|
if (wasm_extern_kind(e) == WASM_EXTERN_MEMORY)
|
||||||
|
{
|
||||||
|
mem = wasm_extern_as_memory(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mem)
|
||||||
|
throw std::runtime_error("WAMR: no memory exported");
|
||||||
|
|
||||||
|
return {
|
||||||
|
reinterpret_cast<std::uint8_t*>(wasm_memory_data(mem)),
|
||||||
|
wasm_memory_data_size(mem)};
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ModulePtr
|
||||||
|
ModuleWrapper::init(wasm_store_t* s, wbytes const& wasmBin)
|
||||||
|
{
|
||||||
|
wasm_byte_vec_t const code{
|
||||||
|
wasmBin.size(),
|
||||||
|
(char*)(wasmBin.data()),
|
||||||
|
wasmBin.size(),
|
||||||
|
sizeof(std::remove_reference_t<decltype(wasmBin)>::value_type),
|
||||||
|
nullptr};
|
||||||
|
ModulePtr m = ModulePtr(wasm_module_new(s, &code), &wasm_module_delete);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleWrapper::ModuleWrapper()
|
||||||
|
: module(nullptr, &wasm_module_delete)
|
||||||
|
, export_types{0, nullptr, 0, 0, nullptr}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleWrapper::ModuleWrapper(ModuleWrapper&& o)
|
||||||
|
: module(nullptr, &wasm_module_delete)
|
||||||
|
, export_types{0, nullptr, 0, 0, nullptr}
|
||||||
|
{
|
||||||
|
*this = std::move(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleWrapper&
|
||||||
|
ModuleWrapper::operator=(ModuleWrapper&& o)
|
||||||
|
{
|
||||||
|
if (this == &o)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
module = std::move(o.module);
|
||||||
|
mod_inst = std::move(o.mod_inst);
|
||||||
|
if (export_types.size)
|
||||||
|
wasm_exporttype_vec_delete(&export_types);
|
||||||
|
export_types = o.export_types;
|
||||||
|
o.export_types = {0, nullptr, 0, 0, nullptr};
|
||||||
|
exec_env = o.exec_env;
|
||||||
|
o.exec_env = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleWrapper::ModuleWrapper(
|
||||||
|
wasm_store_t* s,
|
||||||
|
wbytes const& wasmBin,
|
||||||
|
bool instantiate,
|
||||||
|
int32_t maxPages,
|
||||||
|
std::vector<WasmImportFunc> const& imports)
|
||||||
|
: module(init(s, wasmBin)), export_types{0, nullptr, 0, 0, nullptr}
|
||||||
|
{
|
||||||
|
if (!module)
|
||||||
|
throw std::runtime_error("WAMR: can't create module");
|
||||||
|
|
||||||
|
wasm_module_exports(module.get(), &export_types);
|
||||||
|
if (instantiate)
|
||||||
|
{
|
||||||
|
auto wimports = buildImports(s, imports);
|
||||||
|
addInstance(s, maxPages, wimports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleWrapper::~ModuleWrapper()
|
||||||
|
{
|
||||||
|
if (export_types.size)
|
||||||
|
wasm_exporttype_vec_delete(&export_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleWrapper::operator bool() const
|
||||||
|
{
|
||||||
|
return mod_inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleWrapper::makeImpParams(wasm_valtype_vec_t& v, WasmImportFunc const& imp)
|
||||||
|
{
|
||||||
|
auto const paramSize = imp.params.size();
|
||||||
|
|
||||||
|
if (paramSize)
|
||||||
|
{
|
||||||
|
wasm_valtype_vec_new(&v, paramSize, nullptr);
|
||||||
|
v.num_elems = paramSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
v = WASM_EMPTY_VEC;
|
||||||
|
for (unsigned i = 0; i < paramSize; ++i)
|
||||||
|
{
|
||||||
|
auto const vt = imp.params[i];
|
||||||
|
switch (vt)
|
||||||
|
{
|
||||||
|
case WT_I32:
|
||||||
|
v.data[i] = wasm_valtype_new_i32();
|
||||||
|
break;
|
||||||
|
case WT_I64:
|
||||||
|
v.data[i] = wasm_valtype_new_i64();
|
||||||
|
break;
|
||||||
|
case WT_F32:
|
||||||
|
v.data[i] = wasm_valtype_new_f32();
|
||||||
|
break;
|
||||||
|
case WT_F64:
|
||||||
|
v.data[i] = wasm_valtype_new_f64();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Invalid import type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleWrapper::makeImpReturn(wasm_valtype_vec_t& v, WasmImportFunc const& imp)
|
||||||
|
{
|
||||||
|
if (imp.result)
|
||||||
|
{
|
||||||
|
wasm_valtype_vec_new(&v, 1, nullptr);
|
||||||
|
v.num_elems = 1;
|
||||||
|
switch (*imp.result)
|
||||||
|
{
|
||||||
|
case WT_I32:
|
||||||
|
v.data[0] = wasm_valtype_new_i32();
|
||||||
|
break;
|
||||||
|
case WT_I64:
|
||||||
|
v.data[0] = wasm_valtype_new_i64();
|
||||||
|
break;
|
||||||
|
case WT_F32:
|
||||||
|
v.data[0] = wasm_valtype_new_f32();
|
||||||
|
break;
|
||||||
|
case WT_F64:
|
||||||
|
v.data[0] = wasm_valtype_new_f64();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Invalid return type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
v = WASM_EMPTY_VEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_extern_vec_t
|
||||||
|
ModuleWrapper::buildImports(
|
||||||
|
wasm_store_t* s,
|
||||||
|
std::vector<WasmImportFunc> const& imports)
|
||||||
|
{
|
||||||
|
wasm_importtype_vec_t importTypes = WASM_EMPTY_VEC;
|
||||||
|
wasm_module_imports(module.get(), &importTypes);
|
||||||
|
std::
|
||||||
|
unique_ptr<wasm_importtype_vec_t, decltype(&wasm_importtype_vec_delete)>
|
||||||
|
itDeleter(&importTypes, &wasm_importtype_vec_delete);
|
||||||
|
|
||||||
|
wasm_extern_vec_t wimports = WASM_EMPTY_VEC;
|
||||||
|
if (!importTypes.num_elems)
|
||||||
|
return wimports;
|
||||||
|
|
||||||
|
wasm_extern_vec_new(&wimports, importTypes.size, nullptr);
|
||||||
|
wimports.num_elems = importTypes.num_elems;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < importTypes.num_elems; ++i)
|
||||||
|
{
|
||||||
|
wasm_importtype_t const* importtype = importTypes.data[i];
|
||||||
|
if (wasm_importtype_is_linked(importtype))
|
||||||
|
{
|
||||||
|
// create a placeholder
|
||||||
|
wimports.data[i] = wasm_extern_new_empty(
|
||||||
|
s, wasm_externtype_kind(wasm_importtype_type(importtype)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wasm_name_t const* mn = wasm_importtype_module(importtype);
|
||||||
|
// auto modName = std::string_view(mn->data, mn->num_elems - 1);
|
||||||
|
wasm_name_t const* fn = wasm_importtype_name(importtype);
|
||||||
|
auto fieldName = std::string_view(fn->data, fn->num_elems - 1);
|
||||||
|
|
||||||
|
// for multi-module support
|
||||||
|
// if ((W_ENV != modName) && (W_HOST_LIB != modName))
|
||||||
|
// continue;
|
||||||
|
|
||||||
|
for (auto const& imp : imports)
|
||||||
|
{
|
||||||
|
if (imp.name != fieldName)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
wasm_valtype_vec_t params, results;
|
||||||
|
makeImpReturn(results, imp);
|
||||||
|
makeImpParams(params, imp);
|
||||||
|
|
||||||
|
using ftype_ptr = std::
|
||||||
|
unique_ptr<wasm_functype_t, decltype(&wasm_functype_delete)>;
|
||||||
|
ftype_ptr ftype(
|
||||||
|
wasm_functype_new(¶ms, &results), &wasm_functype_delete);
|
||||||
|
wasm_func_t* func = wasm_func_new_with_env(
|
||||||
|
s,
|
||||||
|
ftype.get(),
|
||||||
|
reinterpret_cast<wasm_func_callback_with_env_t>(imp.wrap),
|
||||||
|
imp.udata,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
wimports.data[i] = wasm_func_as_extern(func);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wimports;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_func_t*
|
||||||
|
ModuleWrapper::getFunc(std::string_view funcName) const
|
||||||
|
{
|
||||||
|
return mod_inst.getFunc(funcName, export_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
wmem
|
||||||
|
ModuleWrapper::getMem() const
|
||||||
|
{
|
||||||
|
return mod_inst.getMem();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ModuleWrapper::addInstance(
|
||||||
|
wasm_store_t* s,
|
||||||
|
int32_t maxPages,
|
||||||
|
wasm_extern_vec_t const& imports)
|
||||||
|
{
|
||||||
|
mod_inst = {s, module.get(), maxPages, imports};
|
||||||
|
exec_env = wasm_instance_exec_env(mod_inst.mod_inst.get());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// int
|
||||||
|
// my_module_t::delInstance(int i)
|
||||||
|
// {
|
||||||
|
// if (i >= mod_inst.size())
|
||||||
|
// return -1;
|
||||||
|
// if (!mod_inst[i])
|
||||||
|
// mod_inst[i] = my_mod_inst_t();
|
||||||
|
// return i;
|
||||||
|
// }
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
ModuleWrapper::setGas(std::int64_t gas)
|
||||||
|
{
|
||||||
|
if (exec_env)
|
||||||
|
{
|
||||||
|
wasm_runtime_set_instruction_count_limit(exec_env, gas);
|
||||||
|
return gas;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
ModuleWrapper::getGas()
|
||||||
|
{
|
||||||
|
return exec_env ? wasm_runtime_get_instruction_count_limit(exec_env) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// void
|
||||||
|
// WamrEngine::clearModules()
|
||||||
|
// {
|
||||||
|
// modules.clear();
|
||||||
|
// store.reset(); // to free the memory before creating new store
|
||||||
|
// store = {wasm_store_new(engine.get()), &wasm_store_delete};
|
||||||
|
// }
|
||||||
|
|
||||||
|
WamrEngine::WamrEngine()
|
||||||
|
: engine(wasm_engine_new(), &wasm_engine_delete)
|
||||||
|
, store(nullptr, &wasm_store_delete)
|
||||||
|
{
|
||||||
|
wasm_runtime_set_default_running_mode(Mode_Interp);
|
||||||
|
wasm_runtime_set_log_level(WASM_LOG_LEVEL_FATAL);
|
||||||
|
// wasm_runtime_set_log_level(WASM_LOG_LEVEL_VERBOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
WamrEngine::addModule(
|
||||||
|
wbytes const& wasmCode,
|
||||||
|
bool instantiate,
|
||||||
|
std::vector<WasmImportFunc> const& imports)
|
||||||
|
{
|
||||||
|
module.reset();
|
||||||
|
store.reset(); // to free the memory before creating new store
|
||||||
|
store = {wasm_store_new(engine.get()), &wasm_store_delete};
|
||||||
|
module = std::make_unique<ModuleWrapper>(
|
||||||
|
store.get(), wasmCode, instantiate, defMaxPages, imports);
|
||||||
|
setGas(defGas);
|
||||||
|
return module ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
WamrEngine::addInstance()
|
||||||
|
{
|
||||||
|
return module->addInstance(store.get(), defMaxPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_func_t*
|
||||||
|
WamrEngine::getFunc(std::string_view funcName)
|
||||||
|
{
|
||||||
|
return module->getFunc(funcName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<wasm_val_t>
|
||||||
|
WamrEngine::convertParams(std::vector<WasmParam> const& params)
|
||||||
|
{
|
||||||
|
std::vector<wasm_val_t> v;
|
||||||
|
v.reserve(params.size());
|
||||||
|
for (auto const& p : params)
|
||||||
|
{
|
||||||
|
switch (p.type)
|
||||||
|
{
|
||||||
|
case WT_I32:
|
||||||
|
v.push_back(WASM_I32_VAL(p.of.i32));
|
||||||
|
break;
|
||||||
|
case WT_I64:
|
||||||
|
v.push_back(WASM_I64_VAL(p.of.i64));
|
||||||
|
break;
|
||||||
|
case WT_F32:
|
||||||
|
v.push_back(WASM_F32_VAL(p.of.f32));
|
||||||
|
break;
|
||||||
|
case WT_F64:
|
||||||
|
v.push_back(WASM_F64_VAL(p.of.f64));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WamrEngine::add_param(std::vector<wasm_val_t>& in, int32_t p)
|
||||||
|
{
|
||||||
|
in.emplace_back();
|
||||||
|
auto& el(in.back());
|
||||||
|
memset(&el, 0, sizeof(el));
|
||||||
|
el = WASM_I32_VAL(p); // WASM_I32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WamrEngine::add_param(std::vector<wasm_val_t>& in, int64_t p)
|
||||||
|
{
|
||||||
|
in.emplace_back();
|
||||||
|
auto& el(in.back());
|
||||||
|
el = WASM_I64_VAL(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
WamrResult
|
||||||
|
WamrEngine::call(std::string_view func, Types... args)
|
||||||
|
{
|
||||||
|
// Lookup our export function
|
||||||
|
auto* f = getFunc(func);
|
||||||
|
return call<NR>(f, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
WamrResult
|
||||||
|
WamrEngine::call(wasm_func_t* func, Types... args)
|
||||||
|
{
|
||||||
|
std::vector<wasm_val_t> in;
|
||||||
|
return call<NR>(func, in, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
WamrResult
|
||||||
|
WamrEngine::call(wasm_func_t* func, std::vector<wasm_val_t>& in)
|
||||||
|
{
|
||||||
|
// wasm_val_t rs[1] = {WASM_I32_VAL(0)};
|
||||||
|
WamrResult ret(NR);
|
||||||
|
// if (NR) { wasm_val_vec_new_uninitialized(&ret, NR); //
|
||||||
|
// wasm_val_vec_new(&ret, NR, &rs[0]); // ret = WASM_ARRAY_VEC(rs); }
|
||||||
|
|
||||||
|
wasm_val_vec_t const inv = in.empty()
|
||||||
|
? wasm_val_vec_t WASM_EMPTY_VEC
|
||||||
|
: wasm_val_vec_t{
|
||||||
|
in.size(),
|
||||||
|
in.data(),
|
||||||
|
in.size(),
|
||||||
|
sizeof(std::remove_reference_t<decltype(in)>::value_type),
|
||||||
|
nullptr};
|
||||||
|
trap = wasm_func_call(func, &inv, &ret.r);
|
||||||
|
if (trap)
|
||||||
|
print_wasm_error("failed to call func", trap);
|
||||||
|
|
||||||
|
// assert(results[0].kind == WASM_I32);
|
||||||
|
// if (NR) printf("Result P5: %d\n", ret[0].of.i32);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
WamrResult
|
||||||
|
WamrEngine::call(
|
||||||
|
wasm_func_t* func,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
std::int32_t p,
|
||||||
|
Types... args)
|
||||||
|
{
|
||||||
|
add_param(in, p);
|
||||||
|
return call<NR>(func, in, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
WamrResult
|
||||||
|
WamrEngine::call(
|
||||||
|
wasm_func_t* func,
|
||||||
|
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
std::int64_t p,
|
||||||
|
Types... args)
|
||||||
|
{
|
||||||
|
add_param(in, p);
|
||||||
|
return call<NR>(func, in, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
WamrResult
|
||||||
|
WamrEngine::call(
|
||||||
|
wasm_func_t* func,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
uint8_t const* d,
|
||||||
|
std::size_t sz,
|
||||||
|
Types... args)
|
||||||
|
{
|
||||||
|
auto res = call<1>(W_ALLOC, static_cast<int32_t>(sz));
|
||||||
|
|
||||||
|
if (trap || (res.r.data[0].kind != WASM_I32))
|
||||||
|
return {};
|
||||||
|
auto const ptr = res.r.data[0].of.i32;
|
||||||
|
if (!ptr)
|
||||||
|
throw std::runtime_error(
|
||||||
|
"WAMR: can't allocate memory, " + std::to_string(sz) + " bytes");
|
||||||
|
|
||||||
|
auto mem = getMem();
|
||||||
|
memcpy(mem.p + ptr, d, sz);
|
||||||
|
|
||||||
|
add_param(in, ptr);
|
||||||
|
add_param(in, static_cast<int32_t>(sz));
|
||||||
|
return call<NR>(func, in, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
WamrResult
|
||||||
|
WamrEngine::call(
|
||||||
|
wasm_func_t* func,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
wbytes const& p,
|
||||||
|
Types... args)
|
||||||
|
{
|
||||||
|
return call<NR>(func, in, p.data(), p.size(), std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<int32_t, TER>
|
||||||
|
WamrEngine::run(
|
||||||
|
wbytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
std::vector<WasmParam> const& params)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return runHlp(wasmCode, funcName, imports, params);
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return Unexpected<TER>(tecFAILED_PROCESSING);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<int32_t, TER>
|
||||||
|
WamrEngine::runHlp(
|
||||||
|
wbytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
std::vector<WasmParam> const& params)
|
||||||
|
{
|
||||||
|
// Create and instantiate the module.
|
||||||
|
if (!wasmCode.empty())
|
||||||
|
{
|
||||||
|
int const m = addModule(wasmCode, true, imports);
|
||||||
|
if (m < 0)
|
||||||
|
return Unexpected<TER>(tecFAILED_PROCESSING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!module)
|
||||||
|
return Unexpected<TER>(tecFAILED_PROCESSING);
|
||||||
|
|
||||||
|
// Call main
|
||||||
|
auto* f = getFunc(!funcName.empty() ? funcName : "_start");
|
||||||
|
auto p = convertParams(params);
|
||||||
|
auto res = call<1>(f, p);
|
||||||
|
if (!res.r.size || trap)
|
||||||
|
return Unexpected<TER>(tecFAILED_PROCESSING);
|
||||||
|
|
||||||
|
assert(res.r.data[0].kind == WASM_I32);
|
||||||
|
// printf("Result: %d\n", results[0].of.i32);
|
||||||
|
// return res.r.data[0].of.i32 != 0;
|
||||||
|
return res.r.data[0].of.i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
WamrEngine::initGas(std::int64_t def)
|
||||||
|
{
|
||||||
|
defGas = def;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
WamrEngine::initMaxPages(std::int32_t def)
|
||||||
|
{
|
||||||
|
defMaxPages = def;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
WamrEngine::setGas(std::int64_t gas)
|
||||||
|
{
|
||||||
|
if (module)
|
||||||
|
{
|
||||||
|
module->setGas(gas);
|
||||||
|
return gas;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
WamrEngine::getGas()
|
||||||
|
{
|
||||||
|
return module ? module->getGas() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wmem
|
||||||
|
WamrEngine::getMem() const
|
||||||
|
{
|
||||||
|
return module ? module->getMem() : wmem();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
WamrEngine::allocate(int32_t sz)
|
||||||
|
{
|
||||||
|
auto res = call<1>(W_ALLOC, static_cast<int32_t>(sz));
|
||||||
|
if (trap || (res.r.data[0].kind != WASM_I32))
|
||||||
|
return {};
|
||||||
|
auto const ptr = res.r.data[0].of.i32;
|
||||||
|
if (!ptr)
|
||||||
|
throw std::runtime_error(
|
||||||
|
"WAMR: can't allocate memory, " + std::to_string(sz) + " bytes");
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
WamrEngine::newTrap(std::string_view txt)
|
||||||
|
{
|
||||||
|
wasm_message_t msg = WASM_EMPTY_VEC;
|
||||||
|
|
||||||
|
if (!txt.empty())
|
||||||
|
wasm_name_new(&msg, txt.size(), txt.data());
|
||||||
|
|
||||||
|
return wasm_trap_new(store.get(), &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
264
src/xrpld/app/misc/WamrVM.h
Normal file
264
src/xrpld/app/misc/WamrVM.h
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2023 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpld/app/misc/WasmVM.h>
|
||||||
|
|
||||||
|
#include <iwasm/wasm_c_api.h>
|
||||||
|
#include <iwasm/wasm_export.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
struct WamrResult
|
||||||
|
{
|
||||||
|
wasm_val_vec_t r;
|
||||||
|
WamrResult(unsigned N = 0):r{0, nullptr, 0, 0, nullptr} {if (N) wasm_val_vec_new_uninitialized(&r, N);}
|
||||||
|
~WamrResult() { if (r.size) wasm_val_vec_delete(&r); }
|
||||||
|
WamrResult(WamrResult const &) = delete;
|
||||||
|
WamrResult& operator=(WamrResult const &) = delete;
|
||||||
|
|
||||||
|
WamrResult(WamrResult &&o) {*this = std::move(o);}
|
||||||
|
WamrResult& operator=(WamrResult &&o){r = o.r; o.r = {0, nullptr, 0, 0, nullptr}; return *this;}
|
||||||
|
//operator wasm_val_vec_t &() {return r;}
|
||||||
|
};
|
||||||
|
|
||||||
|
using ModulePtr = std::unique_ptr<wasm_module_t, decltype(&wasm_module_delete)>;
|
||||||
|
using InstancePtr = std::unique_ptr<wasm_instance_t, decltype(&wasm_instance_delete)>;
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
struct InstanceWrapper
|
||||||
|
{
|
||||||
|
wasm_extern_vec_t exports;
|
||||||
|
InstancePtr mod_inst;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static InstancePtr
|
||||||
|
init(
|
||||||
|
wasm_store_t* s,
|
||||||
|
wasm_module_t* m,
|
||||||
|
int32_t maxPages,
|
||||||
|
wasm_extern_vec_t* expt,
|
||||||
|
wasm_extern_vec_t const& imports = WASM_EMPTY_VEC);
|
||||||
|
|
||||||
|
public:
|
||||||
|
InstanceWrapper();
|
||||||
|
|
||||||
|
InstanceWrapper(InstanceWrapper&& o);
|
||||||
|
|
||||||
|
InstanceWrapper&
|
||||||
|
operator=(InstanceWrapper&& o);
|
||||||
|
|
||||||
|
InstanceWrapper(
|
||||||
|
wasm_store_t* s,
|
||||||
|
wasm_module_t* m,
|
||||||
|
int32_t maxPages,
|
||||||
|
wasm_extern_vec_t const& imports = WASM_EMPTY_VEC);
|
||||||
|
|
||||||
|
~InstanceWrapper();
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
|
||||||
|
wasm_func_t*
|
||||||
|
getFunc(
|
||||||
|
std::string_view funcName,
|
||||||
|
wasm_exporttype_vec_t const& export_types) const;
|
||||||
|
|
||||||
|
wmem
|
||||||
|
getMem() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ModuleWrapper
|
||||||
|
{
|
||||||
|
ModulePtr module;
|
||||||
|
wasm_exec_env_t exec_env = nullptr;
|
||||||
|
InstanceWrapper mod_inst;
|
||||||
|
wasm_exporttype_vec_t export_types;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ModulePtr
|
||||||
|
init(wasm_store_t* s, wbytes const& wasmBin);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModuleWrapper();
|
||||||
|
ModuleWrapper(ModuleWrapper&& o);
|
||||||
|
ModuleWrapper&
|
||||||
|
operator=(ModuleWrapper&& o);
|
||||||
|
ModuleWrapper(
|
||||||
|
wasm_store_t* s,
|
||||||
|
wbytes const& wasmBin,
|
||||||
|
bool instantiate,
|
||||||
|
int32_t maxPages,
|
||||||
|
std::vector<WasmImportFunc> const& imports = {});
|
||||||
|
~ModuleWrapper();
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
|
||||||
|
wasm_func_t*
|
||||||
|
getFunc(std::string_view funcName) const;
|
||||||
|
wmem
|
||||||
|
getMem() const;
|
||||||
|
|
||||||
|
int
|
||||||
|
addInstance(
|
||||||
|
wasm_store_t* s,
|
||||||
|
int32_t maxPages,
|
||||||
|
wasm_extern_vec_t const& imports = WASM_EMPTY_VEC);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
setGas(std::int64_t gas);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
getGas();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void
|
||||||
|
makeImpParams(wasm_valtype_vec_t& v, WasmImportFunc const& imp);
|
||||||
|
static void
|
||||||
|
makeImpReturn(wasm_valtype_vec_t& v, WasmImportFunc const& imp);
|
||||||
|
wasm_extern_vec_t
|
||||||
|
buildImports(wasm_store_t* s, std::vector<WasmImportFunc> const& imports);
|
||||||
|
};
|
||||||
|
|
||||||
|
class WamrEngine
|
||||||
|
{
|
||||||
|
std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)> engine;
|
||||||
|
std::unique_ptr<wasm_store_t, decltype(&wasm_store_delete)> store;
|
||||||
|
std::unique_ptr<ModuleWrapper> module;
|
||||||
|
wasm_trap_t* trap = nullptr;
|
||||||
|
std::int64_t defGas = -1;
|
||||||
|
std::int32_t defMaxPages = -1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WamrEngine();
|
||||||
|
~WamrEngine() = default;
|
||||||
|
|
||||||
|
Expected<int32_t, TER>
|
||||||
|
run(wbytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
std::vector<WasmParam> const& params);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
initGas(std::int64_t def);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
setGas(std::int64_t gas);
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
initMaxPages(std::int32_t def);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
getGas();
|
||||||
|
|
||||||
|
// Host functions helper functionality
|
||||||
|
wmem
|
||||||
|
getMem() const;
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
allocate(int32_t size);
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
newTrap(std::string_view msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Expected<int32_t, TER>
|
||||||
|
runHlp(
|
||||||
|
wbytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
std::vector<WasmParam> const& params);
|
||||||
|
|
||||||
|
int
|
||||||
|
addModule(
|
||||||
|
wbytes const& wasmCode,
|
||||||
|
bool instantiate,
|
||||||
|
std::vector<WasmImportFunc> const& imports);
|
||||||
|
void
|
||||||
|
clearModules();
|
||||||
|
int
|
||||||
|
addInstance();
|
||||||
|
int32_t
|
||||||
|
runFunc(std::string_view const funcName, int32_t p);
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
makeModule(
|
||||||
|
wbytes const& wasmCode,
|
||||||
|
wasm_extern_vec_t const& imports = WASM_EMPTY_VEC);
|
||||||
|
|
||||||
|
wasm_func_t*
|
||||||
|
getFunc(std::string_view funcName);
|
||||||
|
|
||||||
|
std::vector<wasm_val_t>
|
||||||
|
convertParams(std::vector<WasmParam> const& params);
|
||||||
|
|
||||||
|
void
|
||||||
|
add_param(std::vector<wasm_val_t>& in, int32_t p);
|
||||||
|
void
|
||||||
|
add_param(std::vector<wasm_val_t>& in, int64_t p);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(std::string_view func, Types... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(wasm_func_t* func, Types... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(wasm_func_t* f, std::vector<wasm_val_t>& in);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(
|
||||||
|
wasm_func_t* func,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
std::int32_t p,
|
||||||
|
Types... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(
|
||||||
|
wasm_func_t* func,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
std::int64_t p,
|
||||||
|
Types... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(
|
||||||
|
wasm_func_t* func,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
uint8_t const* d,
|
||||||
|
std::size_t sz,
|
||||||
|
Types... args);
|
||||||
|
|
||||||
|
template <int NR, class... Types>
|
||||||
|
inline WamrResult
|
||||||
|
call(
|
||||||
|
wasm_func_t* func,
|
||||||
|
std::vector<wasm_val_t>& in,
|
||||||
|
wbytes const& p,
|
||||||
|
Types... args);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
@@ -19,14 +19,12 @@
|
|||||||
#ifndef RIPPLE_APP_MISC_WASMHOSTFUNCIMPL_H_INLCUDED
|
#ifndef RIPPLE_APP_MISC_WASMHOSTFUNCIMPL_H_INLCUDED
|
||||||
#define RIPPLE_APP_MISC_WASMHOSTFUNCIMPL_H_INLCUDED
|
#define RIPPLE_APP_MISC_WASMHOSTFUNCIMPL_H_INLCUDED
|
||||||
|
|
||||||
|
#include <xrpld/app/misc/WasmVM.h>
|
||||||
|
#include <xrpld/app/tx/detail/ApplyContext.h>
|
||||||
|
|
||||||
#include <xrpl/basics/Expected.h>
|
#include <xrpl/basics/Expected.h>
|
||||||
#include <xrpl/protocol/TER.h>
|
#include <xrpl/protocol/TER.h>
|
||||||
|
|
||||||
#include "xrpl/basics/base_uint.h"
|
|
||||||
#include "xrpld/app/misc/WasmVM.h"
|
|
||||||
#include "xrpld/app/tx/detail/ApplyContext.h"
|
|
||||||
#include <wasmedge/wasmedge.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
class WasmHostFunctionsImpl : public HostFunctions
|
class WasmHostFunctionsImpl : public HostFunctions
|
||||||
{
|
{
|
||||||
|
|||||||
392
src/xrpld/app/misc/WasmHostFuncWrapper.cpp
Normal file
392
src/xrpld/app/misc/WasmHostFuncWrapper.cpp
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <xrpld/app/misc/WasmHostFuncWrapper.h>
|
||||||
|
#include <xrpld/app/tx/detail/NFTokenUtils.h>
|
||||||
|
|
||||||
|
#include <xrpl/protocol/digest.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerSqn_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
int32_t const sqn = hf->getLedgerSqn();
|
||||||
|
results->data[0] = WASM_I32_VAL(sqn);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
getParentLedgerTime_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
int32_t const ltime = hf->getParentLedgerTime();
|
||||||
|
results->data[0] = WASM_I32_VAL(ltime);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Expected<Bytes, std::string>
|
||||||
|
getParameterData(wasm_val_vec_t const* params, size_t index)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto fnameOffset = params->data[index].of.i32;
|
||||||
|
auto fnameLen = params->data[index + 1].of.i32;
|
||||||
|
auto mem = vm.getMem();
|
||||||
|
if (!mem.s)
|
||||||
|
return Unexpected<std::string>("No memory exported");
|
||||||
|
|
||||||
|
if (mem.s <= fnameOffset + fnameLen)
|
||||||
|
return Unexpected<std::string>("Memory access failed");
|
||||||
|
Bytes fname(mem.p + fnameOffset, mem.p + fnameOffset + fnameLen);
|
||||||
|
return fname;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Expected<std::string, wasm_trap_t*>
|
||||||
|
getFieldName(wasm_val_vec_t const* params, size_t index)
|
||||||
|
{
|
||||||
|
auto const dataRes = getParameterData(params, index);
|
||||||
|
if (dataRes)
|
||||||
|
{
|
||||||
|
return std::string(dataRes->begin(), dataRes->end());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
return Unexpected<wasm_trap_t*>(
|
||||||
|
reinterpret_cast<wasm_trap_t*>(vm.newTrap(dataRes.error())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Expected<int32_t, std::string>
|
||||||
|
setData(Bytes const& data)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto mem = vm.getMem();
|
||||||
|
if (!mem.s)
|
||||||
|
return Unexpected<std::string>("No memory exported");
|
||||||
|
|
||||||
|
int32_t const dataLen = static_cast<int32_t>(data.size());
|
||||||
|
int32_t const dataPtr = vm.allocate(dataLen);
|
||||||
|
if (!dataPtr)
|
||||||
|
return Unexpected<std::string>("Allocation error");
|
||||||
|
memcpy(mem.p + dataPtr, data.data(), dataLen);
|
||||||
|
|
||||||
|
auto retPtr = vm.allocate(8);
|
||||||
|
if (!retPtr)
|
||||||
|
return Unexpected<std::string>("Allocation error");
|
||||||
|
int32_t* retData = reinterpret_cast<int32_t*>(mem.p + retPtr);
|
||||||
|
retData[0] = dataPtr;
|
||||||
|
retData[1] = dataLen;
|
||||||
|
|
||||||
|
return retPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
getTxField_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto fname = getFieldName(params, 0);
|
||||||
|
if (!fname)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto fieldData = hf->getTxField(fname.value());
|
||||||
|
if (!fieldData)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap("Field not found"));
|
||||||
|
|
||||||
|
auto pointer = setData(fieldData.value());
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32((int)fieldData.value().size());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerEntryField_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
int32_t const type = params->data[0].of.i32;
|
||||||
|
auto lkData = getParameterData(params, 1);
|
||||||
|
if (!lkData)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto fname = getFieldName(params, 3);
|
||||||
|
if (!fname)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto fieldData =
|
||||||
|
hf->getLedgerEntryField(type, lkData.value(), fname.value());
|
||||||
|
if (!fieldData)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
auto pointer = setData(fieldData.value());
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32((int)fieldData.value().size());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
getCurrentLedgerEntryField_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto fname = getFieldName(params, 0);
|
||||||
|
if (!fname)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto fieldData = hf->getCurrentLedgerEntryField(fname.value());
|
||||||
|
if (!fieldData)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto pointer = setData(fieldData.value());
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32((int)fieldData.value().size());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
getNFT_wrap(void* env, const wasm_val_vec_t* params, wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
auto account = getFieldName(params, 0);
|
||||||
|
if (!account)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto nftId = getFieldName(params, 2);
|
||||||
|
if (!nftId)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto nftURI = hf->getNFT(account.value(), nftId.value());
|
||||||
|
if (!nftURI)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto pointer = setData(nftURI.value());
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
accountKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto account = getFieldName(params, 0);
|
||||||
|
if (!account)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto keylet = hf->accountKeylet(account.value());
|
||||||
|
if (!keylet)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto pointer = setData(keylet.value());
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
credentialKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto subject = getFieldName(params, 0);
|
||||||
|
if (!subject)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto issuer = getFieldName(params, 2);
|
||||||
|
if (!issuer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto credentialType = getFieldName(params, 4);
|
||||||
|
if (!credentialType)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto keylet = hf->credentialKeylet(
|
||||||
|
subject.value(), issuer.value(), credentialType.value());
|
||||||
|
if (!keylet)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto pointer = setData(keylet.value());
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
escrowKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto account = getFieldName(params, 0);
|
||||||
|
if (!account)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
int32_t const sequence = params->data[2].of.i32;
|
||||||
|
|
||||||
|
auto keylet = hf->escrowKeylet(account.value(), sequence);
|
||||||
|
if (!keylet)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto pointer = setData(keylet.value());
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
oracleKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto account = getFieldName(params, 0);
|
||||||
|
if (!account)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto documentId = params->data[2].of.i32;
|
||||||
|
|
||||||
|
auto keylet = hf->escrowKeylet(account.value(), documentId);
|
||||||
|
if (!keylet)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto pointer = setData(keylet.value());
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
updateData_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto fname = getParameterData(params, 0);
|
||||||
|
if (!fname)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
if (!hf->updateData(fname.value()))
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
computeSha512HalfHash_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto fname = getParameterData(params, 0);
|
||||||
|
if (!fname)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
auto hres = hf->computeSha512HalfHash(fname.value());
|
||||||
|
Bytes digest{hres.begin(), hres.end()};
|
||||||
|
auto pointer = setData(digest);
|
||||||
|
if (!pointer)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
|
||||||
|
results->data[0] = WASM_I32_VAL(pointer.value());
|
||||||
|
// out[1] = WasmEdge_ValueGenI32(32);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_trap_t*
|
||||||
|
print_wrap(void* env, const wasm_val_vec_t* params, wasm_val_vec_t* results)
|
||||||
|
{
|
||||||
|
auto& vm = WasmEngine::instance();
|
||||||
|
// auto* hf = reinterpret_cast<HostFunctions*>(env);
|
||||||
|
|
||||||
|
auto f = getParameterData(params, 0);
|
||||||
|
if (!f)
|
||||||
|
return reinterpret_cast<wasm_trap_t*>(vm.newTrap());
|
||||||
|
std::string s(f->begin(), f->end());
|
||||||
|
if (s.size() < 4096)
|
||||||
|
std::cout << s << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
113
src/xrpld/app/misc/WasmHostFuncWrapper.h
Normal file
113
src/xrpld/app/misc/WasmHostFuncWrapper.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2025 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpld/app/misc/WamrVM.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
using getLedgerSqn_proto = int32_t();
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerSqn_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getParentLedgerTime_proto = int32_t();
|
||||||
|
wasm_trap_t*
|
||||||
|
getParentLedgerTime_wrap(
|
||||||
|
void* env,
|
||||||
|
wasm_val_vec_t const* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getTxField_proto = uint32_t*(char const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getTxField_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getLedgerEntryField_proto =
|
||||||
|
uint32_t*(int32_t, uint8_t const*, int32_t, char const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getLedgerEntryField_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getCurrentLedgerEntryField_proto = uint32_t*(char const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getCurrentLedgerEntryField_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using getNFT_proto = uint32_t*(char const*, int32_t, char const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
getNFT_wrap(void* env, const wasm_val_vec_t* params, wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using accountKeylet_proto = uint32_t*(char const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
accountKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using credentialKeylet_proto =
|
||||||
|
uint32_t*(char const*, int32_t, char const*, int32_t, char const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
credentialKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using escrowKeylet_proto = uint32_t*(char const*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
escrowKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using oracleKeylet_proto = uint32_t*(char const*, int32_t, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
oracleKeylet_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using updateData_proto = void(uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
updateData_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using computeSha512HalfHash_proto = uint32_t*(uint8_t const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
computeSha512HalfHash_wrap(
|
||||||
|
void* env,
|
||||||
|
const wasm_val_vec_t* params,
|
||||||
|
wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
using print_proto = void(char const*, int32_t);
|
||||||
|
wasm_trap_t*
|
||||||
|
print_wrap(void* env, const wasm_val_vec_t* params, wasm_val_vec_t* results);
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
@@ -17,730 +17,118 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <xrpld/app/misc/WasmVM.h>
|
#include <xrpld/app/misc/WamrVM.h>
|
||||||
|
#include <xrpld/app/misc/WasmHostFuncWrapper.h>
|
||||||
|
|
||||||
#include "xrpl/protocol/AccountID.h"
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include "xrpl/protocol/LedgerFormats.h"
|
#include <xrpl/protocol/LedgerFormats.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
getLedgerSqn(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext*,
|
|
||||||
const WasmEdge_Value*,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
out[0] = WasmEdge_ValueGenI32(((HostFunctions*)data)->getLedgerSqn());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
getParentLedgerTime(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext*,
|
|
||||||
const WasmEdge_Value*,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
out[0] =
|
|
||||||
WasmEdge_ValueGenI32(((HostFunctions*)data)->getParentLedgerTime());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expected<Bytes, WasmEdge_Result>
|
|
||||||
getParameterData(
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
size_t index)
|
|
||||||
{
|
|
||||||
auto fnameOffset = (uint32_t)WasmEdge_ValueGetI32(in[index]);
|
|
||||||
auto fnameLen = (uint32_t)WasmEdge_ValueGetI32(in[index + 1]);
|
|
||||||
Bytes fname(fnameLen, char{0});
|
|
||||||
WasmEdge_MemoryInstanceContext* mem =
|
|
||||||
WasmEdge_CallingFrameGetMemoryInstance(fm, 0);
|
|
||||||
WasmEdge_Result Res = WasmEdge_MemoryInstanceGetData(
|
|
||||||
mem, (uint8_t*)(fname.data()), fnameOffset, fnameLen);
|
|
||||||
if (WasmEdge_ResultOK(Res))
|
|
||||||
{
|
|
||||||
return fname;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Unexpected<WasmEdge_Result>(Res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Expected<std::string, WasmEdge_Result>
|
|
||||||
getFieldName(
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
size_t index)
|
|
||||||
{
|
|
||||||
auto dataRes = getParameterData(fm, in, index);
|
|
||||||
if (dataRes)
|
|
||||||
{
|
|
||||||
return std::string(dataRes.value().begin(), dataRes->end());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Unexpected<WasmEdge_Result>(dataRes.error());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Expected<WasmEdge_Value, WasmEdge_Result>
|
|
||||||
setData(const WasmEdge_CallingFrameContext* fm, Bytes const& data)
|
|
||||||
{
|
|
||||||
auto alloc = [fm](int32_t dataLen) -> int32_t {
|
|
||||||
WasmEdge_String allocFunc = WasmEdge_StringCreateByCString("allocate");
|
|
||||||
auto mod = WasmEdge_CallingFrameGetModuleInstance(fm);
|
|
||||||
WasmEdge_FunctionInstanceContext* func =
|
|
||||||
WasmEdge_ModuleInstanceFindFunction(mod, allocFunc);
|
|
||||||
WasmEdge_Value allocParams[1] = {
|
|
||||||
WasmEdge_ValueGenI32(dataLen)}; // 4 for prepend the data size
|
|
||||||
WasmEdge_Value allocReturns[1];
|
|
||||||
auto executor = WasmEdge_CallingFrameGetExecutor(fm);
|
|
||||||
auto res = WasmEdge_ExecutorInvoke(
|
|
||||||
executor, func, allocParams, 1, allocReturns, 1);
|
|
||||||
if (WasmEdge_ResultOK(res))
|
|
||||||
{
|
|
||||||
return WasmEdge_ValueGetI32(allocReturns[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto dataLen = (int32_t)data.size();
|
|
||||||
auto dataPtr = alloc(dataLen);
|
|
||||||
auto retPtr = alloc(8);
|
|
||||||
if (dataPtr && retPtr)
|
|
||||||
{
|
|
||||||
auto mem = WasmEdge_CallingFrameGetMemoryInstance(fm, 0);
|
|
||||||
auto res =
|
|
||||||
WasmEdge_MemoryInstanceSetData(mem, data.data(), dataPtr, dataLen);
|
|
||||||
if (WasmEdge_ResultOK(res))
|
|
||||||
{
|
|
||||||
unsigned char intBuf[8]; // little-endian
|
|
||||||
for (size_t i = 0; i < 4; ++i)
|
|
||||||
{
|
|
||||||
intBuf[i] = (dataPtr >> (i * 8)) & 0xFF;
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < 4; ++i)
|
|
||||||
{
|
|
||||||
intBuf[i + 4] = (dataLen >> (i * 8)) & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = WasmEdge_MemoryInstanceSetData(mem, intBuf, retPtr, 8);
|
|
||||||
if (WasmEdge_ResultOK(res))
|
|
||||||
{
|
|
||||||
return WasmEdge_ValueGenI32(retPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Unexpected<WasmEdge_Result>(WasmEdge_Result_Fail);
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
getTxField(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto fname = getFieldName(fm, in, 0);
|
|
||||||
if (!fname)
|
|
||||||
return fname.error();
|
|
||||||
|
|
||||||
auto fieldData = ((HostFunctions*)data)->getTxField(fname.value());
|
|
||||||
if (!fieldData)
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
|
|
||||||
auto pointer = setData(fm, fieldData.value());
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32((int)fieldData.value().size());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
getLedgerEntryField(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto type = WasmEdge_ValueGetI32(in[0]);
|
|
||||||
auto lkData = getParameterData(fm, in, 1);
|
|
||||||
if (!lkData)
|
|
||||||
return lkData.error();
|
|
||||||
|
|
||||||
auto fname = getFieldName(fm, in, 3);
|
|
||||||
if (!fname)
|
|
||||||
return fname.error();
|
|
||||||
|
|
||||||
auto fieldData =
|
|
||||||
((HostFunctions*)data)
|
|
||||||
->getLedgerEntryField(type, lkData.value(), fname.value());
|
|
||||||
if (!fieldData)
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
auto pointer = setData(fm, fieldData.value());
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32((int)fieldData.value().size());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
getCurrentLedgerEntryField(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto fname = getFieldName(fm, in, 0);
|
|
||||||
if (!fname)
|
|
||||||
return fname.error();
|
|
||||||
|
|
||||||
auto fieldData =
|
|
||||||
((HostFunctions*)data)->getCurrentLedgerEntryField(fname.value());
|
|
||||||
if (!fieldData)
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
|
|
||||||
auto pointer = setData(fm, fieldData.value());
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32((int)fieldData.value().size());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
getNFT(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto account = getFieldName(fm, in, 0);
|
|
||||||
if (!account)
|
|
||||||
return account.error();
|
|
||||||
|
|
||||||
auto nftId = getFieldName(fm, in, 2);
|
|
||||||
if (!nftId)
|
|
||||||
return nftId.error();
|
|
||||||
|
|
||||||
auto nftURI =
|
|
||||||
((HostFunctions*)data)->getNFT(account.value(), nftId.value());
|
|
||||||
if (!nftURI)
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
|
|
||||||
auto pointer = setData(fm, nftURI.value());
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
accountKeylet(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto account = getFieldName(fm, in, 0);
|
|
||||||
if (!account)
|
|
||||||
return account.error();
|
|
||||||
|
|
||||||
auto keylet = ((HostFunctions*)data)->accountKeylet(account.value());
|
|
||||||
if (!keylet)
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
|
|
||||||
auto pointer = setData(fm, keylet.value());
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
credentialKeylet(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto subject = getFieldName(fm, in, 0);
|
|
||||||
if (!subject)
|
|
||||||
return subject.error();
|
|
||||||
|
|
||||||
auto issuer = getFieldName(fm, in, 2);
|
|
||||||
if (!issuer)
|
|
||||||
return issuer.error();
|
|
||||||
|
|
||||||
auto credentialType = getFieldName(fm, in, 4);
|
|
||||||
if (!credentialType)
|
|
||||||
return credentialType.error();
|
|
||||||
|
|
||||||
auto keylet =
|
|
||||||
((HostFunctions*)data)
|
|
||||||
->credentialKeylet(
|
|
||||||
subject.value(), issuer.value(), credentialType.value());
|
|
||||||
if (!keylet)
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
|
|
||||||
auto pointer = setData(fm, keylet.value());
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
escrowKeylet(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto account = getFieldName(fm, in, 0);
|
|
||||||
if (!account)
|
|
||||||
return account.error();
|
|
||||||
|
|
||||||
auto sequence = WasmEdge_ValueGetI32(in[2]);
|
|
||||||
|
|
||||||
auto keylet =
|
|
||||||
((HostFunctions*)data)->escrowKeylet(account.value(), sequence);
|
|
||||||
if (!keylet)
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
|
|
||||||
auto pointer = setData(fm, keylet.value());
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
oracleKeylet(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto account = getFieldName(fm, in, 0);
|
|
||||||
if (!account)
|
|
||||||
return account.error();
|
|
||||||
|
|
||||||
auto documentId = WasmEdge_ValueGetI32(in[2]);
|
|
||||||
|
|
||||||
auto keylet =
|
|
||||||
((HostFunctions*)data)->escrowKeylet(account.value(), documentId);
|
|
||||||
if (!keylet)
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
|
|
||||||
auto pointer = setData(fm, keylet.value());
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32((int)nftURI.value().size());
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
updateData(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto fname = getParameterData(fm, in, 0);
|
|
||||||
if (!fname)
|
|
||||||
return fname.error();
|
|
||||||
|
|
||||||
if (((HostFunctions*)data)->updateData(fname.value()))
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
else
|
|
||||||
return WasmEdge_Result_Fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
computeSha512HalfHash(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto fname = getParameterData(fm, in, 0);
|
|
||||||
if (!fname)
|
|
||||||
return fname.error();
|
|
||||||
|
|
||||||
auto hres = ((HostFunctions*)data)->computeSha512HalfHash(fname.value());
|
|
||||||
Bytes digest{hres.begin(), hres.end()};
|
|
||||||
auto pointer = setData(fm, digest);
|
|
||||||
if (!pointer)
|
|
||||||
return pointer.error();
|
|
||||||
|
|
||||||
out[0] = pointer.value();
|
|
||||||
// out[1] = WasmEdge_ValueGenI32(32);
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result
|
|
||||||
print(
|
|
||||||
void* data,
|
|
||||||
const WasmEdge_CallingFrameContext* fm,
|
|
||||||
const WasmEdge_Value* in,
|
|
||||||
WasmEdge_Value* out)
|
|
||||||
{
|
|
||||||
auto f = getParameterData(fm, in, 0);
|
|
||||||
if (!f)
|
|
||||||
return f.error();
|
|
||||||
std::string s(f.value().begin(), f.value().end());
|
|
||||||
std::cout << s << std::endl;
|
|
||||||
return WasmEdge_Result_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expected<EscrowResult, TER>
|
Expected<EscrowResult, TER>
|
||||||
runEscrowWasm(
|
runEscrowWasm(
|
||||||
std::vector<uint8_t> const& wasmCode,
|
Bytes const& wasmCode,
|
||||||
std::string const& funcName,
|
std::string_view funcName,
|
||||||
HostFunctions* hfs,
|
HostFunctions* hfs,
|
||||||
uint64_t gasLimit)
|
uint64_t gasLimit)
|
||||||
{
|
{
|
||||||
// WasmEdge_LogOff();
|
|
||||||
// TODO deletes
|
|
||||||
// create VM and set cost limit
|
// create VM and set cost limit
|
||||||
WasmEdge_ConfigureContext* conf = WasmEdge_ConfigureCreate();
|
auto& vm = WasmEngine::instance();
|
||||||
WasmEdge_ConfigureStatisticsSetInstructionCounting(conf, true);
|
vm.initGas(gasLimit);
|
||||||
WasmEdge_ConfigureStatisticsSetCostMeasuring(conf, true);
|
vm.initMaxPages(MAX_PAGES);
|
||||||
WasmEdge_ConfigureSetMaxMemoryPage(conf, MAX_PAGES);
|
|
||||||
|
|
||||||
WasmEdge_VMContext* VMCxt = WasmEdge_VMCreate(conf, NULL);
|
std::vector<WasmImportFunc> imports;
|
||||||
WasmEdge_StatisticsContext* StatCxt =
|
|
||||||
WasmEdge_VMGetStatisticsContext(VMCxt);
|
|
||||||
WasmEdge_StatisticsSetCostLimit(StatCxt, gasLimit);
|
|
||||||
|
|
||||||
{ // register host function
|
WASM_IMPORT_FUNC(imports, getLedgerSqn, hfs)
|
||||||
// module
|
WASM_IMPORT_FUNC(imports, getParentLedgerTime, hfs)
|
||||||
WasmEdge_String libName = WasmEdge_StringCreateByCString("host_lib");
|
WASM_IMPORT_FUNC(imports, getTxField, hfs)
|
||||||
WasmEdge_ModuleInstanceContext* hostMod =
|
WASM_IMPORT_FUNC(imports, getLedgerEntryField, hfs)
|
||||||
WasmEdge_ModuleInstanceCreate(libName);
|
WASM_IMPORT_FUNC(imports, getCurrentLedgerEntryField, hfs)
|
||||||
WasmEdge_StringDelete(libName);
|
WASM_IMPORT_FUNC(imports, getNFT, hfs)
|
||||||
|
WASM_IMPORT_FUNC(imports, accountKeylet, hfs)
|
||||||
|
WASM_IMPORT_FUNC(imports, credentialKeylet, hfs)
|
||||||
|
WASM_IMPORT_FUNC(imports, escrowKeylet, hfs)
|
||||||
|
WASM_IMPORT_FUNC(imports, oracleKeylet, hfs)
|
||||||
|
WASM_IMPORT_FUNC(imports, updateData, hfs)
|
||||||
|
WASM_IMPORT_FUNC(imports, computeSha512HalfHash, hfs)
|
||||||
|
WASM_IMPORT_FUNC(imports, print, hfs)
|
||||||
|
|
||||||
// getLedgerSqn
|
std::int64_t const sgas = gasLimit; // vm.getGas();
|
||||||
{
|
auto ret = vm.run(wasmCode, funcName, imports);
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
if (!ret.has_value())
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
return Unexpected<TER>(ret.error());
|
||||||
WasmEdge_FunctionTypeCreate(NULL, 0, returnList, 1);
|
std::int64_t const egas = vm.getGas();
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
std::uint64_t const spent = static_cast<std::uint64_t>(sgas - egas);
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, getLedgerSqn, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
return EscrowResult{static_cast<bool>(ret.value()), spent};
|
||||||
WasmEdge_StringCreateByCString("getLedgerSqn");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// getParentLedgerTime
|
|
||||||
{
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(NULL, 0, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, getParentLedgerTime, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("getParentLedgerTime");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTxField
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[2] = {
|
|
||||||
WasmEdge_ValTypeGenI32(), WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 2, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, getTxField, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("getTxField");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// getLedgerEntryField
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[5] = {
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 5, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, getLedgerEntryField, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("getLedgerEntryField");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// getCurrentLedgerEntryField
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[2] = {
|
|
||||||
WasmEdge_ValTypeGenI32(), WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 2, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, getCurrentLedgerEntryField, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("getCurrentLedgerEntryField");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// getNFT
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[4] = {
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 2, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(hostFuncType, getNFT, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName = WasmEdge_StringCreateByCString("getNFT");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// updateData
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[2] = {
|
|
||||||
WasmEdge_ValTypeGenI32(), WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 2, NULL, 0);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, updateData, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("updateData");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// computeSha512HalfHash
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[2] = {
|
|
||||||
WasmEdge_ValTypeGenI32(), WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 2, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, computeSha512HalfHash, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("computeSha512HalfHash");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// accountKeylet
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[2] = {
|
|
||||||
WasmEdge_ValTypeGenI32(), WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 2, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, accountKeylet, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("accountKeylet");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// credentialKeylet
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[6] = {
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 6, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, credentialKeylet, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("credentialKeylet");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// escrowKeylet
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[3] = {
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 3, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, escrowKeylet, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("escrowKeylet");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// oracleKeylet
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[3] = {
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32(),
|
|
||||||
WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_ValType returnList[1] = {WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 3, returnList, 1);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(
|
|
||||||
hostFuncType, oracleKeylet, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName =
|
|
||||||
WasmEdge_StringCreateByCString("oracleKeylet");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
// print
|
|
||||||
{
|
|
||||||
WasmEdge_ValType inputList[2] = {
|
|
||||||
WasmEdge_ValTypeGenI32(), WasmEdge_ValTypeGenI32()};
|
|
||||||
WasmEdge_FunctionTypeContext* hostFuncType =
|
|
||||||
WasmEdge_FunctionTypeCreate(inputList, 2, NULL, 0);
|
|
||||||
WasmEdge_FunctionInstanceContext* hostFunc =
|
|
||||||
WasmEdge_FunctionInstanceCreate(hostFuncType, print, hfs, 100);
|
|
||||||
// WasmEdge_FunctionTypeDelete(hostFuncType);
|
|
||||||
// WasmEdge_FunctionInstanceDelete(hostFunc);
|
|
||||||
|
|
||||||
WasmEdge_String fName = WasmEdge_StringCreateByCString("print");
|
|
||||||
WasmEdge_ModuleInstanceAddFunction(hostMod, fName, hostFunc);
|
|
||||||
// WasmEdge_StringDelete(fName);
|
|
||||||
}
|
|
||||||
WasmEdge_Result regRe =
|
|
||||||
WasmEdge_VMRegisterModuleFromImport(VMCxt, hostMod);
|
|
||||||
if (!WasmEdge_ResultOK(regRe))
|
|
||||||
{
|
|
||||||
printf("host func reg error\n");
|
|
||||||
return Unexpected<TER>(tecFAILED_PROCESSING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_Result loadRes =
|
|
||||||
WasmEdge_VMLoadWasmFromBuffer(VMCxt, wasmCode.data(), wasmCode.size());
|
|
||||||
if (!WasmEdge_ResultOK(loadRes))
|
|
||||||
{
|
|
||||||
printf("load error, %p, %d\n", wasmCode.data(), wasmCode.size());
|
|
||||||
return Unexpected<TER>(tecFAILED_PROCESSING);
|
|
||||||
}
|
|
||||||
WasmEdge_Result validateRes = WasmEdge_VMValidate(VMCxt);
|
|
||||||
if (!WasmEdge_ResultOK(validateRes))
|
|
||||||
{
|
|
||||||
printf("validate error\n");
|
|
||||||
return Unexpected<TER>(tecFAILED_PROCESSING);
|
|
||||||
}
|
|
||||||
WasmEdge_Result instantiateRes = WasmEdge_VMInstantiate(VMCxt);
|
|
||||||
if (!WasmEdge_ResultOK(instantiateRes))
|
|
||||||
{
|
|
||||||
printf("instantiate error\n");
|
|
||||||
return Unexpected<TER>(tecFAILED_PROCESSING);
|
|
||||||
}
|
|
||||||
WasmEdge_Value funcReturns[1];
|
|
||||||
WasmEdge_String func = WasmEdge_StringCreateByCString(funcName.c_str());
|
|
||||||
WasmEdge_Result funcRes =
|
|
||||||
WasmEdge_VMExecute(VMCxt, func, NULL, 0, funcReturns, 1);
|
|
||||||
|
|
||||||
bool ok = WasmEdge_ResultOK(funcRes);
|
|
||||||
EscrowResult re;
|
|
||||||
if (ok)
|
|
||||||
{
|
|
||||||
auto sc = WasmEdge_VMGetStatisticsContext(VMCxt);
|
|
||||||
re.cost = WasmEdge_StatisticsGetTotalCost(sc);
|
|
||||||
// WasmEdge_StatisticsGetTotalCost, WasmEdge_StatisticsGetInstrCount
|
|
||||||
auto result = WasmEdge_ValueGetI32(funcReturns[0]);
|
|
||||||
if (result != 0)
|
|
||||||
re.result = true;
|
|
||||||
else
|
|
||||||
re.result = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Error message: %s\n", WasmEdge_ResultGetMessage(funcRes));
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmEdge_VMDelete(VMCxt);
|
|
||||||
WasmEdge_StringDelete(func);
|
|
||||||
// delete other obj allocated
|
|
||||||
if (ok)
|
|
||||||
return re;
|
|
||||||
else
|
|
||||||
return Unexpected<TER>(tecFAILED_PROCESSING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
WasmEngine::WasmEngine() : impl(std::make_unique<WamrEngine>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WasmEngine&
|
||||||
|
WasmEngine::instance()
|
||||||
|
{
|
||||||
|
static WasmEngine e;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<int32_t, TER>
|
||||||
|
WasmEngine::run(
|
||||||
|
wbytes const& wasmCode,
|
||||||
|
std::string_view funcName,
|
||||||
|
std::vector<WasmImportFunc> const& imports,
|
||||||
|
std::vector<WasmParam> const& params)
|
||||||
|
{
|
||||||
|
return impl->run(wasmCode, funcName, imports, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
WasmEngine::initGas(std::int64_t def)
|
||||||
|
{
|
||||||
|
return impl->initGas(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
WasmEngine::initMaxPages(std::int32_t def)
|
||||||
|
{
|
||||||
|
return impl->initMaxPages(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
// gas = 1'000'000'000LL
|
||||||
|
std::int64_t
|
||||||
|
WasmEngine::setGas(std::int64_t gas)
|
||||||
|
{
|
||||||
|
return impl->setGas(gas);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
WasmEngine::getGas()
|
||||||
|
{
|
||||||
|
return impl->getGas();
|
||||||
|
}
|
||||||
|
|
||||||
|
wmem
|
||||||
|
WasmEngine::getMem() const
|
||||||
|
{
|
||||||
|
return impl->getMem();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
WasmEngine::allocate(int32_t size)
|
||||||
|
{
|
||||||
|
return impl->allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
WasmEngine::newTrap(std::string_view msg)
|
||||||
|
{
|
||||||
|
return impl->newTrap(msg);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|||||||
@@ -16,16 +16,43 @@
|
|||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
#ifndef RIPPLE_APP_MISC_WASMVM_H_INLCUDED
|
#pragma once
|
||||||
#define RIPPLE_APP_MISC_WASMVM_H_INLCUDED
|
|
||||||
|
|
||||||
#include <xrpl/basics/Expected.h>
|
#include <xrpl/basics/Expected.h>
|
||||||
|
#include <xrpl/basics/base_uint.h>
|
||||||
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/protocol/TER.h>
|
#include <xrpl/protocol/TER.h>
|
||||||
|
|
||||||
#include "xrpl/basics/base_uint.h"
|
#include <boost/function_types/function_arity.hpp>
|
||||||
#include <wasmedge/wasmedge.h>
|
#include <boost/function_types/parameter_types.hpp>
|
||||||
|
#include <boost/function_types/result_type.hpp>
|
||||||
|
#include <boost/mpl/vector.hpp>
|
||||||
|
|
||||||
|
// #include <iwasm/wasm_c_api.h>
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace bft = boost::function_types;
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
static const std::string_view W_ENV = "env";
|
||||||
|
static const std::string_view W_HOST_LIB = "host_lib";
|
||||||
|
static const std::string_view W_MEM = "memory";
|
||||||
|
static const std::string_view W_STORE = "store";
|
||||||
|
static const std::string_view W_LOAD = "load";
|
||||||
|
static const std::string_view W_SIZE = "size";
|
||||||
|
static const std::string_view W_ALLOC = "allocate";
|
||||||
|
static const std::string_view W_DEALLOC = "deallocate";
|
||||||
|
static const std::string_view W_PROC_EXIT = "proc_exit";
|
||||||
|
|
||||||
|
using wbytes = std::vector<std::uint8_t>;
|
||||||
|
struct wmem
|
||||||
|
{
|
||||||
|
std::uint8_t* p = nullptr;
|
||||||
|
std::size_t s = 0;
|
||||||
|
};
|
||||||
|
|
||||||
const uint32_t MAX_PAGES = 128; // 8MB = 64KB*128
|
const uint32_t MAX_PAGES = 128; // 8MB = 64KB*128
|
||||||
|
|
||||||
typedef std::vector<uint8_t> Bytes;
|
typedef std::vector<uint8_t> Bytes;
|
||||||
@@ -122,12 +149,220 @@ struct HostFunctions
|
|||||||
virtual ~HostFunctions() = default;
|
virtual ~HostFunctions() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
enum WasmTypes { WT_I32, WT_I64, WT_F32, WT_F64 };
|
||||||
|
|
||||||
|
struct WasmImportFunc
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::optional<WasmTypes> result;
|
||||||
|
std::vector<WasmTypes> params;
|
||||||
|
void* udata = nullptr;
|
||||||
|
// wasm_func_callback_with_env_t
|
||||||
|
void* wrap = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WASM_IMPORT_FUNC(v, f, ...) \
|
||||||
|
WasmImpFunc<f##_proto>( \
|
||||||
|
v, #f, reinterpret_cast<void*>(&f##_wrap), ##__VA_ARGS__);
|
||||||
|
|
||||||
|
template <int N, int C, typename mpl>
|
||||||
|
void
|
||||||
|
WasmImpArgs(WasmImportFunc& e)
|
||||||
|
{
|
||||||
|
if constexpr (N < C)
|
||||||
|
{
|
||||||
|
using at = typename boost::mpl::at_c<mpl, N>::type;
|
||||||
|
if constexpr (std::is_pointer_v<at>)
|
||||||
|
e.params.push_back(WT_I32);
|
||||||
|
else if constexpr (std::is_same_v<at, std::int32_t>)
|
||||||
|
e.params.push_back(WT_I32);
|
||||||
|
else if constexpr (std::is_same_v<at, std::int64_t>)
|
||||||
|
e.params.push_back(WT_I64);
|
||||||
|
else if constexpr (std::is_same_v<at, float>)
|
||||||
|
e.params.push_back(WT_F32);
|
||||||
|
else if constexpr (std::is_same_v<at, double>)
|
||||||
|
e.params.push_back(WT_F64);
|
||||||
|
else
|
||||||
|
static_assert(std::is_pointer_v<at>, "Unsupported argument type");
|
||||||
|
|
||||||
|
return WasmImpArgs<N + 1, C, mpl>(e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename rt>
|
||||||
|
void
|
||||||
|
WasmImpRet(WasmImportFunc& e)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_pointer_v<rt>)
|
||||||
|
e.result = WT_I32;
|
||||||
|
else if constexpr (std::is_same_v<rt, std::int32_t>)
|
||||||
|
e.result = WT_I32;
|
||||||
|
else if constexpr (std::is_same_v<rt, std::int64_t>)
|
||||||
|
e.result = WT_I64;
|
||||||
|
else if constexpr (std::is_same_v<rt, float>)
|
||||||
|
e.result = WT_F32;
|
||||||
|
else if constexpr (std::is_same_v<rt, double>)
|
||||||
|
e.result = WT_F64;
|
||||||
|
else if constexpr (std::is_void_v<rt>)
|
||||||
|
e.result.reset();
|
||||||
|
#if (defined(__GNUC__) && (__GNUC__ >= 14)) || \
|
||||||
|
((defined(__clang_major__)) && (__clang_major__ >= 18))
|
||||||
|
else
|
||||||
|
static_assert(false, "Unsupported return type");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void
|
||||||
|
WasmImpFuncHelper(WasmImportFunc& e)
|
||||||
|
{
|
||||||
|
using rt = typename bft::result_type<F>::type;
|
||||||
|
using pt = typename bft::parameter_types<F>::type;
|
||||||
|
// typename boost::mpl::at_c<mpl, N>::type
|
||||||
|
|
||||||
|
WasmImpRet<rt>(e);
|
||||||
|
WasmImpArgs<0, bft::function_arity<F>::value, pt>(e);
|
||||||
|
// WasmImpWrap(e, std::forward<F>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void
|
||||||
|
WasmImpFunc(
|
||||||
|
std::vector<WasmImportFunc>& v,
|
||||||
|
std::string_view imp_name,
|
||||||
|
void* f_wrap,
|
||||||
|
void* data = nullptr)
|
||||||
|
{
|
||||||
|
WasmImportFunc e;
|
||||||
|
e.name = imp_name;
|
||||||
|
e.udata = data;
|
||||||
|
e.wrap = f_wrap;
|
||||||
|
WasmImpFuncHelper<F>(e);
|
||||||
|
v.push_back(std::move(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct WasmParam
|
||||||
|
{
|
||||||
|
WasmTypes type = WT_I32;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
std::int32_t i32;
|
||||||
|
std::int64_t i64 = 0;
|
||||||
|
float f32;
|
||||||
|
double f64;
|
||||||
|
} of;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline std::vector<WasmParam>
|
||||||
|
wasmParams(Types... args)
|
||||||
|
{
|
||||||
|
std::vector<WasmParam> v;
|
||||||
|
v.reserve(sizeof...(args));
|
||||||
|
return wasmParams(v, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline std::vector<WasmParam>
|
||||||
|
wasmParams(std::vector<WasmParam>& v, std::int32_t p, Types... args)
|
||||||
|
{
|
||||||
|
v.push_back({.type = WT_I32, .of = {.i32 = p}});
|
||||||
|
return wasmParams(v, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline std::vector<WasmParam>
|
||||||
|
wasmParams(std::vector<WasmParam>& v, std::int64_t p, Types... args)
|
||||||
|
{
|
||||||
|
v.push_back({.type = WT_I64, .of = {.i64 = p}});
|
||||||
|
return wasmParams(v, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline std::vector<WasmParam>
|
||||||
|
wasmParams(std::vector<WasmParam>& v, float p, Types... args)
|
||||||
|
{
|
||||||
|
v.push_back({.type = WT_F32, .of = {.f32 = p}});
|
||||||
|
return wasmParams(v, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Types>
|
||||||
|
inline std::vector<WasmParam>
|
||||||
|
wasmParams(std::vector<WasmParam>& v, double p, Types... args)
|
||||||
|
{
|
||||||
|
v.push_back({.type = WT_F64, .of = {.f64 = p}});
|
||||||
|
return wasmParams(v, std::forward<Types>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::vector<WasmParam>
|
||||||
|
wasmParams(std::vector<WasmParam>& v)
|
||||||
|
{
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class WamrEngine;
|
||||||
|
class WasmEngine
|
||||||
|
{
|
||||||
|
std::unique_ptr<WamrEngine> const impl;
|
||||||
|
|
||||||
|
WasmEngine();
|
||||||
|
|
||||||
|
WasmEngine(WasmEngine const&) = delete;
|
||||||
|
WasmEngine(WasmEngine&&) = delete;
|
||||||
|
WasmEngine&
|
||||||
|
operator=(WasmEngine const&) = delete;
|
||||||
|
WasmEngine&
|
||||||
|
operator=(WasmEngine&&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~WasmEngine() = default;
|
||||||
|
|
||||||
|
static WasmEngine&
|
||||||
|
instance();
|
||||||
|
|
||||||
|
Expected<int32_t, TER>
|
||||||
|
run(wbytes const& wasmCode,
|
||||||
|
std::string_view funcName = {},
|
||||||
|
std::vector<WasmImportFunc> const& imports = {},
|
||||||
|
std::vector<WasmParam> const& params = {});
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
initGas(std::int64_t def = 1'000'000'000'000LL);
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
initMaxPages(std::int32_t def);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
setGas(std::int64_t gas);
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
getGas();
|
||||||
|
|
||||||
|
// for host functions usage
|
||||||
|
wmem
|
||||||
|
getMem() const;
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
allocate(int32_t size);
|
||||||
|
|
||||||
|
void*
|
||||||
|
newTrap(std::string_view msg = {});
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Expected<EscrowResult, TER>
|
Expected<EscrowResult, TER>
|
||||||
runEscrowWasm(
|
runEscrowWasm(
|
||||||
std::vector<uint8_t> const& wasmCode,
|
Bytes const& wasmCode,
|
||||||
std::string const& funcName,
|
std::string_view funcName,
|
||||||
HostFunctions* hfs,
|
HostFunctions* hfs,
|
||||||
uint64_t gasLimit);
|
uint64_t gasLimit);
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
#endif // RIPPLE_APP_MISC_WASMVM_H_INLCUDED
|
|
||||||
|
|||||||
Reference in New Issue
Block a user