From d57ebc14e0cd3b0e90e55928a017487241034755 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 28 Aug 2018 23:13:39 +0100 Subject: [PATCH 1/2] Split wasm engines into external/internal headers --- src/binaryen.cpp | 39 ++++++++++++- src/binaryen.h | 40 ------------- src/hera.cpp | 2 + src/wabt.cpp | 142 ++++++++++++++++++++++++++++++++++++++++++++++ src/wabt.h | 145 ----------------------------------------------- src/wavm.cpp | 52 +++++++++++++++++ src/wavm.h | 48 +--------------- 7 files changed, 236 insertions(+), 232 deletions(-) diff --git a/src/binaryen.cpp b/src/binaryen.cpp index 6429f437d..6911bbe2f 100644 --- a/src/binaryen.cpp +++ b/src/binaryen.cpp @@ -29,11 +29,44 @@ #include "eei.h" #include "exceptions.h" +#include "shell-interface.h" + using namespace std; using namespace wasm; namespace hera { +class BinaryenEthereumInterface : public wasm::ShellExternalInterface, EthereumInterface { +public: + explicit BinaryenEthereumInterface( + evmc_context* _context, + vector const& _code, + evmc_message const& _msg, + ExecutionResult & _result, + bool _meterGas + ): + ShellExternalInterface(), + EthereumInterface(_context, _code, _msg, _result, _meterGas) + { } + +protected: + wasm::Literal callImport(wasm::Import *import, wasm::LiteralList& arguments) override; +#if HERA_DEBUGGING + wasm::Literal callDebugImport(wasm::Import *import, wasm::LiteralList& arguments); +#endif + + void importGlobals(map& globals, wasm::Module& wasm) override; + + void trap(const char* why) override { + ensureCondition(false, VMTrap, why); + } + +private: + size_t memorySize() const override { return memory.size(); } + void memorySet(size_t offset, uint8_t value) override { memory.set(offset, value); } + uint8_t memoryGet(size_t offset) override { return memory.get(offset); } +}; + void BinaryenEthereumInterface::importGlobals(map& globals, Module& wasm) { (void)globals; (void)wasm; @@ -434,8 +467,10 @@ namespace hera { heraAssert(false, string("Unsupported import called: ") + import->module.str + "::" + import->base.str + " (" + to_string(arguments.size()) + "arguments)"); } +namespace { + // NOTE: This should be caught during deployment time by the Sentinel. -void BinaryenEngine::validate_contract(Module & module) +void validate_contract(Module & module) { ensureCondition( module.getExportOrNull(Name("main")) != nullptr, @@ -468,6 +503,8 @@ void BinaryenEngine::validate_contract(Module & module) } } +} + unique_ptr BinaryenEngine::create() { return unique_ptr{new BinaryenEngine}; diff --git a/src/binaryen.h b/src/binaryen.h index 92b492c8d..6054d6ad2 100644 --- a/src/binaryen.h +++ b/src/binaryen.h @@ -16,49 +16,12 @@ #pragma once -#include -#include - #include "eei.h" -#include "shell-interface.h" - namespace hera { -class BinaryenEthereumInterface : public wasm::ShellExternalInterface, EthereumInterface { -public: - explicit BinaryenEthereumInterface( - evmc_context* _context, - std::vector const& _code, - evmc_message const& _msg, - ExecutionResult & _result, - bool _meterGas - ): - ShellExternalInterface(), - EthereumInterface(_context, _code, _msg, _result, _meterGas) - { } - -protected: - wasm::Literal callImport(wasm::Import *import, wasm::LiteralList& arguments) override; -#if HERA_DEBUGGING - wasm::Literal callDebugImport(wasm::Import *import, wasm::LiteralList& arguments); -#endif - - void importGlobals(std::map& globals, wasm::Module& wasm) override; - - void trap(const char* why) override { - ensureCondition(false, VMTrap, why); - } - -private: - size_t memorySize() const override { return memory.size(); } - void memorySet(size_t offset, uint8_t value) override { memory.set(offset, value); } - uint8_t memoryGet(size_t offset) override { return memory.get(offset); } -}; - class BinaryenEngine : public WasmEngine { public: - /// Factory method to create the Binaryen Wasm Engine. static std::unique_ptr create(); @@ -69,9 +32,6 @@ class BinaryenEngine : public WasmEngine { evmc_message const& msg, bool meterInterfaceGas ) override; - -private: - static void validate_contract(wasm::Module & module); }; } diff --git a/src/hera.cpp b/src/hera.cpp index b9a09d2ac..ed4405333 100644 --- a/src/hera.cpp +++ b/src/hera.cpp @@ -16,6 +16,8 @@ #include +#include +#include #include #include #include diff --git a/src/wabt.cpp b/src/wabt.cpp index d818815ea..3f0db8edd 100644 --- a/src/wabt.cpp +++ b/src/wabt.cpp @@ -41,6 +41,148 @@ using namespace wabt; namespace hera { +class WabtEthereumInterface : EthereumInterface, public wabt::interp::HostImportDelegate { +public: + explicit WabtEthereumInterface( + evmc_context* _context, + vector const& _code, + evmc_message const& _msg, + ExecutionResult & _result, + bool _meterGas + ): + EthereumInterface(_context, _code, _msg, _result, _meterGas) + {} + + // TODO: improve this design... + void setWasmMemory(wabt::interp::Memory* _wasmMemory) { + m_wasmMemory = _wasmMemory; + } + +protected: + wabt::Result ImportFunc( + wabt::interp::FuncImport* import, + wabt::interp::Func* func, + wabt::interp::FuncSignature* func_sig, + const ErrorCallback& callback + ) override; + + wabt::Result ImportMemory( + wabt::interp::MemoryImport* import, + wabt::interp::Memory* mem, + const ErrorCallback& callback + ) override; + + wabt::Result ImportGlobal( + wabt::interp::GlobalImport* import, + wabt::interp::Global* global, + const ErrorCallback& callback + ) override; + + wabt::Result ImportTable( + wabt::interp::TableImport* import, + wabt::interp::Table* table, + const ErrorCallback& callback + ) override; + + static wabt::interp::Result wabtUseGas( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + + static wabt::interp::Result wabtGetGasLeft( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + + static wabt::interp::Result wabtStorageStore( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + + static wabt::interp::Result wabtStorageLoad( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + + static wabt::interp::Result wabtFinish( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + + static wabt::interp::Result wabtRevert( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + + static wabt::interp::Result wabtGetCallDataSize( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + + static wabt::interp::Result wabtCallDataCopy( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + + static wabt::interp::Result wabtGetCallValue( + const wabt::interp::HostFunc* func, + const wabt::interp::FuncSignature* sig, + wabt::Index num_args, + wabt::interp::TypedValue* args, + wabt::Index num_results, + wabt::interp::TypedValue* out_results, + void* user_data + ); + +private: + // These assume that m_wasmMemory was set prior to execution. + size_t memorySize() const override { return m_wasmMemory->data.size(); } + void memorySet(size_t offset, uint8_t value) override { m_wasmMemory->data[offset] = static_cast(value); } + uint8_t memoryGet(size_t offset) override { return static_cast(m_wasmMemory->data[offset]); } + + wabt::interp::Memory* m_wasmMemory; +}; + unique_ptr WabtEngine::create() { return unique_ptr{new WabtEngine}; diff --git a/src/wabt.h b/src/wabt.h index 23c0bdd30..34d8b819e 100644 --- a/src/wabt.h +++ b/src/wabt.h @@ -16,157 +16,12 @@ #pragma once -#include - #include "eei.h" namespace hera { -class WabtEthereumInterface : EthereumInterface, public wabt::interp::HostImportDelegate { -public: - explicit WabtEthereumInterface( - evmc_context* _context, - std::vector const& _code, - evmc_message const& _msg, - ExecutionResult & _result, - bool _meterGas - ): - EthereumInterface(_context, _code, _msg, _result, _meterGas) - {} - - // TODO: improve this design... - void setWasmMemory(wabt::interp::Memory* _wasmMemory) { - m_wasmMemory = _wasmMemory; - } - -protected: - wabt::Result ImportFunc( - wabt::interp::FuncImport* import, - wabt::interp::Func* func, - wabt::interp::FuncSignature* func_sig, - const ErrorCallback& callback - ) override; - - wabt::Result ImportMemory( - wabt::interp::MemoryImport* import, - wabt::interp::Memory* mem, - const ErrorCallback& callback - ) override; - - wabt::Result ImportGlobal( - wabt::interp::GlobalImport* import, - wabt::interp::Global* global, - const ErrorCallback& callback - ) override; - - wabt::Result ImportTable( - wabt::interp::TableImport* import, - wabt::interp::Table* table, - const ErrorCallback& callback - ) override; - - static wabt::interp::Result wabtUseGas( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - - static wabt::interp::Result wabtGetGasLeft( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - - static wabt::interp::Result wabtStorageStore( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - - static wabt::interp::Result wabtStorageLoad( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - - static wabt::interp::Result wabtFinish( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - - static wabt::interp::Result wabtRevert( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - - static wabt::interp::Result wabtGetCallDataSize( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - - static wabt::interp::Result wabtCallDataCopy( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - - static wabt::interp::Result wabtGetCallValue( - const wabt::interp::HostFunc* func, - const wabt::interp::FuncSignature* sig, - wabt::Index num_args, - wabt::interp::TypedValue* args, - wabt::Index num_results, - wabt::interp::TypedValue* out_results, - void* user_data - ); - -private: - // These assume that m_wasmMemory was set prior to execution. - size_t memorySize() const override { return m_wasmMemory->data.size(); } - void memorySet(size_t offset, uint8_t value) override { m_wasmMemory->data[offset] = static_cast(value); } - uint8_t memoryGet(size_t offset) override { return static_cast(m_wasmMemory->data[offset]); } - - wabt::interp::Memory* m_wasmMemory; -}; - class WabtEngine : public WasmEngine { public: - /// Factory method to create the WABT Wasm Engine. static std::unique_ptr create(); diff --git a/src/wavm.cpp b/src/wavm.cpp index 2c2576c47..bf363b021 100644 --- a/src/wavm.cpp +++ b/src/wavm.cpp @@ -15,7 +15,21 @@ * limitations under the License. */ +#include +#include +#include + #include "wavm.h" + +#define DLL_IMPORT // Needed by wavm on some platforms +#include "Inline/Serialization.h" +#include "IR/Module.h" +#include "IR/Validate.h" +#include "Runtime/Intrinsics.h" +#include "Runtime/Linker.h" +#include "Runtime/Runtime.h" +#include "WASM/WASM.h" + #include "debugging.h" #include "eei.h" #include "exceptions.h" @@ -27,6 +41,31 @@ using namespace std; namespace hera { +class WavmEthereumInterface : public EthereumInterface { +public: + explicit WavmEthereumInterface( + evmc_context* _context, + vector const& _code, + evmc_message const& _msg, + ExecutionResult & _result, + bool _meterGas + ): + EthereumInterface(_context, _code, _msg, _result, _meterGas) + {} + + void setWasmMemory(Runtime::MemoryInstance* _wasmMemory) { + m_wasmMemory = _wasmMemory; + } + +private: + // These assume that m_wasmMemory was set prior to execution. + size_t memorySize() const override { return Runtime::getMemoryNumPages(m_wasmMemory) * 65536; } + void memorySet(size_t offset, uint8_t value) override { (Runtime::memoryArrayPtr(m_wasmMemory, offset, 1))[0] = value; } + uint8_t memoryGet(size_t offset) override { return (Runtime::memoryArrayPtr(m_wasmMemory, offset, 1))[0]; } + + Runtime::MemoryInstance* m_wasmMemory; +}; + unique_ptr WavmEngine::create() { return unique_ptr{new WavmEngine}; @@ -147,6 +186,19 @@ namespace wavm_host_module { }; } // namespace wavm_host_module +ExecutionResult WavmEngine::execute( + evmc_context* context, + vector const& code, + vector const& state_code, + evmc_message const& msg, + bool meterInterfaceGas +) { + ExecutionResult result = internalExecute(context, code, state_code, msg, meterInterfaceGas); + // And clean up mess left by this run. + Runtime::collectGarbage(); + return result; +} + ExecutionResult WavmEngine::internalExecute( evmc_context* context, vector const& code, diff --git a/src/wavm.h b/src/wavm.h index cc185cf76..44cfb4ef8 100644 --- a/src/wavm.h +++ b/src/wavm.h @@ -17,52 +17,13 @@ #pragma once -#include -#include -#include - -#define DLL_IMPORT // Needed by wavm on some platforms -#include "Inline/Serialization.h" -#include "IR/Module.h" -#include "IR/Validate.h" -#include "Runtime/Intrinsics.h" -#include "Runtime/Linker.h" -#include "Runtime/Runtime.h" -#include "WASM/WASM.h" - #include "eei.h" namespace hera { -class WavmEthereumInterface : public EthereumInterface { - -public: - explicit WavmEthereumInterface( - evmc_context* _context, - std::vector const& _code, - evmc_message const& _msg, - ExecutionResult & _result, - bool _meterGas - ): - EthereumInterface(_context, _code, _msg, _result, _meterGas) - {} - - void setWasmMemory(Runtime::MemoryInstance* _wasmMemory) { - m_wasmMemory = _wasmMemory; - } - -private: - // These assume that m_wasmMemory was set prior to execution. - size_t memorySize() const override { return Runtime::getMemoryNumPages(m_wasmMemory) * 65536; } - void memorySet(size_t offset, uint8_t value) override { (Runtime::memoryArrayPtr(m_wasmMemory, offset, 1))[0] = value; } - uint8_t memoryGet(size_t offset) override { return (Runtime::memoryArrayPtr(m_wasmMemory, offset, 1))[0]; } - - Runtime::MemoryInstance* m_wasmMemory; -}; - class WavmEngine : public WasmEngine { public: - /// Factory method to create the WABT Wasm Engine. + /// Factory method to create the WAVM Wasm Engine. static std::unique_ptr create(); ExecutionResult execute( @@ -71,12 +32,7 @@ class WavmEngine : public WasmEngine { std::vector const& state_code, evmc_message const& msg, bool meterInterfaceGas - ) override { - ExecutionResult result = internalExecute(context, code, state_code, msg, meterInterfaceGas); - // And clean up mess left by this run. - Runtime::collectGarbage(); - return result; - } + ) override; private: ExecutionResult internalExecute( From 21066990d202f4644043408c026453de783a775f Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 18 Sep 2018 00:29:10 +0100 Subject: [PATCH 2/2] Merge validate_contract into execute in Binaryen to be in line with the other engines --- src/binaryen.cpp | 70 +++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/src/binaryen.cpp b/src/binaryen.cpp index 6911bbe2f..ab3c7dc33 100644 --- a/src/binaryen.cpp +++ b/src/binaryen.cpp @@ -467,44 +467,6 @@ class BinaryenEthereumInterface : public wasm::ShellExternalInterface, EthereumI heraAssert(false, string("Unsupported import called: ") + import->module.str + "::" + import->base.str + " (" + to_string(arguments.size()) + "arguments)"); } -namespace { - -// NOTE: This should be caught during deployment time by the Sentinel. -void validate_contract(Module & module) -{ - ensureCondition( - module.getExportOrNull(Name("main")) != nullptr, - ContractValidationFailure, - "Contract entry point (\"main\") missing." - ); - - ensureCondition( - module.getExportOrNull(Name("memory")) != nullptr, - ContractValidationFailure, - "Contract export (\"memory\") missing." - ); - - ensureCondition( - module.exports.size() == 2, - ContractValidationFailure, - "Contract exports more than (\"main\") and (\"memory\")." - ); - - for (auto const& import: module.imports) { - ensureCondition( - import->module == Name("ethereum") -#if HERA_DEBUGGING - || import->module == Name("debug") -#endif - , - ContractValidationFailure, - "Import from invalid namespace." - ); - } -} - -} - unique_ptr BinaryenEngine::create() { return unique_ptr{new BinaryenEngine}; @@ -541,8 +503,36 @@ ExecutionResult BinaryenEngine::execute( "Module is not valid." ); - // NOTE: This should be caught during deployment time by the Sentinel. - validate_contract(module); + // NOTE: Most of this should be caught during deployment time by the Sentinel. + ensureCondition( + module.getExportOrNull(Name("main")) != nullptr, + ContractValidationFailure, + "Contract entry point (\"main\") missing." + ); + + ensureCondition( + module.getExportOrNull(Name("memory")) != nullptr, + ContractValidationFailure, + "Contract export (\"memory\") missing." + ); + + ensureCondition( + module.exports.size() == 2, + ContractValidationFailure, + "Contract exports more than (\"main\") and (\"memory\")." + ); + + for (auto const& import: module.imports) { + ensureCondition( + import->module == Name("ethereum") +#if HERA_DEBUGGING + || import->module == Name("debug") +#endif + , + ContractValidationFailure, + "Import from invalid namespace." + ); + } // NOTE: DO NOT use the optimiser here, it will conflict with metering