Skip to content

Commit

Permalink
Merge pull request #391 from ewasm/engine-internals
Browse files Browse the repository at this point in the history
Split wasm engines into external/internal headers
  • Loading branch information
axic authored Sep 18, 2018
2 parents 484bc6c + 2106699 commit f08ca82
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 267 deletions.
99 changes: 63 additions & 36 deletions src/binaryen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t> 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<wasm::Name, wasm::Literal>& 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<uint8_t>(offset, value); }
uint8_t memoryGet(size_t offset) override { return memory.get<uint8_t>(offset); }
};

void BinaryenEthereumInterface::importGlobals(map<Name, Literal>& globals, Module& wasm) {
(void)globals;
(void)wasm;
Expand Down Expand Up @@ -434,40 +467,6 @@ namespace hera {
heraAssert(false, string("Unsupported import called: ") + import->module.str + "::" + import->base.str + " (" + to_string(arguments.size()) + "arguments)");
}

// NOTE: This should be caught during deployment time by the Sentinel.
void BinaryenEngine::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<WasmEngine> BinaryenEngine::create()
{
return unique_ptr<WasmEngine>{new BinaryenEngine};
Expand Down Expand Up @@ -504,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

Expand Down
40 changes: 0 additions & 40 deletions src/binaryen.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,49 +16,12 @@

#pragma once

#include <wasm.h>
#include <wasm-binary.h>

#include "eei.h"

#include "shell-interface.h"

namespace hera {

class BinaryenEthereumInterface : public wasm::ShellExternalInterface, EthereumInterface {
public:
explicit BinaryenEthereumInterface(
evmc_context* _context,
std::vector<uint8_t> 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<wasm::Name, wasm::Literal>& 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<uint8_t>(offset, value); }
uint8_t memoryGet(size_t offset) override { return memory.get<uint8_t>(offset); }
};

class BinaryenEngine : public WasmEngine {
public:

/// Factory method to create the Binaryen Wasm Engine.
static std::unique_ptr<WasmEngine> create();

Expand All @@ -69,9 +32,6 @@ class BinaryenEngine : public WasmEngine {
evmc_message const& msg,
bool meterInterfaceGas
) override;

private:
static void validate_contract(wasm::Module & module);
};

}
2 changes: 2 additions & 0 deletions src/hera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include <hera/hera.h>

#include <limits>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <iostream>
Expand Down
142 changes: 142 additions & 0 deletions src/wabt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,148 @@ using namespace wabt;

namespace hera {

class WabtEthereumInterface : EthereumInterface, public wabt::interp::HostImportDelegate {
public:
explicit WabtEthereumInterface(
evmc_context* _context,
vector<uint8_t> 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<char>(value); }
uint8_t memoryGet(size_t offset) override { return static_cast<uint8_t>(m_wasmMemory->data[offset]); }

wabt::interp::Memory* m_wasmMemory;
};

unique_ptr<WasmEngine> WabtEngine::create()
{
return unique_ptr<WasmEngine>{new WabtEngine};
Expand Down
Loading

0 comments on commit f08ca82

Please sign in to comment.