diff --git a/.cspell.config.yaml b/.cspell.config.yaml index 23227aa6ef..b9ea40383b 100644 --- a/.cspell.config.yaml +++ b/.cspell.config.yaml @@ -7,7 +7,6 @@ ignorePaths: - cmake/** - LICENSE.md - .clang-tidy - - src/test/app/wasm_fixtures/*.c language: en allowCompoundWords: true # TODO (#6334) ignoreRandomStrings: true @@ -105,6 +104,7 @@ words: - deleteme - demultiplexer - deserializaton + - desugars - desync - desynced - determ @@ -130,6 +130,7 @@ words: - gcov - gcovr - ghead + - gmock - Gnutella - godexsoft - gpgcheck @@ -138,7 +139,9 @@ words: - hwaddress - hwrap - ifndef + - impls - inequation + - initialiser - insuf - insuff - invasively @@ -244,6 +247,7 @@ words: - pyparsing - qalloc - qbsprofile + - qself - queuable - Raphson - rcflags @@ -337,6 +341,7 @@ words: - unflatten - unfund - unimpair + - unmetered - unroutable - unscalable - unserviced @@ -357,6 +362,7 @@ words: - vfalco - vinnie - wasmi + - Werror - wextra - wptr - writeme diff --git a/crates/xrpl-wasm-vm/src/register.rs b/crates/xrpl-wasm-vm/src/register.rs index ab87571cfe..ef933f1bf9 100644 --- a/crates/xrpl-wasm-vm/src/register.rs +++ b/crates/xrpl-wasm-vm/src/register.rs @@ -19,7 +19,7 @@ pub(crate) fn register_host_functions( ) -> Result<(), wasmi::errors::LinkerError> { // The arms are hand-written and repetitive by decision, not by neglect: // generating them needs the typed `link_*` shims, deferred until the C header - // is generated from the same table (docs/claude/wasm-vm/abi.md). + // is generated from the same table. for &op in HostFunctionSpec::ALL { match op { HostFunctionSpec::GetLedgerSqn => linker.func_wrap( diff --git a/include/xrpl/tx/wasm/README.md b/include/xrpl/tx/wasm/README.md index a9dbc84c85..4b99510705 100644 --- a/include/xrpl/tx/wasm/README.md +++ b/include/xrpl/tx/wasm/README.md @@ -5,10 +5,7 @@ runs to decide whether the release conditions are met. Specification: [XLS-0102: WASM VM](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html). The engine itself is Rust (`crates/xrpl-wasm-vm`, over wasmi), reached through a cxx -bridge. The design docs live in [`docs/claude/wasm-vm/`](../../../../docs/claude/wasm-vm/index.md) -— read [`abi.md`](../../../../docs/claude/wasm-vm/abi.md) before adding a host function and -[`bridge.md`](../../../../docs/claude/wasm-vm/bridge.md) before changing anything that -crosses between the two languages. +bridge. ## What is in this directory diff --git a/src/libxrpl/tx/wasm/HostContext.cpp b/src/libxrpl/tx/wasm/HostContext.cpp index 3c167e4065..d6742ada5a 100644 --- a/src/libxrpl/tx/wasm/HostContext.cpp +++ b/src/libxrpl/tx/wasm/HostContext.cpp @@ -54,8 +54,8 @@ guarded( } catch (...) { - JLOG(journal.warn()) - << "wasm host call threw a non-exception in " << location.function_name(); + JLOG(journal.warn()) << "wasm host call threw a non-exception in " + << location.function_name(); } return kHostInternal; diff --git a/src/libxrpl/tx/wasm/WasmVM.cpp b/src/libxrpl/tx/wasm/WasmVM.cpp index f8ba707a58..8e29fcd41a 100644 --- a/src/libxrpl/tx/wasm/WasmVM.cpp +++ b/src/libxrpl/tx/wasm/WasmVM.cpp @@ -85,8 +85,8 @@ outcome(rs::wasm_vm::RunResult const& run) // // The counterpart of the engine's own `guarded`, which stops a Rust panic on the other // side of the bridge. Neither side may unwind into the other, and this is this side's -// half: the reason `HostContext`'s methods are `noexcept` rather than relying on cxx is -// documented in `docs/claude/wasm-vm/bridge.md`. +// half. `HostContext`'s methods are `noexcept` rather than leaving this to cxx because +// cxx's own `trycatch` catches only `std::exception`, and only for `Result` returns. template std::invoke_result_t guarded(beast::Journal j, std::invoke_result_t onThrow, Call&& call) diff --git a/src/test/app/HostFuncImpl_test.cpp b/src/test/app/HostFuncImpl_test.cpp index 4fb4c12717..61ee4c3ed2 100644 --- a/src/test/app/HostFuncImpl_test.cpp +++ b/src/test/app/HostFuncImpl_test.cpp @@ -3780,28 +3780,36 @@ struct HostFuncImpl_test : public beast::unit_test::Suite int const normalExp = 18; - Bytes const floatIntMin = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}; // -2^63 (rounds to nearest: -(2^63-1)) - Bytes const floatIntZero = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; // 0 - Bytes const floatIntMax = {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; // 2^63-1 - Bytes const floatUIntMax = {0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9A, 0x00, 0x00, 0x00, 0x01}; // 2^64-1 + Bytes const floatIntMin = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, +0x00, 0x00}; // -2^63 (rounds to nearest: -(2^63-1)) Bytes const floatIntZero = {0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; // 0 Bytes const floatIntMax = +{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; // 2^63-1 Bytes const +floatUIntMax = {0x19, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9A, 0x00, 0x00, 0x00, 0x01}; // +2^64-1 - Bytes const floatMaxExp = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00}; // 1e(Number::kMaxExponent + normalExp) - Bytes const floatPreMaxExp = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF}; // 1e(Number::kMaxExponent + normalExp - 1) - Bytes const floatMinusMaxExp = {0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00}; // -1e(Number::kMaxExponent + normalExp) - Bytes const floatMinExp = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; // 1e(Number::kMinExponent - normalExp) - Bytes const floatMax = {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0x00}; // Number::kMaxRep e(Number::kMaxExponent - normalExp) + Bytes const floatMaxExp = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0x00, 0x00, +0x80, 0x00}; // 1e(Number::kMaxExponent + normalExp) Bytes const floatPreMaxExp = {0x0D, 0xE0, +0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF}; // 1e(Number::kMaxExponent + normalExp +- 1) Bytes const floatMinusMaxExp = {0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0x00, 0x00, +0x80, 0x00}; // -1e(Number::kMaxExponent + normalExp) Bytes const floatMinExp = {0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}; // 1e(Number::kMinExponent - +normalExp) Bytes const floatMax = {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, +0x00, 0x80, 0x00}; // Number::kMaxRep e(Number::kMaxExponent - normalExp) - Bytes const floatMaxIOU = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x63, 0xFF, 0x9C, 0x00, 0x00, 0x00, 0x4E}; // 9999999999999999e(96) - Bytes const floatMinIOU = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x9D}; // 1e(-96 - 3 + normalExp = -81) + Bytes const floatMaxIOU = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x63, 0xFF, 0x9C, 0x00, 0x00, +0x00, 0x4E}; // 9999999999999999e(96) Bytes const floatMinIOU = {0x0D, 0xE0, 0xB6, 0xB3, +0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x9D}; // 1e(-96 - 3 + normalExp = -81) - Bytes const float1 = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // 1 - Bytes const floatMinus1 = {0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // -1 - Bytes const float1More = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x03, 0xE8, 0xFF, 0xFF, 0xFF, 0xEE}; // 1.000 000 000 000 001 - Bytes const float2 = {0x1B, 0xC1, 0x6D, 0x67, 0x4E, 0xC8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // 2 - Bytes const float10 = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEF}; // 10 - Bytes const floatPi = {0x2B, 0x99, 0x2D, 0xDF, 0xA2, 0x32, 0x48, 0xE8, 0xFF, 0xFF, 0xFF, 0xEE}; // 3.141592653589793 - Bytes const floatInvalidZero = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00}; // INVALID - Bytes const floatMinus3 = {0xD6, 0x5D, 0xDB, 0xE5, 0x09, 0xD4, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // -3 + Bytes const float1 = {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, +0xFF, 0xEE}; // 1 Bytes const floatMinus1 = {0xF2, 0x1F, 0x49, 0x4C, 0x58, 0x9C, 0x00, +0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // -1 Bytes const float1More = {0x0D, 0xE0, 0xB6, 0xB3, +0xA7, 0x64, 0x03, 0xE8, 0xFF, 0xFF, 0xFF, 0xEE}; // 1.000 000 000 000 001 Bytes const float2 = +{0x1B, 0xC1, 0x6D, 0x67, 0x4E, 0xC8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // 2 Bytes const float10 += {0x0D, 0xE0, 0xB6, 0xB3, 0xA7, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEF}; // 10 Bytes const +floatPi = {0x2B, 0x99, 0x2D, 0xDF, 0xA2, 0x32, 0x48, 0xE8, 0xFF, 0xFF, 0xFF, 0xEE}; +// 3.141592653589793 Bytes const floatInvalidZero = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x81, 0x00, 0x00, 0x00}; // INVALID Bytes const floatMinus3 = {0xD6, 0x5D, 0xDB, +0xE5, 0x09, 0xD4, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xEE}; // -3 std::string const invalid = "invalid_data"; diff --git a/src/tests/libxrpl/tx/wasm/HostCalls.cpp b/src/tests/libxrpl/tx/wasm/HostCalls.cpp index 79ea4b54fc..eba4a5dabd 100644 --- a/src/tests/libxrpl/tx/wasm/HostCalls.cpp +++ b/src/tests/libxrpl/tx/wasm/HostCalls.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -8,6 +6,7 @@ #include #include +#include #include #include @@ -294,8 +293,7 @@ protected: TEST_F(TraceNumCall, I64ArrivesWholeIncludingMostNegativeValue) { EXPECT_CALL( - host_, - traceNum(std::string_view("count"), std::numeric_limits::min())) + host_, traceNum(std::string_view("count"), std::numeric_limits::min())) .WillOnce(Return(0)); EXPECT_EQ(hostAnswer(), 0); diff --git a/src/tests/libxrpl/tx/wasm/Preflight.cpp b/src/tests/libxrpl/tx/wasm/Preflight.cpp index 21eddcb003..0c90d446ac 100644 --- a/src/tests/libxrpl/tx/wasm/Preflight.cpp +++ b/src/tests/libxrpl/tx/wasm/Preflight.cpp @@ -1,10 +1,9 @@ -#include - #include #include #include #include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/WasmFixture.h b/src/tests/libxrpl/tx/wasm/WasmFixture.h index c8ad70d107..96c638b263 100644 --- a/src/tests/libxrpl/tx/wasm/WasmFixture.h +++ b/src/tests/libxrpl/tx/wasm/WasmFixture.h @@ -1,15 +1,13 @@ #pragma once -#include - #include #include #include -#include - #include #include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/WasmVM.cpp b/src/tests/libxrpl/tx/wasm/WasmVM.cpp index a77bbc4555..4eb5e23a99 100644 --- a/src/tests/libxrpl/tx/wasm/WasmVM.cpp +++ b/src/tests/libxrpl/tx/wasm/WasmVM.cpp @@ -1,12 +1,12 @@ -#include +#include #include #include #include -#include #include #include +#include #include #include @@ -173,13 +173,9 @@ TEST_F(WasmVMTest, UnrunnableModuleIsNodeSideFault) Bytes code; std::string_view entryPoint; } const cases[] = { - {.what = "not wasm at all", - .code = Bytes{0, 1, 2, 3}, - .entryPoint = escrowFunctionName}, + {.what = "not wasm at all", .code = Bytes{0, 1, 2, 3}, .entryPoint = escrowFunctionName}, {.what = "empty", .code = Bytes{}, .entryPoint = escrowFunctionName}, - {.what = "no such export", - .code = assemble(kEngineWat), - .entryPoint = "no_such_export"}, + {.what = "no such export", .code = assemble(kEngineWat), .entryPoint = "no_such_export"}, {.what = "export is not a function", .code = assemble(kEngineWat), .entryPoint = "not_a_function"}, @@ -302,9 +298,10 @@ TEST_F(WasmVMTest, FatalHostErrorStopsRun) // the host, and must not take the node with it. TEST_F(WasmVMTest, ThrowingHostFunctionBecomesInternal) { - EXPECT_CALL(host_, getLedgerSqn()).WillOnce([]() -> std::expected { - Throw("the ledger came apart"); - }); + EXPECT_CALL(host_, getLedgerSqn()) + .WillOnce([]() -> std::expected { + Throw("the ledger came apart"); + }); auto const outcome = run(kEngineWat, kAmpleGas, "calls_the_host");