mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
compiling
This commit is contained in:
committed by
RichardAH
parent
9ab33d580d
commit
71a6f9c4d5
@@ -224,6 +224,7 @@ enum hook_log_code : uint16_t {
|
||||
CUSTOM_SECTION_DISALLOWED =
|
||||
86, // the wasm contained a custom section (id=0)
|
||||
INTERNAL_ERROR = 87, // an internal error described by the log text
|
||||
JS_TEST_FAILURE = 88, // smoke test of js bytecode failed
|
||||
// RH NOTE: only HookSet msgs got log codes, possibly all Hook log lines
|
||||
// should get a code?
|
||||
};
|
||||
@@ -341,8 +342,15 @@ enum ExitType : uint8_t {
|
||||
ROLLBACK = 2,
|
||||
ACCEPT = 3,
|
||||
JSVM_ERROR = 4,
|
||||
LEDGER_ERROR = 5, // if the ledger contained for example a nonsense hookapi number
|
||||
};
|
||||
|
||||
enum CodeType : uint8_t {
|
||||
WASM = 0,
|
||||
JS = 1,
|
||||
};
|
||||
|
||||
|
||||
const uint16_t max_state_modifications = 256;
|
||||
const uint8_t max_slots = 255;
|
||||
const uint8_t max_nonce = 255;
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <wasmedge/wasmedge.h>
|
||||
#include "quickjs.h"
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
namespace hook {
|
||||
struct HookContext;
|
||||
struct HookResult;
|
||||
@@ -453,7 +456,7 @@ apply(
|
||||
bool hasCallback,
|
||||
bool isCallback,
|
||||
bool isStrongTSH,
|
||||
uint32_t wasmParam,
|
||||
uint32_t hookArgument,
|
||||
uint8_t hookChainPosition,
|
||||
// result of apply() if this is weak exec
|
||||
std::shared_ptr<STObject const> const& provisionalMeta);
|
||||
@@ -501,7 +504,7 @@ struct HookResult
|
||||
bool isCallback =
|
||||
false; // true iff this hook execution is a callback in action
|
||||
bool isStrong = false;
|
||||
uint32_t wasmParam = 0;
|
||||
uint32_t hookArgument = 0;
|
||||
uint32_t overrideCount = 0;
|
||||
uint8_t hookChainPosition = 0;
|
||||
bool foreignStateSetDisabled = false;
|
||||
@@ -511,8 +514,9 @@ struct HookResult
|
||||
std::shared_ptr<STObject const> provisionalMeta;
|
||||
};
|
||||
|
||||
class HookExecutorWasm;
|
||||
class HookExecutorJs;
|
||||
class HookExecutorBase;
|
||||
//class HookExecutorWasm;
|
||||
//class HookExecutorJs;
|
||||
|
||||
struct SlotEntry
|
||||
{
|
||||
@@ -550,7 +554,7 @@ struct HookContext
|
||||
emitFailure; // if this is a callback from a failed
|
||||
// emitted txn then this optional becomes
|
||||
// populated with the SLE
|
||||
const HookExecutorWasm* module = 0;
|
||||
const HookExecutorBase* module = 0;
|
||||
};
|
||||
|
||||
bool
|
||||
@@ -619,7 +623,7 @@ protected:
|
||||
public:
|
||||
HookContext& hookCtx;
|
||||
|
||||
virtual ~HookExecutorBase() {}
|
||||
HookExecutorBase(HookContext& ctx) : hookCtx(ctx) {}
|
||||
|
||||
virtual void execute(
|
||||
const void* code,
|
||||
@@ -635,6 +639,8 @@ public:
|
||||
// Base class doesn't implement validation
|
||||
return "validate() illegally called on HookExecutorBase class";
|
||||
}
|
||||
|
||||
virtual ~HookExecutorBase() = default;
|
||||
};
|
||||
|
||||
|
||||
@@ -646,9 +652,7 @@ public:
|
||||
* this is done during execteWasm function.
|
||||
* The instance is single use.
|
||||
*/
|
||||
class HookExecutorWasm : public HookExecutorBase
|
||||
{
|
||||
private:
|
||||
|
||||
// create these once at boot and keep them
|
||||
static WasmEdge_String exportName = WasmEdge_StringCreateByCString("env");
|
||||
static WasmEdge_String tableName = WasmEdge_StringCreateByCString("table");
|
||||
@@ -666,6 +670,8 @@ static WasmEdge_String hookFunctionName =
|
||||
// see: lib/system/allocator.cpp
|
||||
#define WasmEdge_kPageSize 65536ULL
|
||||
|
||||
class HookExecutorWasm : public HookExecutorBase
|
||||
{
|
||||
public:
|
||||
WasmEdge_ModuleInstanceContext* importObj;
|
||||
|
||||
@@ -747,7 +753,7 @@ public:
|
||||
const void* wasm,
|
||||
size_t len,
|
||||
bool callback,
|
||||
uint32_t wasmParam,
|
||||
uint32_t hookArgument,
|
||||
beast::Journal const& j) override
|
||||
{
|
||||
// HookExecutorWasm can only execute once
|
||||
@@ -780,7 +786,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
WasmEdge_Value params[1] = {WasmEdge_ValueGenI32((int64_t)wasmParam)};
|
||||
WasmEdge_Value params[1] = {WasmEdge_ValueGenI32((int64_t)hookArgument)};
|
||||
WasmEdge_Value returns[1];
|
||||
|
||||
res = WasmEdge_VMRunWasmFromBuffer(
|
||||
@@ -808,7 +814,7 @@ public:
|
||||
}
|
||||
|
||||
HookExecutorWasm(HookContext& ctx)
|
||||
: hookCtx(ctx), importObj(WasmEdge_ModuleInstanceCreate(exportName))
|
||||
: HookExecutorBase(ctx), importObj(WasmEdge_ModuleInstanceCreate(exportName))
|
||||
{
|
||||
ctx.module = this;
|
||||
|
||||
@@ -907,7 +913,7 @@ public:
|
||||
WasmEdge_ModuleInstanceAddMemory(importObj, memName, hostMem);
|
||||
}
|
||||
|
||||
~HookExecutorWasm()
|
||||
virtual ~HookExecutorWasm()
|
||||
{
|
||||
WasmEdge_ModuleInstanceDelete(importObj);
|
||||
};
|
||||
@@ -1053,9 +1059,12 @@ public:
|
||||
* Validate that a web assembly blob can be loaded by wasmedge
|
||||
*/
|
||||
static std::optional<std::string>
|
||||
validate(const void* buf, size_t len)
|
||||
validate(const void* buf, size_t buf_len)
|
||||
{
|
||||
|
||||
if (buf_len < 5)
|
||||
return "Could not create QUICKJS instance, bytecode too short.";
|
||||
|
||||
std::optional<std::string> retval;
|
||||
|
||||
QuickJSVM vm;
|
||||
@@ -1065,7 +1074,7 @@ public:
|
||||
return "Could not create QUICKJS instance";
|
||||
|
||||
JSValue obj =
|
||||
JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE);
|
||||
JS_ReadObject(ctx, (uint8_t const*)buf, buf_len, JS_READ_OBJ_BYTECODE);
|
||||
if (JS_IsException(obj))
|
||||
{
|
||||
if (const char* str = JS_ToCString(ctx, obj); str)
|
||||
@@ -1074,7 +1083,7 @@ public:
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
|
||||
JS_FreeVal(ctx, obj);
|
||||
JS_FreeValue(ctx, obj);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1127,7 +1136,7 @@ public:
|
||||
const void* buf,
|
||||
size_t buf_len,
|
||||
bool callback,
|
||||
uint32_t callParam,
|
||||
uint32_t hookArgument,
|
||||
beast::Journal const& j) override
|
||||
{
|
||||
// HookExecutorWasm can only execute once
|
||||
@@ -1138,6 +1147,7 @@ public:
|
||||
<< "]: creating quickjs instance";
|
||||
|
||||
QuickJSVM vm;
|
||||
JSContext* ctx = vm.ctx;
|
||||
|
||||
if (!vm.sane())
|
||||
{
|
||||
@@ -1149,11 +1159,11 @@ public:
|
||||
}
|
||||
|
||||
JSValue obj =
|
||||
JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE);
|
||||
JS_ReadObject(ctx, (uint8_t const*)buf, buf_len, JS_READ_OBJ_BYTECODE);
|
||||
|
||||
if (JS_IsException(obj))
|
||||
{
|
||||
JS_FreeVal(ctx, obj);
|
||||
JS_FreeValue(ctx, obj);
|
||||
JLOG(j.warn()) << "HookError[" << HC_ACC()
|
||||
<< "]: Could not create QUICKJS instance (invalid bytecode).";
|
||||
hookCtx.result.exitType = hook_api::ExitType::JSVM_ERROR;
|
||||
@@ -1179,11 +1189,11 @@ public:
|
||||
char expr[256];
|
||||
|
||||
int expr_len =
|
||||
snprintf(expr_len, 256, "%s(%d)",
|
||||
snprintf(expr, 256, "%s(%d)",
|
||||
callback ? "Callback" : "Hook",
|
||||
callParam);
|
||||
hookArgument);
|
||||
|
||||
if (char_count < 7 || char_count == 256)
|
||||
if (expr_len < 7 || expr_len == 256)
|
||||
{
|
||||
JLOG(j.warn()) << "HookError[" << HC_ACC()
|
||||
<< "]: Could not create QUICKJS instance (expr string).";
|
||||
@@ -1192,7 +1202,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
JSValue val =
|
||||
val =
|
||||
JS_Eval(vm.ctx, expr, expr_len, "<qjsvm>", 0);
|
||||
|
||||
if (JS_IsException(val))
|
||||
@@ -1214,14 +1224,12 @@ public:
|
||||
}
|
||||
|
||||
HookExecutorJS(HookContext& ctx)
|
||||
: hookCtx(ctx)
|
||||
: HookExecutorBase(ctx)
|
||||
{
|
||||
ctx.module = this;
|
||||
|
||||
|
||||
}
|
||||
|
||||
~HookExecutorJS()
|
||||
virtual ~HookExecutorJS()
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1236,27 +1236,34 @@ hook::apply(
|
||||
|
||||
switch (hookApiVersion)
|
||||
{
|
||||
case 0: // wasm
|
||||
case hook_api::CodeType::WASM:
|
||||
{
|
||||
HookExecutorWasm executor{hookCtx};
|
||||
|
||||
executor.executeWasm(
|
||||
executor.execute(
|
||||
bytecode.data(), (size_t)bytecode.size(), isCallback, hookArgument, j);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // js
|
||||
case hook_api::CodeType::JS:
|
||||
{
|
||||
|
||||
// RHUPTO: populate hookArgument, bytecode, perform execution
|
||||
HookExecutorJs executor{hookCtx};
|
||||
HookExecutorJS executor{hookCtx};
|
||||
|
||||
executor.execute(
|
||||
bytecode.data(), (size_t)bytecode.size(), isCallback, hookArgument, j);
|
||||
|
||||
|
||||
js_std_eval_binary_bare(ctx, wasm.data(), wasm.size());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
hookCtx.result.exitType = hook_api::ExitType::LEDGER_ERROR;
|
||||
return hookCtx.result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
JLOG(j.trace()) << "HookInfo[" << HC_ACC() << "]: "
|
||||
|
||||
@@ -785,60 +785,9 @@ run(int argc, char** argv)
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
static JSContext*
|
||||
JS_NewCustomContext(JSRuntime* rt)
|
||||
{
|
||||
JSContext* ctx = JS_NewContextRaw(rt);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
JS_AddIntrinsicBaseObjects(ctx);
|
||||
JS_AddIntrinsicDate(ctx);
|
||||
JS_AddIntrinsicEval(ctx);
|
||||
JS_AddIntrinsicStringNormalize(ctx);
|
||||
JS_AddIntrinsicRegExp(ctx);
|
||||
JS_AddIntrinsicJSON(ctx);
|
||||
JS_AddIntrinsicProxy(ctx);
|
||||
JS_AddIntrinsicMapSet(ctx);
|
||||
JS_AddIntrinsicTypedArrays(ctx);
|
||||
JS_AddIntrinsicPromise(ctx);
|
||||
JS_AddIntrinsicBigInt(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
const uint32_t qjsc_x_size = 140;
|
||||
|
||||
const uint8_t qjsc_x[140] = {
|
||||
0x43, 0x05, 0x02, 0x78, 0x08, 0x78, 0x2e, 0x6a, 0x73, 0x02, 0x69, 0x0e,
|
||||
0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x0c,
|
||||
0x00, 0x06, 0x00, 0xa2, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x16,
|
||||
0x01, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x3f, 0xe3, 0x00, 0x00, 0x00, 0x40,
|
||||
0xc2, 0x00, 0x40, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x38, 0xe3, 0x00, 0x00,
|
||||
0x00, 0xf0, 0xcf, 0x28, 0xc8, 0x03, 0x01, 0x04, 0x1f, 0x00, 0x08, 0x0e,
|
||||
0x0c, 0x43, 0x06, 0x00, 0xc6, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00,
|
||||
0x2a, 0x01, 0xca, 0x03, 0x02, 0x00, 0x20, 0x61, 0x00, 0x00, 0xb7, 0xcb,
|
||||
0x62, 0x00, 0x00, 0xbf, 0x0a, 0xa4, 0xec, 0x1d, 0x38, 0xe6, 0x00, 0x00,
|
||||
0x00, 0x42, 0xe7, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x24, 0x01, 0x00,
|
||||
0x0e, 0x62, 0x00, 0x00, 0x90, 0x11, 0x63, 0x00, 0x00, 0x0e, 0xee, 0xdd,
|
||||
0x29, 0xc8, 0x03, 0x01, 0x03, 0x04, 0x44, 0x8f,
|
||||
};
|
||||
JSRuntime* rt;
|
||||
JSContext* ctx;
|
||||
rt = JS_NewRuntime();
|
||||
JS_SetMaxStackSize(rt, 65535);
|
||||
JS_SetMemoryLimit(rt, 16 * 1024 * 1024);
|
||||
ctx = JS_NewContextRaw(rt);
|
||||
JS_AddIntrinsicBaseObjects(ctx);
|
||||
JS_AddIntrinsicJSON(ctx);
|
||||
JS_AddIntrinsicBigInt(ctx);
|
||||
js_std_add_helpers(ctx, argc, argv);
|
||||
js_std_eval_binary(ctx, qjsc_x, qjsc_x_size, 0);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
#if BOOST_OS_WINDOWS
|
||||
{
|
||||
// Work around for https://svn.boost.org/trac/boost/ticket/10657
|
||||
|
||||
@@ -611,7 +611,7 @@ Change::activateXahauGenesis()
|
||||
}
|
||||
|
||||
std::optional<std::string> result2 =
|
||||
hook::HookExecutor::validateWasm(
|
||||
hook::HookExecutorWasm::validate(
|
||||
wasmBytes.data(), (size_t)wasmBytes.size());
|
||||
|
||||
if (result2)
|
||||
|
||||
@@ -461,15 +461,26 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
|
||||
if (version == 1)
|
||||
{
|
||||
// RHTODO: don't eval here, scan for valid bytecode, return error if not
|
||||
// figure out how to correctly sandbox quickjs runtime so segfault doesnt crash
|
||||
//
|
||||
// for now, do nothing here
|
||||
//
|
||||
// RHTODO: guard or other check for js, depending on design choices
|
||||
|
||||
std::optional<std::string> result =
|
||||
hook::HookExecutorJS::validate(
|
||||
hook.data(), (size_t)hook.size());
|
||||
|
||||
if (result)
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::JS_TEST_FAILURE << ")["
|
||||
<< HS_ACC()
|
||||
<< "Tried to set a hook with invalid code. VM error: "
|
||||
<< *result;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (version == 0)
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
// RH NOTE: validateGuards has a generic non-rippled specific
|
||||
// interface so it can be used in other projects (i.e. tooling).
|
||||
@@ -534,7 +545,7 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
<< "size = " << hook.size();
|
||||
|
||||
std::optional<std::string> result2 =
|
||||
hook::HookExecutor::validateWasm(
|
||||
hook::HookExecutorWasm::validate(
|
||||
hook.data(), (size_t)hook.size());
|
||||
|
||||
if (result2)
|
||||
@@ -549,6 +560,11 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
JLOG(ctx.j.trace())
|
||||
<< "HookSet(" << hook::log::HASH_OR_CODE << ")[" << HS_ACC()
|
||||
<< "]: Malformed transaction: SetHook specified invalid HookApiVersion.";
|
||||
return false;
|
||||
}
|
||||
|
||||
case hsoINVALID:
|
||||
|
||||
@@ -1242,7 +1242,7 @@ Transactor::executeHookChain(
|
||||
|
||||
bool hasCallback = hookDef->isFieldPresent(sfHookCallbackFee);
|
||||
|
||||
uint16_t hookApiVersion = hookDef-getFieldU16(sfHookApiVersion);
|
||||
uint16_t hookApiVersion = hookDef->getFieldU16(sfHookApiVersion);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -1397,6 +1397,7 @@ Transactor::doHookCallback(
|
||||
hook::HookResult callbackResult = hook::apply(
|
||||
hookDef->getFieldH256(sfHookSetTxnID),
|
||||
callbackHookHash,
|
||||
hookDef->getFieldU16(sfHookApiVersion),
|
||||
ns,
|
||||
hookDef->getFieldVL(sfCreateCode),
|
||||
parameters,
|
||||
@@ -1662,6 +1663,7 @@ Transactor::doAgainAsWeak(
|
||||
hook::HookResult aawResult = hook::apply(
|
||||
hookDef->getFieldH256(sfHookSetTxnID),
|
||||
hookHash,
|
||||
hookDef->getFieldU16(sfHookApiVersion),
|
||||
ns,
|
||||
hookDef->getFieldVL(sfCreateCode),
|
||||
parameters,
|
||||
|
||||
Reference in New Issue
Block a user