diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake index 07fd2834e0..feea6f2a54 100644 --- a/cmake/XrplCore.cmake +++ b/cmake/XrplCore.cmake @@ -302,8 +302,6 @@ if(xrpld) "${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp" ) target_sources(xrpld PRIVATE ${sources}) - - target_link_libraries(xrpld rs_hello_world_cxxbridge) endif() target_link_libraries(xrpld Xrpl::boost Xrpl::opts Xrpl::libs xrpl.libxrpl) diff --git a/crates/CMakeLists.txt b/crates/CMakeLists.txt index 51cb22fc1d..5ba2714a4e 100644 --- a/crates/CMakeLists.txt +++ b/crates/CMakeLists.txt @@ -42,7 +42,6 @@ function(add_xrpl_crate name) add_dependencies(xrpl_crates ${name}_cxxbridge) endfunction() -add_xrpl_crate(rs_hello_world CRATE rs_hello_world FILES lib.rs) add_xrpl_crate(xrpl_wasm_vm_ffi CRATE xrpl_wasm_vm_ffi FILES lib.rs) # Test-only, and deliberately not part of xrpl_wasm_vm_ffi: it carries the `wat` assembler, diff --git a/crates/Cargo.lock b/crates/Cargo.lock index ac8823570e..f118b25e84 100644 --- a/crates/Cargo.lock +++ b/crates/Cargo.lock @@ -223,13 +223,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rs-hello_world" -version = "0.1.0" -dependencies = [ - "cxx", -] - [[package]] name = "scratch" version = "1.0.9" diff --git a/crates/Cargo.toml b/crates/Cargo.toml index e2efab629b..840d9a1149 100644 --- a/crates/Cargo.toml +++ b/crates/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["hello_world", "xrpl-wasm-vm-ffi", "xrpl-wasm-vm", "xrpl-wasm-testkit", "xrpl-host-functions", "xrpl-host-functions-macros"] +members = ["xrpl-wasm-vm-ffi", "xrpl-wasm-vm", "xrpl-wasm-testkit", "xrpl-host-functions", "xrpl-host-functions-macros"] resolver = "3" [workspace.dependencies] diff --git a/crates/hello_world/Cargo.toml b/crates/hello_world/Cargo.toml deleted file mode 100644 index 2e5a329c9a..0000000000 --- a/crates/hello_world/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "rs-hello_world" -version = "0.1.0" -edition.workspace = true - -[lib] -crate-type = ["staticlib"] - -[dependencies] -cxx.workspace = true diff --git a/crates/hello_world/src/lib.rs b/crates/hello_world/src/lib.rs deleted file mode 100644 index b1cb121fa0..0000000000 --- a/crates/hello_world/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[cxx::bridge(namespace = "rs::hello_world")] -mod ffi { - extern "Rust" { - fn hello_world() -> String; - } -} - -pub fn hello_world() -> String { - "hello_world".to_string() -} diff --git a/docs/claude/wasm-vm/abi.md b/docs/claude/wasm-vm/abi.md deleted file mode 100644 index 0e499178f2..0000000000 --- a/docs/claude/wasm-vm/abi.md +++ /dev/null @@ -1,122 +0,0 @@ -[← Rust WASM VM docs](index.md) - -# The ABI: one declaration, three outputs - -`crates/xrpl-host-functions/` is the one declaration. C compatibility adds a **third -output** beside the trait and the spec enum — a *generated, checked-in* C header with a CI -diff — not a second input. "Explicit vs hidden" is the wrong axis; "derivable and emitted" -is the right one, because C authors read a header, not a macro. - -**Adding a host function** is one `host_functions!` entry plus one arm in -`register_host_functions`'s exhaustive `match` (a new `HostFunctionSpec` variant will not -compile until it is registered), one `MOCK_METHOD` in `MockHostFunctions`, and one method on -`HostContext` if C++ is to serve it. - -## The lowering table - -The DSL already implied this; it was never written down, and that was the whole gap. - -``` -params, in declared order: - &self -> nothing (receiver, not part of the ABI) - i32, bool -> i32 (bool: nonzero = true) - i64 -> i64 - &[u8], &str -> i32 ptr, i32 len const uint8_t*, int32_t - &mut [u8] -> i32 ptr, i32 len uint8_t*, int32_t (an output region) - -returns, always HostResult; Err(e) -> negative code, or a trap when host-fatal: - HostResult -> i32 = bytes written into the output region - HostResult, -> i32 = the value - HostResult<()> -> i32 = 0 -``` - -Total, unambiguous and **positional**: every wasm parameter is a declared parameter in -order, so the C prototype is a direct reading of the declaration. **The macro must reject -any type not in this table** — that is C++'s `WasmImpArgs` `static_assert` restored, and it -is what keeps the C API always surfaceable. - -All five current declarations lower to exactly the deleted C++ `_proto` aliases (verified -2026-07-29; `&self` dropped below since it contributes no C parameter): - -| Declaration | Derived C | -|---|---| -| `get_ledger_sqn(out: &mut [u8]) -> HostResult` | `int32_t(uint8_t*, int32_t)` | -| `get_current_ledger_obj_field(field: i32, out: &mut [u8]) -> HostResult` | `int32_t(int32_t, uint8_t*, int32_t)` | -| `sha512_half(data: &[u8], out: &mut [u8]) -> HostResult` | `int32_t(const uint8_t*, int32_t, uint8_t*, int32_t)` | -| `trace(msg: &str, data: &[u8], as_hex: bool) -> HostResult<()>` | `int32_t(const uint8_t*, int32_t, const uint8_t*, int32_t, int32_t)` | -| `trace_num(msg: &str, number: i64) -> HostResult<()>` | `int32_t(const uint8_t*, int32_t, int64_t)` | - -**Discipline the table requires**: a byte output is an explicit `out: &mut [u8]` plus -`HostResult`, never a returned value. `get_ledger_sqn` writes 4 LE bytes and returns -4 — it does not return the sequence number; by the same rule `float_to_int` takes an out -region rather than returning `i64`. A scalar `HostResult` means value-in-the-return. - -**The out-region contract, which the engine relies on: write only if the whole value fits, -and return its true length either way.** So a host never needs to know the guest's buffer -size — the engine turns `n > cap` into `BufferTooSmall`. - -## Closing the drift gap to `register.rs` - -**wasmi 1.1 cannot introspect a registered host function's signature.** `Linker::get` -returns `None` for `func_wrap`'d functions — they land in `Definition::HostFunc` -(`wasmi-1.1.0/src/linker.rs:147`), and `Definition::ty()` exists at `:171` but `Definition` -and `get_definition` are private. So "assert `Func::ty()` equals the spec" is unavailable. - -| Approach | `register.rs` | Guarantee | -|---|---|---| -| Generate closures wholesale | disappears | by construction | -| **Generate `link_*` shims, hand-write bodies** | **stays, readable** | **compile-time** | -| Hand-write everything + probe-module test | stays | test-time | - -**Preferred: the middle row** — the macro emits the *type* without the *body*: - -```rust -pub type Sha512HalfFn = - fn(Caller<'_, VmState<'_>>, i32, i32, i32, i32) -> Result; - -pub fn link_sha512_half(l: &mut Linker>, f: Sha512HalfFn) - -> Result<(), LinkerError> { l.func_wrap(MODULE, HostFunctionSpec::Sha512Half.wasm_name(), f) } -``` - -Wrong arity, scalar type or return then becomes a compile error, and the same lowering -table emits both the alias and the C prototype so they cannot drift. *Constraint*: `fn` -pointers accept only non-capturing closures; every arm today is non-capturing, and one that -needs to capture can take `impl Fn(..) + Send + Sync + 'static` instead. Cheap extra worth -having: a **probe-module test** that synthesises a WAT module importing every function with -its declared type and instantiates it — the only check that also catches module-name and -missing-import mistakes, from the guest's side. - -Deferred together: the shims, the generated header, the probe test. - -## The ABI crate is a library both sides link - -It is consumed as an ordinary dependency — by `xrpl-wasm-vm` today, the guest stdlib next. -Neither invokes `host_functions!`; consumers get the generated code, not the generator. -That makes four properties load-bearing: - -| Property | Why | Status | -|---|---|---| -| `#![no_std]`, no allocator | the guest stdlib is strictly `no_std` | ✓ `Vec` left when byte outputs became `out: &mut [u8]` | -| zero runtime dependencies | anything else must also build for the guest | ✓ `cargo tree` is the proc-macro crate alone | -| builds for `wasm32-unknown-unknown` | it links into the guest | ✓ verified | -| implementable by **both** sides | one declaration, two implementors | ✓ the out-param shape is what buys this | - -A host impl writes into `out` and returns the length; a guest impl forwards to the import -and decodes the `i32` through `HostError::from_code`, which range-checks — unlike the SDK's -bare transmute, which is "new error codes are UB in the guest" in -[open-questions.md](open-questions.md). One trait serves both *because the declaration is now -the wire shape*. - -**Known gap.** The `#[link(wasm_import_module = "…")] unsafe extern "C" { … }` block is not -generated; the PoC's macro did generate it plus a `GuestHost` impl. If the stdlib -hand-writes it, that is precisely the drift a single source of truth exists to prevent. One -wrinkle to decide first: a generated guest impl needs `HostError::from_code`, a name no -declaration mentions, so it would be the first vocabulary dependency inside an otherwise -closed expansion. - -**Convention: the expansion is closed.** Every name in it is generated or written in the -declarations; `names_no_crate_of_its_own` enforces it. The macro owns `HostFunctions`, -`HostFunctionSpec`, `ALL`, `wasm_name()`, `gas()` and the private `HostFnSpec` row type. -The facade hand-writes only the vocabulary declarations are written in — `HostError`, -`HostResult`, `HASH_LEN` — which resolve at the call site like `&[u8]` does. `HostFnSpec` -and `spec()` are private; read the table through `wasm_name()` / `gas()`. diff --git a/docs/claude/wasm-vm/bridge.md b/docs/claude/wasm-vm/bridge.md deleted file mode 100644 index 97d874f62d..0000000000 --- a/docs/claude/wasm-vm/bridge.md +++ /dev/null @@ -1,153 +0,0 @@ -[← Rust WASM VM docs](index.md) - -# The cxx bridge - -`crates/xrpl-wasm-vm-ffi/src/lib.rs` is the whole of the Rust half; `HostContext.{h,cpp}` and -`WasmVM.{h,cpp}` are the C++ half. Two decisions carry the design. - -Three crossings, not two: `run_escrow` in, the host calls back out, and `check_escrow` -in. The third goes one way only — screening a module needs no host — so it takes no -`HostContext`, has no C++-exception half to contain, and is the one bridge function the -crate's own tests can call outright. - -**The result is total, not `Result`.** cxx's `Result` sugar throws a `rust::Error` into -C++; a status is the better interface for a condition the caller has to turn into a TER -anyway. `RunResult { status, result, gas_used, detail }` flattens the engine's -`Result` because a cxx enum carries no payload, and `RunStatus` is -1:1 with `RunError` plus `Ok` and `Panic`. Both directions of that map are compile-enforced: -`status_of`'s `match` is exhaustive over `RunError`, and C++'s `switch` over the generated -enum has no `default`, so an outcome added to the engine fails to build until it has been -given a status *and* a TER. - -**Neither side may unwind into the other, and the two halves are not symmetric.** - -- A **C++ exception** is stopped in C++. Every `HostContext` method is `noexcept` and every - body goes through one `guarded()` that catches `std::exception` and `...`, journals, and - returns -1. Nothing relies on cxx's own `trycatch`, which only catches `std::exception` - and only for `Result` returns. -- A **Rust panic** is caught in Rust, by `guarded()` in the bridge. `[profile.release]` - turns overflow checks on, so this is a live path; `#[cfg(panic = "abort")] - compile_error!` keeps a profile change from silently defeating it. -- The asymmetry is what makes each half sufficient: because the C++ shims never unwind, - every frame between a panic and `catch_unwind` is Rust. - -Both halves are named `guarded`, and each is one function that every crossing goes through: -Rust's takes the panic arm as an argument (`ffi::RunResult::panicked`), C++'s takes the value -to answer with if the call throws. Anything C++ catches there is xrpld's own — a bad -allocation, or a `funcName` that is not valid UTF-8 and so cannot become a `rust::Str` — -never a wasm outcome, since those arrive as statuses. - -`HostContext` holds a `HostFunctions&` and lowers its typed `std::expected` onto the wire. -The `&self`-vs-non-const worry was a non-issue: a `const` member function holding a -non-const reference can still call `cacheLedgerObj`/`updateData`. `cxx_name` on each method -keeps ABI names on the Rust side and rippled's camelBack on the C++ side. `guarded` names the -failing call through a defaulted `std::source_location` rather than a string per call site; -`__func__` would expand to `operator()` inside the lambda. - -The five current functions needed **no change to `HostFunctions`** — the shim absorbs the -`uint32 → bytes` (via `adjustWasmEndianess`, which is where the wasm boundary's byte order -is decided for the whole system), `i32 → SField` and `Hash → 32 bytes` lowerings. Where that -will stop being true: `float_to_mant_exp` (two output regions), the `FieldLocator` entries, -and `updateData`. - -## The TER map - -`runEscrowWasm` owns it. `tecINTERNAL` reports no cost by convention: it says the fault is the -node's, and charging a transaction for a node's defect would write that defect into the ledger. - -| `RunStatus` | TER | cost | -|---|---|---| -| `Ok` | — | `gas_used` | -| `OutOfGas` | `tecOUT_OF_GAS` | `gas_used` | -| `Trap`, `NoMemory`, `Instantiate` | `tecFAILED_PROCESSING` | `gas_used` | -| `Compile`, `EntryPoint` | `tecINTERNAL` | none | -| `Internal`, `Panic` | `tecINTERNAL` | none | - -`Compile` and `EntryPoint` are `tecINTERNAL` because preflight decides both from the same -bytes and the same engine, so agreement is not a matter of degree: reaching apply means the -screening did not happen. `Instantiate` is **not** in that row, and the reason is the point of -the whole arrangement — see below. `NoMemory` had no old TER to match (it used to reach the -guest as code -14); `tecFAILED_PROCESSING` treats it as the contract fault it is. - -One thing to settle before a long-lived escrow exists: `Compile` is only a node fault while -the engine's configuration never changes. A contract created under one feature set and -finished under another could legitimately fail to compile at apply, so either the config is -amendment-gated or `Compile` joins the charged row. - -`gas <= 0` is refused as `temBAD_AMOUNT` before the engine is called, restoring what -`WasmiEngine::run` did — see [open-questions.md](open-questions.md). - -## The preflight map - -`preflightEscrowWasm` owns it, and it is deliberately flat: every fault in the module is -one answer, because a caller's only decision is whether the transaction may proceed. - -| `CheckStatus` | `NotTEC` | -|---|---| -| `Ok` | `tesSUCCESS` | -| `Compile`, `Import`, `EntryPoint`, `Memory` | `temBAD_WASM` | -| `Panic` | `telFAILED_PROCESSING` | - -The statuses stay distinct anyway: the *detail* is what a contract author needs, and one -status per stage keeps the map's arms reviewable and lets it grow without inventing -distinctions later. - -`Panic` is not `temBAD_WASM`. A defect in the engine teaches nothing about the module, and -`tem` would record our bug as the transaction's malformation; `tel` is the preflight -analogue of `tecINTERNAL`'s "the fault is the node's" — local, not forwarded, no fee. Two -things follow that are worth stating: divergence between nodes is not what the code choice -fixes (a panic in deterministic code is not node-local, and if it were, no TER would -reconcile the two), and this arm has no test on the C++ side, because there is no reliable -way to make the engine panic from a fixture. - -**The signature the C++ front does not have is the point**: `(Bytes, beast::Journal, -std::string_view) -> NotTEC`, with no `HostFunctions&`. The deleted `preflightEscrowWasm` -took one and could therefore never have been called from a real `preflight()` — -`PreflightContext` has no view to build a host over. - -## Why `Instantiate` is the contract's fault - -The map must not depend on preflight being exhaustive, because it cannot be. `check` closes -compile, imports, the entry point and an exported memory over the page cap — but a memory a -module *keeps to itself* is absent from its exports, so such a module passes screening and -then fails to instantiate ([engine.md](engine.md)). That is a deterministic property of the -code, identical on every node, and nothing this node did; charging it as -`tecFAILED_PROCESSING` says so, where `tecINTERNAL` would blame the node and forgive the gas. - -The other half is in the engine rather than the map: `vm::instantiation_failure` reports a -failure carrying a trap code as `RunError::Trap`, because a start section that traps is guest -code trapping, and a trap is the guest's fault wherever it happens. What is left for -`Instantiate` is a module the linker or the store would not accept at all — -`vm_limits::instantiation_failure_is_a_module_the_engine_will_not_accept` pins both shapes. - -So `tecINTERNAL` now means what it says: `Internal` and `Panic`, the node's own defects, plus -the two stages preflight decides exactly. - -## The one copy left on the byte path, and why it needs `HostFunctions` to change - -The engine's side of the byte path is copy-free by construction — `write_into` hands the host -guest memory directly, `write_buffered` copies once after every rule has passed -([engine.md](engine.md)). **The C++ side then puts a copy back**, because `HostFunctions` -returns its answer *by value*: - -```cpp -std::expected getCurrentLedgerObjField(SField const&) const; -``` - -`Bytes` is a `std::vector`, so serving one field allocates, fills, gets copied -into `out` by `HostContext::answer`, and is freed — a heap round trip per host call, on a -consensus path, for a value the caller already has a buffer for. **49 of the 66 virtuals -return `Bytes` this way**; only the two `Hash` ones are inline. - -The fix is an out-param form on `HostFunctions` itself — `(…, std::span out) --> std::expected`, returning the value's true length on the -same "write only if it all fits" contract the ABI already uses end to end. That makes the -convention identical on both sides of the bridge and leaves `HostContext` with no copy to -make. Note the two shapes are not equivalent for every function: one that cannot know its -length without building the value still allocates internally, so the win is real for field -and keylet reads and smaller for the float ops. - -Deliberately **not** done with the bridge: it touches 49 signatures plus -`WasmHostFunctionsImpl`, `HostFuncImpl*.cpp` and the test hosts, which is a mechanical sweep -that would bury the bridge in review. Sequence it after a caller exists, so the sweep can be -measured against something that runs. diff --git a/docs/claude/wasm-vm/conventions.md b/docs/claude/wasm-vm/conventions.md deleted file mode 100644 index 9ad9fb25cf..0000000000 --- a/docs/claude/wasm-vm/conventions.md +++ /dev/null @@ -1,24 +0,0 @@ -[← Rust WASM VM docs](index.md) - -# Conventions - -**Comments.** Terse. A comment should say something the compiler cannot check and the code -cannot show; everything else is a candidate for deletion. Keep: why an apparent redundancy is -not one (the `MAX_FIELD_BYTES` check beside the clamp; `is_fatal`/`host_fatal` as two lists; -`MUST_TRAP` not deriving from `is_fatal` — each of these has been "simplified" wrongly in a -mutation test at least once); load-bearing invariants; hidden contracts a signature cannot -state; wasmi facts that decide a design. Cut: prose restating the next line; the same -rationale on a field and on its reader; retellings of these docs. - -**No references to C++ that will not survive the merge.** They read as evidence but point at -deleted files. The crate has none, in `src/` or `tests/`. Two live exceptions stand: -`Protocol.h`'s `kMaxWasmDataLength` and `kWasmTransferLimit`, which are where those numbers -are defined for the rest of the system. The parity evidence itself lives in -[history.md](history.md) instead, which is commit-pinned and therefore stays resolvable. - -**No historical comments** in code — describe the present, not how it differs from a previous -state. - -**C++ naming.** rippled's camelBack for methods, `k`-prefixed CamelCase for constants; the -bridge keeps ABI names on the Rust side and camelBack on the C++ side via `cxx_name`. Test -names are subject-first with no leading article ([testing.md](testing.md)). diff --git a/docs/claude/wasm-vm/engine.md b/docs/claude/wasm-vm/engine.md deleted file mode 100644 index 4c7a51932b..0000000000 --- a/docs/claude/wasm-vm/engine.md +++ /dev/null @@ -1,171 +0,0 @@ -[← Rust WASM VM docs](index.md) - -# How the engine works - -Contracts worth knowing before changing anything, and the reasons that are not visible in -the code. - -**Two channels for a result.** A value or a guest-actionable error is the `i32` the wasm -function returns (`>= 0` value, `< 0` a `HostError` code). A **host-fatal** error — -`OutOfGas`, `Internal`, `NoMemExported` — traps instead, carrying `FatalHostError(HostError)` -as the payload so `run` can name the condition with `downcast_ref` rather than -string-comparing a message. XLS-0102 requires immediate halting on gas exhaustion, and a -guest handed `OutOfGas` as a code would run to the end of its current basic block — a -stopping point wasmi's `ConsumeFuel` placement decides rather than the protocol. -`is_fatal` spells the set variant by variant so a new `HostError`'s channel is chosen, not -inherited from its number. **`OutOfTransferLimit` is soft**: the one budget a contract can -be expected to handle. - -`is_fatal` and `vm::host_fatal` are two lists that must agree. One direction is -compiler-enforced (`host_fatal` is exhaustive, so a new variant fails to build); -`every_fatal_error_has_an_outcome_of_its_own` covers the other. `HostError::ALL` and -`HostFunctionSpec::ALL` exist because an exhaustive `match` forces you to *write an arm* but -cannot *enumerate* variants, and every const-assertion scheme over `ALL` is beaten by "add -the variant, give its arm a value, leave `ALL` alone". The airtight mechanism is a single -declaration site: a `host_errors!` macro emits the enum, `ALL` and `from_code` from one list. - -**Every failure carries its cost.** `run` returns `Result` where -`RunFailure` is `{ error: RunError, fuel_used }`, so gas is on both paths by construction. A -cost that cannot be read becomes `RunError::Internal` rather than a number — `0` would -forgive a run its whole cost and `gas` would charge an untouched one for everything. -`guest_halted` asks "did the guest halt?" at *every* stage from instantiation on, so a start -section that burns the limit is `OutOfGas`, not `Instantiate`: the stage a run stopped at is -not what the caller maps. `instantiation_failure` finishes the thought — a failure carrying a -trap code is `Trap`, since a start section that traps is guest code trapping — leaving -`Instantiate` to mean a module the linker or the store would not accept. - -**Two ways a byte answer reaches the guest**, both taking a `Region`: - -- `write_into` — the host writes straight into the guest's output region. Used by calls with - no byte input. Zero copy. -- `write_buffered` — the host fills `VmState::out_buffer` and the engine copies it to the - guest once every rule has passed. Used by calls that also *read* guest memory, because a - `&mut` view of that memory admits no simultaneous `&` view. `Memory::data_and_store_mut` - (`memory/mod.rs:165`) returns `(&mut [u8], &mut T)` — guest bytes and store data in one - split borrow — which is what lets any number of inputs stay borrowed while the answer is - written. No copying inputs out, no `unsafe`. - -`write_buffered` never tells the host the guest's capacity: it offers the whole buffer and -takes the value's true length, so nothing reaches guest memory until the length, bounds, fit -and budget have all passed — **a refused value reaches it in no part**, which `write_into` -can only bound rather than prevent. The output is judged *after* the inputs, so a call with -both malformed reports the input's verdict; `NoMemExported` precedes both, because there is -no memory to validate a region against. `MAX_FIELD_BYTES` is checked beside the clamp on -purpose: the clamp bounds the **bytes**, the check bounds the **status**, since a host -reports a true length that can exceed the region it was offered. - -Why this shape: of the ~65 ABI entries, **38 have a byte input *and* a byte output**, 9 are -output-only, 18 are input-only or scalar. Of the 38, **22 have more than one region** — every -two-argument keylet, `nft_uri`, all four float arithmetic ops — which a one-input helper -cannot express at all. The 9 output-only ones are exactly the row a buffer makes worse, and -they keep `write_into`. - -**`Region`** (`region.rs`) is the wire's `(ptr, len)` as one type. It cannot catch a swapped -pair — `Region::new(len, ptr)` compiles, and no type can do better where the values arrive -as indistinguishable `i32`s in positional order; that is a job for a reader or for the shim -generator. What it enforces is that the pair cannot be *used* unchecked: `range()` is the -only way to indices, and it is where `InvalidParams` (the conversion to `usize` is the -negativity check) and the end-overflow guard live. It sits in its own module because Rust -privacy is module-level — inside `abi.rs` the helpers could still read `.ptr` and skip the -check. Verified: an attempted bypass is `error[E0616]: field ptr of struct Region is -private`. Construction is **infallible on purpose**; validating in `new` would hoist the -output region's verdict above the host call and break the input-first order that -`a_read_write_checks_its_input_before_its_output` pins. - -`Region::read` is then ordinary safe slicing, because a guest pointer is an *index*: wasm -linear memory is a byte array in the store, `mem.data(caller)` is a `&[u8]` over it, and -`data.get(start..end)` does the bounds check and returns a slice **aliasing** guest memory. -`get` rather than `[..]` because indexing panics, and a panic on a consensus path is a node -crash. Elision ties the returned slice's lifetime to `data`, so a host cannot stash an input -past the call. - -**Two budgets.** Gas is charged per host call from the spec table, before the body runs -(`charged` is the one path, so it cannot be forgotten); exhaustion spends what is left. The -transfer budget counts only bytes *copied* across — `charge_transfer` has one call site per -write path. A borrowed read copies nothing and is not charged; what bounds how many reads a -run makes is gas. Typed reads that materialise a host object will charge; this ABI has none -yet, and the alignment-copy charge for unaligned field reads has nothing to attach to until a -`FieldLocator` function exists. - -**Guest memory is resolved once per run, by kind.** `run` takes -`instance.exports(&store).find_map(Export::into_memory)` after `instantiate_and_start` and -keeps the handle in `VmState::memory`, so no call pays for an export lookup. By *kind*, never -by name: nothing in the wasm spec attaches meaning to `"memory"`. Caching is sound because a -`Memory` is an arena index, not a pointer — it survives `memory.grow`. Two consequences: -the field assumes **one module, one instance, one store per `run`** (module linking would -have to resolve per instance, or serve a call against the wrong memory), and **a start -section cannot make a host call needing memory** — `Module::instantiate` is `pub(crate)`, so -instantiation cannot be split from the start section. `a_start_section_cannot_make_a_host_call` -pins it. - -**Engine config is consensus-fixed**: fuel on, floats off, every post-MVP proposal off, one -process-wide `Engine` behind a `LazyLock` (an `Engine` is internally `Arc`ed and `Send + -Sync`). Notably `wasmi = { default-features = false, features = ["std"] }` — wasmi's `wat` -feature is **on by default** and makes `Module::new` accept text as readily as binary, which -would put a text assembler in the consensus path and make a transaction's validity a build -flag. `the_vm_refuses_a_text_format_module` catches that coming back, and -`WasmVMTest.TextFormatModuleIsRejected` catches it from the guest's side. - -**A start section cannot be rejected outright.** wasmi 1.1 exposes no -`InstancePre`/`ensure_no_start` and `ModuleHeader::start` is private, so only a byte-level -section scan would do it. It is metered and memory-capped regardless, since `run` installs -the fuel and the limiter before `instantiate_and_start`. - -## Screening without running: `check` - -`preflight.rs`'s `check` decides whether `run` would refuse a module before the guest's first -instruction — compile, imports, entry point — from **the compiled module alone**: no host, no -store, no gas, no execution. That is not economy, it is a requirement; the caller is a -transaction's preflight, which has no ledger to serve a host call from. - -Three things keep it from becoming a second opinion. Both stages compile through `vm::compile`, -so the configuration that decides validity cannot differ. The import set is -`HostFunctionSpec::ALL`, which is also what `register_host_functions` iterates, so adding a -host function extends the check and the linker at once. And the entry point's three faults are -described by one `entry_point_fault`, called from `run` with wasmi's error appended. - -The rules themselves are pure functions over what a module *declares* — `check_import` takes -`(namespace, name, ExternType)`, `entry_point_fault` takes an `Option` — so the -unit tests state each rule, its precedence and its wording on inputs built directly, and -`tests/preflight.rs` is left to run real modules. Precedence is a decision, not an accident: -an import breaking two rules reports the namespace, which is what explains the module's other -imports too. - -A fourth stage screens what a module *declares*: an exported linear memory whose initial size -is past the page cap is refused, since the store's limiter would refuse it anyway. The -**minimum** only — a declared maximum past the cap is legal and simply unreachable. Only the -exported memory is visible, which is enough for every contract the guest SDK produces, since -a contract needs an exported memory to make a host call at all. - -What stays invisible is one module: a memory the module keeps to itself, over the cap, which -passes the check and then fails instantiation — the reason a run's refusal at that stage is -charged to the contract rather than blamed on the node ([bridge.md](bridge.md)). A start -section is invisible too, but no longer matters: a trap in one is reported as -`RunError::Trap` and charged like any other trap. -`what_static_screening_cannot_see` is that one module, and `screening_and_a_run_agree` pins -the equivalence everywhere else — in both directions, so a rule that refused a contract the -engine would have served fails too. - -Import **signatures** are the deliberate gap: `check` compares names and kinds, not types, so -a mistyped import still parts a module from the engine at instantiation. Closing it needs the -expected `FuncType` per function, and the only non-duplicating source is the closure -`register.rs` registers — `wasmi::IntoFunc::into_func()` returns `(FuncType, _)` and -`Linker::func_wrap` is a thin wrapper over it, so making `register_host_functions` generic -over a sink would give the linker and a type table from one declaration site. - -**A dead end, recorded so nobody retries it.** Host-function parameters cannot be newtypes. -`wasmi::WasmTy` looks implementable — public, no sealing supertrait — but its bound names -`UntypedVal`, which wasmi re-exports only through a **private** `mod core` -(`wasmi-1.1.0/src/lib.rs:109-137`). Probed: `error[E0603]: module core is private`. The -escape hatch is a direct `wasmi_core` dependency pinned in lockstep with wasmi's own, plus a -`#[doc(hidden)]` method — not worth it on a consensus path. So the wire stays `i32` and pairs -are formed on the first line of each arm. - -## Known gap: `OutOfGas` does not always report the whole limit - -A contract that loops until the meter empties reports the full budget, but a budget too small -to reach the first charge reports `0`: wasmi leaves the remaining fuel in place on its own -`OutOfFuel` trap, and only `abi::charge` forces it to zero. The deleted C++ path did this -deliberately (`iw.setGas(0)` on out-of-gas, so the cost was always the full limit). Closing -the gap is a one-line change in `vm::run`, but it is consensus-visible metadata, so it is -called out rather than slipped in. diff --git a/docs/claude/wasm-vm/history.md b/docs/claude/wasm-vm/history.md deleted file mode 100644 index 3691b8a03e..0000000000 --- a/docs/claude/wasm-vm/history.md +++ /dev/null @@ -1,77 +0,0 @@ -[← Rust WASM VM docs](index.md) - -# History: review findings, and the deleted C++ path - -## Review findings (2026-07-29) - -A read of `vm.rs`, `abi.rs` and `register.rs` against the vendored wasmi 1.1.0. **Seventeen -of the eighteen are closed, C12 the only one left** — earlier revisions of these docs said -"fourteen of seventeen", which never matched the table. The rationale that is still -load-bearing has moved into [engine.md](engine.md). - -| # | Finding | Outcome | -|---|---|---| -| A1 | Out-of-gas returned a code instead of trapping, so how much guest code ran after exhaustion was wasmi's business | ✓ two-channel design, `FatalHostError` payload | -| A2 | `run` discarded gas accounting on every failure path, and its error was a `String` | ✓ `RunFailure { error, fuel_used }` over a typed `RunError` | -| A3 | `HOST_MODULE = "host"` matched no guest that exists | ✓ `host_lib`, pinned by test | -| A4 | Transfer budget charged for bytes never copied, and charged before validation | ✓ one call site per write path; reads are free | -| A5 | `Module::new` accepted WAT text — a behaviour the rewrite introduced by accident | ✓ `default-features = false` | -| A6 | The memory export's *name* was a rule the rewrite introduced | ✓ resolved by kind, as C++ did | -| B6 | `AbiRet` was vestigial | ✓ deleted | -| B7 | The `i64` pipeline was pointless and lossy (silent truncating cast) | ✓ `HostResult` end to end | -| B8 | `cxx` was an unused dependency of this crate | ✓ removed | -| B9 | Seven broken intra-doc links, plus historical comments | ✓ fixed, `deny` added | -| C10 | The `"memory"` export was a string hash lookup on every host call | ✓ resolved once per run, by kind | -| C11 | `read_write` memset 1 KiB of stack per call and did not generalize past one byte input | ✓ replaced by `write_buffered` + `Region` | -| C12 | `Linker` rebuilt per run; module compiled per run with no cache | **open — [open-questions.md](open-questions.md)** | -| D13 | The public surface was accidental (`RunOutcome` unnameable, limits unreachable) | ✓ exported; `MAX_FIELD_BYTES` renamed out of `abi.rs` | -| D14 | `abi.rs` *claimed* every access was a checked slice op | ✓ `forbid(unsafe_code)` + cast lints enforce it | -| D15 | Zero tests | ✓ 79 in `xrpl-wasm-vm` | -| D16 | `gas = 0` accepted silently; `get_fuel().unwrap_or(0)` reported the whole limit; entry-point diagnostic wrong for a wrong-signature export | ✓ closed — `gas <= 0` is `temBAD_AMOUNT` in `runEscrowWasm` | -| D17 | The start-section TODO reads like a hole | ✓ documented as not closeable with wasmi 1.1 | - -Three of the closed findings were **behaviour changes nobody had chosen** — A3, A5, A6 — and -all three restored C++ behaviour the rewrite had altered by accident. That is the pattern -worth carrying forward: on this path, "tidier than C++" is usually "different from -C++". A fourth decision, C11's buffer, extends it rather than restoring it. - -## Reference points from the deleted C++ path - -Import names and gas costs are ABI. The rest is *evidence of prior behaviour* — useful for -comparison and for the gas assertions in `Wasm_test.cpp`, not gospel. All recoverable with -`git show b7059deb9f^:` — note that `WasmVM.{h,cpp}` exist again at that path with -entirely different contents, so the revision in that command is doing real work. - -Deleted later, with the dead `wasmi::wasmi` link that was the only thing supplying their -``: `include/xrpl/tx/wasm/HostFuncWrapper.h` (the `*_proto` aliases and `*_wrap` -declarations, whose `.cpp` went in `b7059deb9f`) and `WasmImportsHelper.h` (`ImportVec`, -`WasmImpArgs`'s `static_assert`). Every remaining reference to either was inside a -commented-out file. The `_proto` aliases are the C lowering the table in [abi.md](abi.md) -reproduces, so they are worth reading before extending it. - -- **Import names + per-call gas**: `src/libxrpl/tx/wasm/WasmVM.cpp` - (`setCommonHostFunctions`, 64 entries plus `set_data` registered only in - `createWasmImport`; e.g. `ldgr_index` 60, `sha512_half` 2000, `set_data` 1000, `float_pow` - 5'500). -- **Guest-visible error codes**: `HostFunctionError` in `include/xrpl/tx/wasm/WasmCommon.h` - (-1 `Unimplemented` … -20 `FloatComputationError`; note **-11 is `OutOfTransferLimit`** - there, `InvalidDecoding` in the SDK; see "the two error enums have already drifted" in - [open-questions.md](open-questions.md)). -- **Host-fatal conditions were traps**: out-of-gas and internal errors threw - `hfErrOutOfGas` / `hfErrInternal` → trap → `tecOUT_OF_GAS` / `tecINTERNAL`. Only the - transfer limit was a soft, guest-visible failure. -- **Limits**: `maxPages = 128` (8 MiB), `kMaxWasmDataLength = 1024`, `kWasmTransferLimit = - 1 << 20`. The last two are still live in `include/xrpl/protocol/Protocol.h:328,333`. -- **Transfer limit** was charged for bytes actually copied: host→guest writes (`setData`) and - typed reads materialising a host object (uint256, AccountID, Currency, Asset), plus - unaligned `FieldLocator` copies (+`unalignedGas = 50`). Plain slice/string reads were not - charged. -- **Check order after a value existed** (`setData`): params → data-too-large → no-memory → - out-of-bounds → buffer-too-small → transfer → copy. Inputs (`getDataSlice`) were validated - before the call. `write_buffered` follows this; `write_into` cannot, since it must - bounds-check before handing over a slice. -- **Entry point** was `escrow_finish` (`escrowFunctionName`); gas `-1` meant unlimited, - `<= 0` meant `temBAD_AMOUNT`; on out-of-gas the reported cost was the full limit. Positive - return = conditions met; `0` or negative = reject. -- **wasmi's fuel table is consensus input** — pin the version deliberately (currently - `wasmi = "1.1.0"`). diff --git a/docs/claude/wasm-vm/index.md b/docs/claude/wasm-vm/index.md deleted file mode 100644 index c8ac87f9a3..0000000000 --- a/docs/claude/wasm-vm/index.md +++ /dev/null @@ -1,114 +0,0 @@ -# Rust WASM VM — working docs - -The Rust wasmi engine for programmable escrows on branch `Wasm-vm-redesign`, and the cxx -bridge that connects it to xrpld. - -| Read | When | -|---|---| -| [bridge.md](bridge.md) | changing anything that crosses between C++ and Rust, or the TER map | -| [engine.md](engine.md) | changing `vm.rs`, `preflight.rs`, `abi.rs`, `region.rs` — the invariants, and the wasmi facts that decided them | -| [abi.md](abi.md) | adding or changing a host function | -| [testing.md](testing.md) | running the loop, or adding a test on either side | -| [conventions.md](conventions.md) | before writing code or comments in the crate | -| [open-questions.md](open-questions.md) | the undecided ABI questions, and the two performance items gated on a benchmark | -| [history.md](history.md) | recovering deleted C++ behaviour, or checking a review finding's outcome | - -## What this branch is doing - -`Wasm-vm-redesign`: replacing the C++ wasmi **C-API** integration with a Rust wasmi -wrapper, written as production code built on the PoC's ideas — not a cleanup pass over the -PoC. - -`Rust_wasm_PoC` (and `Rust_wasm_PoC_benchmark`) are read-only reference branches. Their -crates are named differently — `host_functions`, `host_functions_macros`, `wasm_vm` (with -`imports.rs` where we have `register.rs`, plus `ffi.rs`), `stdlib`, `example_contract` — -read with `git show Rust_wasm_PoC:crates/`. - -**One PoC difference explains a lot of this crate.** The PoC's `host_abi!` inserted -`&self`, wrapped returns in `HostResult<_>`, and for a `Vec`/`[u8; N]` return -**appended `out: &mut [u8]` and changed the return to `HostResult`**. Here the -declaration *is* the signature — nothing is appended behind the reader's back. That is what -"no magic" means throughout these docs, and it is why byte outputs are written as explicit -out-params. - -The C-API path is gone: `b7059deb9f` ("Remove wasmi dependency") deleted -`WasmVM.{h,cpp}`, `WasmiVM.h`, `HostFuncWrapper.cpp` and dropped the conan `wasmi` -package. Old semantics are recoverable with `git show b7059deb9f^:` — do that rather -than guessing. See [history.md](history.md) for what is worth recovering. - -## Where the code lives - -- `crates/` — cargo workspace (edition 2024, resolver 3), built into the C++ build via - corrosion (`crates/CMakeLists.txt`, which registers the cxxbridge targets). - - `xrpl-host-functions/` — `no_std` ABI declaration: `host_functions! { … }` generates the - `HostFunctions` trait and the `HostFunctionSpec` enum (import name + gas per function). - Also `HostError`. **The single source of truth for the ABI** — see [abi.md](abi.md). - - `xrpl-host-functions-macros/` — the proc macro. An implementation detail of the crate - above, deliberately not re-exported: the ABI has one declaration site. - - `xrpl-wasm-vm/` — the wasmi wrapper. `vm.rs` (engine, store, `run`), `preflight.rs` - (`check` — compile, imports, entry point, declared memory, with no host, store or - gas), `abi.rs` (gas, - transfer budget, guest-memory marshaling), `region.rs` (the `(ptr, len)` type), - `register.rs` (one `func_wrap` per host function). See [engine.md](engine.md). - - `xrpl-wasm-vm-ffi/` — the cxx bridge, all three crossings. `RunStatus`/`RunResult` and - `run_escrow`, `CheckStatus`/`CheckResult` and `check_escrow`, `CxxHost`, the panic - guard. See [bridge.md](bridge.md). - - `xrpl-wasm-testkit/` — **test-only**: `compile_wat`, so the C++ tests write their modules - as WebAssembly text. A crate of its own so `wat` cannot reach the shipped node; see - [testing.md](testing.md). -- `include/xrpl/tx/wasm/`, `src/libxrpl/tx/wasm/` — C++ side: `HostFunc.h` (the ~60-method - `HostFunctions` interface), `HostFuncImpl*.cpp` (its implementations, over - `ApplyContext&`), `WasmCommon.h` (`HostFunctionError`, `Wmem`, `WasmTER`, `FieldLocator`). - The bridge's C++ half is `HostContext.{h,cpp}` (the ABI-shaped view of `HostFunctions`) - and `WasmVM.{h,cpp}` (`runEscrowWasm`, `preflightEscrowWasm`, gas validation, both TER - maps). -- `src/tests/libxrpl/tx/wasm/` — the C++ tests, in the `xrpl_tests` gtest binary. -- `include/xrpl/tx/wasm/README.md` is **stale**: it uses the long name `get_ledger_sqn` - where the code registers `ldgr_index`, and references `detail/WasmVM.cpp`, - `detail/HostFuncWrapper.cpp`, `HostFuncWrapper.h` and `ParamsHelper.h`, none of which - exist. - -## Current state (2026-08-04) - -**The whole workspace is green**: `cargo test --workspace`, `clippy --workspace ---all-targets`, `fmt`, and `cargo doc -p xrpl-wasm-vm --no-deps`. **173 tests** — 33 macro, -12 facade, 1 doctest, **110 in `xrpl-wasm-vm`** (20 unit; 90 integration — 13 `budgets`, -12 `host_calls`, 23 `memory_policy`, 20 `preflight`, 22 `vm_limits`), 15 in -`xrpl-wasm-vm-ffi`, 2 in `xrpl-wasm-testkit`. On the C++ side, **40 tests over the whole -loop** in seven fixtures: `./xrpl_tests ---gtest_filter='WasmVMTest.*:*Call.*:PreflightTest.*'`. - -**All three crossings are wired and a real contract runs through them**: C++ calls -`runEscrowWasm`, the engine services `ldgr_index` by calling back into -`xrpl::HostFunctions`, and the guest reads the answer out of its own memory; -`preflightEscrowWasm` screens a module through the third, with no host at all. Five host -functions are registered (`ldgr_index`, `home_le_field`, `sha512_half`, `trace`, -`trace_num`) out of the ~65 the full ABI will carry. - -**Seventeen of the eighteen review findings are closed**, C12 the only one left -([history.md](history.md)). - -## Next - -1. **A caller.** `EscrowFinish.cpp` still has no wasm reference, so `runEscrowWasm` and - `preflightEscrowWasm` are reached only from `src/tests/libxrpl/tx/wasm/`. Wiring it up is - what makes `WasmHostFunctionsImpl` (over a real `ApplyContext`) the host in production - rather than in principle. **Blocked on the protocol fields**: `FinishFunction` and - `ComputationAllowance` exist nowhere in this fork or upstream, and adding - `FinishFunction` also has to answer the **contract code-size cap** — there is none, and - preflight's cost is linear in the blob (a 249 KB module of duplicate imports measures - 1.5 ms, mostly wasmi's own parse). -2. **Import signatures at preflight.** `check` compares an import's namespace, name and - kind, not its type, so a mistyped import still parts a module from the engine at - instantiation. Deferred to when `host_functions!` generates the wasm-level lowering, - which the C header and the typed `link_*` shims in [abi.md](abi.md) both want anyway. - Note the deleted C++ `check` did not compare signatures either, so this is inherited - rather than new. -3. **A gas parity oracle.** `Wasm_test.cpp` asserts exact gas numbers (e.g. 29'502) and is - the best oracle we have, but it is commented out and its fixtures cannot run on this - engine — see the `env` finding in [testing.md](testing.md). -4. **The `Bytes`-by-value copy in `HostFunctions`** — [bridge.md](bridge.md). A - 49-signature sweep, so it wants a caller to measure against first. - -Also open: the two performance items and the ABI questions in -[open-questions.md](open-questions.md). diff --git a/docs/claude/wasm-vm/open-questions.md b/docs/claude/wasm-vm/open-questions.md deleted file mode 100644 index 3aa8ea2c7b..0000000000 --- a/docs/claude/wasm-vm/open-questions.md +++ /dev/null @@ -1,91 +0,0 @@ -[← Rust WASM VM docs](index.md) - -# Open questions and deferred work - -## Resolved, recorded so they are not reopened - -**`gas = 0` — refused in C++ as `temBAD_AMOUNT`.** The old code already decided this and an -earlier revision of these docs had it garbled: `WasmiEngine::run` rejected `gas <= 0` for -*every* value including `-1`, and `-1 = unlimited` applied only to preflight's `check`. -`runEscrowWasm` restores exactly that, which is why the engine's own budget stays a `u64` with -no invalid value to represent. - -**Import module name — `host_lib`**, matching the SDK and this fork's Rust fixtures. -`the_import_module_name_must_match` rejects `host`, `env` and the empty name. - -**`-1` collides semantically** — host `Unimplemented` vs Rust `Internal`. Now a decision -rather than an accident: the bridge treats them as one condition, "the host could not serve -this call, and the contract has no business interpreting why". Both are host-fatal, so both -stop the run and report `tecINTERNAL`, which is also what a C++ exception caught in -`HostContext::guarded` becomes. The guest-side half of the collision (its own `InternalError`) -is untouched. - -## ABI / guest-SDK interop - -Found auditing the guest SDK (`~/Documents/rust/xrpl-wasm-stdlib`, checkout `435a091f`) -against this fork. All are decisions rather than code. - -1. **Import name lineage.** The fixtures pin the SDK at `branch = renames` and use **short** - wire names (`parent_ldgr_hash`, `cache_le`, `tx_inner_arr_len`, `accountroot_id`, - `trustline_id`), matching `ldgr_index` / `home_le_field` / `sha512_half`. The standalone - SDK checkout is the **long**-name lineage (`get_parent_ledger_hash`, `cache_ledger_obj`, - `compute_sha512_half`). Which is authoritative is undecided. -2. **New error codes are UB in the guest.** The SDK decodes with a bare transmute and no - range check (`xrpl-common-stdlib/src/host/mod.rs:325`), valid only for `-1..=-20`. Making - host-fatal errors trap (A1) removed `OutOfGas` from the guest's view, and the - soft/fatal question is settled — **`OutOfTransferLimit` stays soft**. The *encoding* - question is not: `OutOfTransferLimit = -23` still reaches a transmuting guest, and - `NoRuntime = -21` would if anything returned it. Closing it needs either a range check in - the SDK or a remap into `-1..=-20`. -3. **The two error enums have already drifted.** C++ `HostFunctionError` spells -11 - `OutOfTransferLimit`; the Rust ABI spells it `Decoding`. `WasmVMTest.SoftHostErrorCodes- - CrossUnchanged` now walks every soft code so a further renumbering is caught, but the - divergence itself is unresolved — one of the two lists is wrong. -4. **`float_to_mant_exp` byte count.** The host returns **12** (8 mantissa + 4 exponent); - the guest doc says 8, and the guest's `match_result_code_with_expected_bytes` **panics** - on a non-negative mismatch. Note this function writes *two* output regions, a shape no - current helper serves. -5. **Return conventions are not uniform** — six of them: bytes-written; value-in-return - (`*_arr_len`, `nft_flags`); boolean 0/1 (`amendment_enabled`, `check_sig`); 1-based handle - (`cache_le`, always ≥ 1); status-0 (`trace*`, `set_data`); tri-state (`float_cmp` — `0` - equal, `1` first >, `2` second >). -6. **The SDK's drift checker is silently broken.** `tools/compareHostFunctions.js` - regex-parses `WasmVM.cpp` and `HostFuncWrapper.h`, both deleted. A generated C header - would give it a stable target again ([abi.md](abi.md)). - -## Performance, gated on a benchmark - -**Two optimisations are deferred pending measurement, not rejected.** Neither is worth -guessing at, and one benchmarking pass with the google-benchmark harness on a -host-call-heavy module settles both. - -1. **Lazy output buffer.** `VmState::out_buffer` is an inline `[u8; MAX_FIELD_BYTES]`, - zero-filled once per run whether or not the contract makes a call that uses it. The lazy - form is `Option<[u8; N]>` with `get_or_insert_with` (not `OnceCell` — that is for init - behind a shared borrow; `write_buffered` holds `&mut VmState`). The case against it today - is a magnitude argument a measurement could overturn: it defers one ~1 KiB fill per run, - invisible beside the `Module::new` that starts every run, and pays for it with a - discriminant test on **every host call** — the direction C11 moved cost away from. Also - note `Option<[u8; N]>` does not shrink `VmState` (no niche in a byte array), and - `Option>` does but then charges a malloc to the 38 functions that use this - path in order to save the ones that do not. -2. **C12: cached `Linker`, cached module.** Two independent halves. - - *Module compile cache* is the bigger win — a whole wasm translation per run versus - building a five-entry linker — and it is **not** blocked by the lifetime problem, since - a `Module` is engine-scoped. But it carries a question that is not the engine's to - answer: **who owns a compiled contract's lifetime?** An unbounded static cache inside a - library on a consensus path brings an eviction policy nobody asked for; the alternative - is handing `run` a pre-compiled module, which changes the signature the bridge now - consumes. Either way the answer comes from the caller side. - - *Per-run `Linker`* is blocked: `VmState<'h>`'s lifetime forces `Linker>` to - be per-run, so hoisting it means making the store data `'static` — not holding - `&'h dyn HostFunctions`. This was expected to fall out of the bridge; **it did not.** - `CxxHost<'a>` borrows the C++ `HostContext` for one run and coerces to - `&'h dyn HostFunctions` unchanged, so hoisting the linker is still its own piece of - work with no other reason to do it. - -So: **measure first**, and treat the linker and the lazy buffer as whatever the numbers say. -The module cache's open question is unchanged by the bridge — `run(wasm, gas, host, name)` is -now a signature the C++ side consumes, so handing it a pre-compiled module is a change to a -live interface rather than a hypothetical one, and **who owns a compiled contract's lifetime** -is still the caller's question to answer. diff --git a/docs/claude/wasm-vm/testing.md b/docs/claude/wasm-vm/testing.md deleted file mode 100644 index e36c1046c1..0000000000 --- a/docs/claude/wasm-vm/testing.md +++ /dev/null @@ -1,147 +0,0 @@ -[← Rust WASM VM docs](index.md) - -# Testing: the loop, and how the suites are built - -## The build / test loop - -- Fast: `cd crates && cargo check --workspace --all-targets`, `cargo test --workspace`, - `cargo clippy --workspace --all-targets`. -- **`cargo doc -p xrpl-wasm-vm --no-deps` is part of the loop, not a nicety.** `lib.rs` - carries `deny(rustdoc::broken_intra_doc_links)`, and neither `cargo test` nor `clippy` - checks doc links. **Caveat: it does not cover private modules**, which are not documented - by default — a dead link inside `abi.rs` passes silently (this is how a `VmState::scratch` - link survived the `out_buffer` rename). Add `--document-private-items` to check those, and - grep after renaming a field. `lib.rs` also carries `forbid(unsafe_code)`, - `deny(unreachable_pub)` and `deny` on four clippy cast lints, so an unargued cast fails the - build rather than warning. -- Full C++↔Rust: normal CMake build, then - `./xrpl_tests --gtest_filter='WasmVMTest.*:*Call.*'`. -- Guest-linkability (needs `rustup target add wasm32-unknown-unknown`): - `cargo check -p xrpl-host-functions --target wasm32-unknown-unknown`. Only the ABI crate — - `xrpl-wasm-vm` is host-side and pulls in wasmi, and `crates/hello_world` cannot be checked - for that target at all because it depends on `cxx` → `link-cplusplus`, which wants a C++ - toolchain for the target. -- VCS is **jj** (`jj st`, `jj log`), not raw git, for local work. - -### Two build gotchas that cost an afternoon each - -- **A stale build directory fails to link with `duplicate symbol '_rust_eh_personality'`.** - The conan `wasmi` package ships a Rust `std`, and so does our staticlib. `b7059deb9f` - dropped the conan requirement but left `find_package(wasmi REQUIRED)` and `wasmi::wasmi` in - the CMake, both now removed; a build folder generated before that still has - `build/generators/wasmi-*.cmake`, so re-run `conan install .. --output-folder . --build - missing --settings build_type=Debug` and delete them. Note this was *two differently - compiled* `std`s — two staticlibs from this workspace are fine, and `xrpld` already links - `rs_hello_world` alongside `xrpl_wasm_vm_ffi`. -- **`cargo test` on the bridge crate links only because nothing in the tests reaches a C++ - shim.** The `extern "C++"` symbols exist only in the CMake build, and the test binary links - because `-dead_strip` drops what no test path reaches. Verified: forcing a reference - (`let f: fn(&ffi::HostContext) -> _ = ...`) fails with `Undefined symbols: - _rs$wasm_vm$cxxbridge1$…`. So keep those tests on pure logic — the status map, the panic - guard, the wire conversions — and put anything that needs a host in the gtest. - **`check_escrow` is the exception**: it takes no `HostContext`, so its tests call the real - bridge function, hand-writing the two modules they need as bytes (the eight-byte header is - a valid module) rather than reaching for an assembler this crate does not have. - -## The Rust tests - -- **They come in two kinds, and the split is forced.** A wasmi `Caller` exists only during a - host call, so everything in `abi.rs` that takes one cannot be reached from a unit test. - Unit tests in `src/` cover what needs no live instance (wire conversions, budget - arithmetic, the limits); guest-memory policy lives in `tests/`, running real modules - against a configurable fake host. -- Those integration tests write modules as **WAT text** and assemble it themselves — `wat` is - a `[dev-dependencies]` entry and `support::assemble` its only caller, so the assembler - never enters the library. `run` takes binaries; there is no `run_wat`. -- `tests/support/mod.rs` holds the fake host and the import declarations. `Answer` separates - *what the host writes* from *what length it reports*, which is what makes the over-cap and - buffer-fit rules testable without values that large existing. - -## How the C++ tests are built - -`src/tests/libxrpl/tx/wasm/`, in the `xrpl_tests` gtest binary. Four decisions, each of which -had an obvious cheaper alternative that was worse. - -**Modules are WebAssembly text, assembled at run time.** Checked-in hex blobs do not scale -past one module — every host function needs its own, with its own import signature — and they -are unreviewable. So `compile_wat` comes over cxx from **`crates/xrpl-wasm-testkit`**, a crate -of its own that nothing in `libxrpl` or `xrpld` links. - -That separation is the whole point and is worth not undoing. The engine pins -`wasmi = { default-features = false }` because wasmi's `wat` feature makes `Module::new` -accept text as readily as binary, which would make a transaction's validity a build flag -(finding A5 in [history.md](history.md)). Putting `compile_wat` on the production bridge would -link an assembler into the shipped node even though nothing called it; a cargo feature would -make the test and production binaries differ. A separate crate makes "no assembler in the -node" a property of the link graph. `WasmVMTest.TextFormatModuleIsRejected` then feeds the -engine the very text the rest of the suite assembles, so the guest-side half of A5 is pinned -too. - -**The host is a `StrictMock`.** `MockHostFunctions` mocks only the methods the ABI declares; -the ~60 others keep `HostFunctions`' `Unimplemented` default, so a contract reaching past the -ABI fails the way production would. What this buys over a hand-written fake is assertions on -*what the host was asked* — that a guest `i32` became the right `SField`, that two borrowed -regions and a flag all arrived, that an `i64` survived as `INT64_MIN`. - -Strict rather than nice, because these modules import exactly what they mean to exercise: a -host call no test asked for means the engine reached for something on its own, which is worth -a failure rather than a warning. The cost is one line in the fixture — -`EXPECT_CALL(host_, checkSelf()).WillRepeatedly(Return(true))`, since `runEscrowWasm` asks -every run whether the host is clean. Verified by mutation: giving `escrow_finish` an -unstubbed host call fails the test under Strict and passes silently under `NiceMock`. - -*One trap worth knowing even so*: gmock's default action for `std::expected` is a -**successful** `T{}`, so a method with an `EXPECT_CALL` but no action would answer `0` and a -test could pass on an answer nobody chose. The mock's constructor therefore `ON_CALL`s every -method to the base class's `std::unexpected(Unimplemented)`. - -**Two levels of fixture.** `WasmTest` holds the mock, a capturing journal sink and `run(wat, -gas, entryPoint)`. `HostCallTest` adds a `wat()` the derived fixture supplies and -`hostAnswer()`, so a per-function test says only what the host was asked and what came back. -Then one fixture per host function — `LedgerSqnCall`, `CurrentLedgerObjFieldCall`, -`Sha512HalfCall`, `TraceCall`, `TraceNumCall` — because the module *is* that function's shared -setup. `WasmVMTest` keeps what belongs to the engine rather than to any function. - -**`PreflightTest` deliberately derives from `testing::Test`, not from `WasmTest`**, and holds -no mock: `preflightEscrowWasm` takes no host, and a fixture that supplied one would hide the -signature that is the point. That is why `assembleWat` is a free function in `WasmFixture.h` -rather than a `WasmTest` member. `PreflightTest.ScreeningAgreesWithARun` is the one test -there that does build a host — it puts the same modules through `runEscrowWasm` so the two -entry points do not have to be trusted to agree. - -**The journal is captured, not sent to a null sink.** -`WasmVMTest.ThrowingHostFunctionBecomesInternal` asserts the exception text *and* that the log -names `getLedgerSqn`; without that, an exception silently swallowed with no log would pass, and -`HostContext::guarded`'s `source_location` would be untested. - -Two properties are pinned from the guest's side rather than asserted about internals: -`LedgerSqnCall.BufferTooSmallIsRefusedWholeNotTruncated` has the contract report whether -*anything* reached its memory, which is "a refused value reaches it in no part" as a contract -can observe it; and `WasmVMTest.SoftHostErrorCodesCrossUnchanged` walks all 18 soft -`HostFunctionError` codes, because the C++ and Rust error enums are two hand-maintained lists -of the same numbers that **have already drifted once** — -11 is `OutOfTransferLimit` in C++ and -`Decoding` in the Rust ABI; see "the two error enums have already drifted" in -[open-questions.md](open-questions.md). - -*Mutation-checked*: making a too-large value write a truncated prefix, and pointing the -sha512 input matcher at bytes the guest does not send, each fail exactly one test and nothing -else. - -**Naming.** Subject-first, no leading article — `ContractReturnValueReachesCaller`, not -`AContractsReturnValueReachesTheCaller`. That is the house style in `src/tests/libxrpl` -(`BuilderThrowsOnWrongEntryType`, `OptionalFieldsReturnNullopt`). - -## The old C++ suites, and why they are not the parity oracle yet - -`src/test/app/Wasm_test.cpp` and `HostFuncImpl_test.cpp` are **entirely inside `/* */`** and -compile to nothing, as is `src/libxrpl/tx/wasm/WasmiVM.cpp`. - -`Wasm_test.cpp` asserts exact gas numbers (e.g. 29'502), which makes it the best gas-parity -oracle available — but **its fixtures cannot run on this engine.** They import from module -`env`, not `host_lib` (`kLedgerSqnWasmHex` decodes to -`... 03 656e76 0a 6c6467725f696e646578 ...`), and their `target_features` include `sign-ext`, -`multivalue` and `reference-types`, which this engine disables. The deleted C++ engine ignored -the import module name entirely — `wasm_importtype_module` is commented out at its -`WasmiVM.cpp:428`. Reviving it as an oracle means recompiling those fixtures with -`-Wl,--import-module=host_lib` and the engine's feature set. The gtest carries its own -WAT-derived modules for that reason. diff --git a/include/xrpl/nodestore/detail/Varint.h b/include/xrpl/nodestore/detail/Varint.h new file mode 100644 index 0000000000..5474cdc8b4 --- /dev/null +++ b/include/xrpl/nodestore/detail/Varint.h @@ -0,0 +1,126 @@ +#pragma once + +#include + +#include +#include +#include + +namespace xrpl::node_store { + +// This is a variant of the base128 varint format from +// google protocol buffers: +// https://developers.google.com/protocol-buffers/docs/encoding#varints + +// field tag +struct Varint; + +// Metafunction to return largest +// possible size of T represented as varint. +// T must be unsigned +template > +struct VarintTraits; + +template +struct VarintTraits +{ + explicit VarintTraits() = default; + + static constexpr std::size_t kMax = ((8 * sizeof(T)) + 6) / 7; +}; + +// Returns: Number of bytes consumed or 0 on error, +// if the buffer was too small or t overflowed. +// +template +std::size_t +readVarint(void const* buf, std::size_t buflen, std::size_t& t) +{ + if (buflen == 0) + return 0; + t = 0; + auto const* p = reinterpret_cast(buf); + std::size_t n = 0; + while (p[n] & 0x80) + { + if (++n >= buflen) + return 0; + } + if (++n > buflen) + return 0; + // Special case for 0 + if (n == 1 && *p == 0) + { + t = 0; + return 1; + } + auto const used = n; + while (n > 0) + { + --n; + auto const d = p[n]; + auto const t0 = t; + t *= 127; + t += d & 0x7f; + if (t <= t0) + return 0; // overflow + } + return used; +} + +template +std::size_t +sizeVarint(T v) + requires(std::is_unsigned_v) +{ + std::size_t n = 0; + do + { + v /= 127; + ++n; + } while (v != 0); + return n; +} + +template +std::size_t +writeVarint(void* p0, std::size_t v) +{ + // NOLINTNEXTLINE(misc-const-correctness) + auto* p = reinterpret_cast(p0); + do + { + std::uint8_t d = v % 127; + v /= 127; + if (v != 0) + d |= 0x80; + *p++ = d; + } while (v != 0); + return p - reinterpret_cast(p0); +} + +// input stream + +template +void +read(nudb::detail::istream& is, std::size_t& u) + requires(std::is_same_v) +{ + auto p0 = is(1); + auto p1 = p0; + while (*p1++ & 0x80) + is(1); + readVarint(p0, p1 - p0, u); +} + +// output stream + +template +void +write(nudb::detail::ostream& os, std::size_t t) + requires(std::is_same_v) +{ + writeVarint(os.data(sizeVarint(t)), t); +} + +} // namespace xrpl::node_store diff --git a/include/xrpl/tx/wasm/HostFunc.h b/include/xrpl/tx/wasm/HostFunc.h index f318610488..3269acc7de 100644 --- a/include/xrpl/tx/wasm/HostFunc.h +++ b/include/xrpl/tx/wasm/HostFunc.h @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -12,9 +11,6 @@ #include #include -#include -#include -#include #include #include @@ -73,7 +69,6 @@ floatPowerImpl(Slice const& x, int32_t n, int32_t mode); class HostFunctions { protected: - RTOptRef rt_; beast::Journal j_; public: @@ -81,26 +76,6 @@ public: { } - void - setRT(WasmRuntimeWrapper& rt) - { - rt_ = rt; - } - - void - resetRT() - { - rt_ = std::nullopt; - } - - [[nodiscard]] WasmRuntimeWrapper& - getRT() const - { - if (!rt_) - Throw("Wasm runtime not set"); - return rt_->get(); - } - [[nodiscard]] beast::Journal getJournal() const { @@ -518,6 +493,4 @@ public: // LCOV_EXCL_STOP }; -using HFRef = std::reference_wrapper; - } // namespace xrpl diff --git a/include/xrpl/tx/wasm/README.md b/include/xrpl/tx/wasm/README.md index 04958b663a..a9dbc84c85 100644 --- a/include/xrpl/tx/wasm/README.md +++ b/include/xrpl/tx/wasm/README.md @@ -1,189 +1,42 @@ # WASM Module for Programmable Escrows -This module provides WebAssembly (WASM) execution capabilities for programmable -escrows on the XRP Ledger. When an escrow is finished, the WASM code runs to -determine whether the escrow conditions are met, enabling custom programmable -logic for escrow release conditions. - -For the full specification, see +WebAssembly execution for programmable escrows. When an escrow is finished, its contract +runs to decide whether the release conditions are met. Specification: [XLS-0102: WASM VM](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html). -## Architecture +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. -The module follows a layered architecture: +## What is in this directory -``` -┌─────────────────────────────────────────────────────────────┐ -│ WasmEngine (WasmVM.h) │ -│ runEscrowWasm(), preflightEscrowWasm() │ -│ Host function registration │ -├─────────────────────────────────────────────────────────────┤ -│ WasmiEngine (WasmiVM.h) │ -│ Low-level wasmi interpreter integration │ -├─────────────────────────────────────────────────────────────┤ -│ HostFuncWrapper │ HostFuncImpl │ -│ C-style WASM bridges │ C++ implementations │ -├─────────────────────────────────────────────────────────────┤ -│ HostFunc (Interface) │ -│ Abstract base class for host functions │ -└─────────────────────────────────────────────────────────────┘ -``` +- **`WasmVM.h`** — the entry points xrpld calls: `runEscrowWasm` (execute a contract, + returning a result and its gas cost, or a `WasmTER`) and `preflightEscrowWasm` (screen a + module with no host and no execution). Both own their TER maps. +- **`HostFunc.h`** — the `HostFunctions` interface: one virtual per host function, each + defaulting to `Unimplemented`, returning `std::expected`. +- **`HostFuncImpl.h`** — `WasmHostFunctionsImpl`, the implementation over an + `ApplyContext&`. Bodies are split across `HostFuncImpl*.cpp` by category. +- **`HostContext.h`** — the bridge's C++ half: an ABI-shaped, `noexcept` view of + `HostFunctions` that the engine calls back into. Nothing may unwind into Rust, so every + method routes through one `guarded()`. +- **`WasmCommon.h`** — the shared vocabulary: `HostFunctionError` (the codes a contract + sees), `Bytes`, `FieldLocator`, `WasmTER`, and `adjustWasmEndianess`, which is where the + boundary's byte order is decided. -### Key Components +## Host functions -- **`WasmVM.h` / `detail/WasmVM.cpp`** - High-level facade providing: - - `WasmEngine` singleton that wraps the underlying WASM interpreter - - `runEscrowWasm()` - Execute WASM code for escrow finish - - `preflightEscrowWasm()` - Validate WASM code during preflight - - `createWasmImport()` - Register all host functions +Grouped by what they reach: ledger information; transaction and ledger-object field access; +keylet construction; cryptography; float arithmetic; NFT queries; tracing. -- **`WasmiVM.h` / `detail/WasmiVM.cpp`** - Low-level integration with the - [wasmi](https://github.com/wasmi-labs/wasmi) WebAssembly interpreter: - - `WasmiEngine` - Manages WASM modules, instances, and execution - - Memory management and gas metering - - Function invocation and result handling +The wire names and per-call gas costs are declared in `crates/xrpl-host-functions` — +one `host_functions!` block that generates the ABI trait and the spec table. That +declaration is the single source of truth; `HostFunc.h` is the C++ side of it. -- **`HostFunc.h`** - Abstract `HostFunctions` base class defining the interface - for all callable host functions. Each method returns - `std::expected`. +## Entry point -- **`HostFuncImpl.h` / `detail/HostFuncImpl*.cpp`** - Concrete - `WasmHostFunctionsImpl` class that implements host functions with access to - `ApplyContext` for ledger state queries. Implementation split across files: - - `HostFuncImpl.cpp` - Core utilities (updateData, checkSignature, etc.) - - `HostFuncImplFloat.cpp` - Float/number arithmetic operations - - `HostFuncImplGetter.cpp` - Field access (transaction, ledger objects) - - `HostFuncImplKeylet.cpp` - Keylet construction functions - - `HostFuncImplLedgerHeader.cpp` - Ledger header info access - - `HostFuncImplNFT.cpp` - NFT-related queries - - `HostFuncImplTrace.cpp` - Debugging/tracing functions - -- **`HostFuncWrapper.h` / `detail/HostFuncWrapper.cpp`** - C-style wrapper - functions that bridge WASM calls to C++ `HostFunctions` methods. Each host - function has: - - A `_proto` type alias defining the function signature - - A `_wrap` function that extracts parameters and calls the implementation - -- **`ParamsHelper.h`** - Utilities for WASM parameter handling: - - `WASM_IMPORT_FUNC` / `WASM_IMPORT_FUNC2` macros for registration - - `wasmParams()` helper for building parameter vectors - - Type conversion between WASM and C++ types - -## Host Functions - -Host functions allow WASM code to interact with the XRP Ledger. They are -organized into categories: - -- **Ledger Information** - Access ledger sequence, timestamps, hashes, fees -- **Transaction & Ledger Object Access** - Read fields from the transaction - and ledger objects (including the current escrow object) -- **Keylet Construction** - Build keylets to look up various ledger object types -- **Cryptography** - Signature verification and hashing -- **Float Arithmetic** - Mathematical operations for amount calculations -- **NFT Operations** - Query NFT properties -- **Tracing/Debugging** - Log messages for debugging - -For the complete list of available host functions, their WASM names, and gas -costs, see the [XLS-0102 specification](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html) -or `detail/WasmVM.cpp` where they are registered via `WASM_IMPORT_FUNC2` macros. -For method signatures, see `HostFunc.h`. - -## Gas Model - -Each host function has an associated gas cost. The gas cost is specified when -registering the function in `detail/WasmVM.cpp`: - -```cpp -WASM_IMPORT_FUNC2(i, getLedgerSqn, "get_ledger_sqn", hfs, 60); -// ^^ gas cost -``` - -WASM execution is metered, and if the gas limit is exceeded, execution fails. - -## Entry Point - -The WASM module must export a function with the name defined by -`escrowFunctionName` (currently `"escrow_finish"`). This function: - -- Takes no parameters (or parameters passed via host function calls) -- Returns an `int32_t`: - - `1` (or positive): Escrow conditions are met, allow finish - - `0` (or negative): Escrow conditions are not met, reject finish - -## Adding a New Host Function - -To add a new host function, follow these steps: - -### 1. Add to HostFunc.h (Base Class) - -Add a virtual method declaration with a default implementation that returns an -error: - -```cpp -virtual std::expected -myNewFunction(ParamType1 param1, ParamType2 param2) -{ - return std::unexpected(HostFunctionError::INTERNAL); -} -``` - -### 2. Add to HostFuncImpl.h (Declaration) - -Add the method override declaration in `WasmHostFunctionsImpl`: - -```cpp -std::expected -myNewFunction(ParamType1 param1, ParamType2 param2) override; -``` - -### 3. Implement in detail/HostFuncImpl\*.cpp - -Add the implementation in the appropriate file: - -```cpp -std::expected -WasmHostFunctionsImpl::myNewFunction(ParamType1 param1, ParamType2 param2) -{ - // Implementation using ctx (ApplyContext) for ledger access - return result; -} -``` - -### 4. Add Wrapper to HostFuncWrapper.h - -Add the prototype and wrapper declaration: - -```cpp -using myNewFunction_proto = int32_t(uint8_t const*, int32_t, ...); -wasm_trap_t* -myNewFunction_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results); -``` - -### 5. Implement Wrapper in detail/HostFuncWrapper.cpp - -Implement the C-style wrapper that bridges WASM to C++: - -```cpp -wasm_trap_t* -myNewFunction_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results) -{ - // Extract parameters from params - // Call hfs->myNewFunction(...) - // Set results and return -} -``` - -### 6. Register in WasmVM.cpp - -Add the function registration in `setCommonHostFunctions()` or -`createWasmImport()`: - -```cpp -WASM_IMPORT_FUNC2(i, myNewFunction, "my_new_function", hfs, 100); -// ^^ WASM name ^^ gas cost -``` - -> [!IMPORTANT] -> New host functions MUST be amendment-gated in `WasmVM.cpp`. -> Wrap the registration in an amendment check to ensure the function is only -> available after the corresponding amendment is enabled on the network. +A module must export `escrow_finish` (`escrowFunctionName`) taking no parameters and +returning `int32_t`: positive means the conditions are met, zero or negative rejects the +finish. Everything the contract needs it asks for through a host call. diff --git a/include/xrpl/tx/wasm/WasmCommon.h b/include/xrpl/tx/wasm/WasmCommon.h index 3e55777b7c..d2bb44284c 100644 --- a/include/xrpl/tx/wasm/WasmCommon.h +++ b/include/xrpl/tx/wasm/WasmCommon.h @@ -7,10 +7,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -21,18 +19,6 @@ using Bytes = std::vector; using Hash = xrpl::uint256; using FloatPair = std::pair; -// Error signals that cross the wasm boundary as trap messages (the C API has no -// trap code). WasmiEngine::call maps them to TER: hfErrInternal -> tecINTERNAL, -// hfErrOutOfGas / wasmi's OutOfFuel -> tecOUT_OF_GAS, anything else -> -// tecFAILED_PROCESSING. -// -// Matched as substrings, not by equality: the C API returns the Rust Debug form -// of the error, e.g. `Error { kind: Message("HfInternal") }` or -// `Error { kind: TrapCode(OutOfFuel) }`. -std::string_view inline constexpr hfErrInternal = "HfInternal"; -std::string_view inline constexpr hfErrOutOfGas = "HfOutOfGas"; -std::string_view inline constexpr wasmiTrapOutOfFuel = "OutOfFuel"; - enum class HostFunctionError : int32_t { Unimplemented = -1, FieldNotFound = -2, @@ -56,19 +42,6 @@ enum class HostFunctionError : int32_t { FloatComputationError = -20, }; -enum class WasmTypes { WtI32, WtI64 }; - -struct Wmem -{ - std::uint8_t* p = nullptr; - std::size_t s = 0; - - Wmem() = default; - Wmem(void* ptr, std::size_t size) : p(reinterpret_cast(ptr)), s(size) - { - } -}; - template struct WasmResult { @@ -136,71 +109,6 @@ public: } }; -class WasmRuntimeWrapper -{ -public: - virtual ~WasmRuntimeWrapper() = default; - - virtual Wmem - getMem() = 0; - - virtual std::int64_t - getGas() = 0; - - virtual std::int64_t - setGas(std::int64_t gas) = 0; - - virtual std::int64_t - getTransferLimit() = 0; - - virtual std::int64_t - setTransferLimit(std::int64_t transferLimit) = 0; -}; -using RTOptRef = std::optional>; - -struct WasmParam -{ - // We are not supporting float/double - - WasmTypes type = WasmTypes::WtI32; - union - { - std::int32_t i32; - std::int64_t i64 = 0; - } of; -}; - -template -inline void -wasmParamsHlp(std::vector& v, std::int32_t p, Types&&... args) -{ - v.push_back({.type = WasmTypes::WtI32, .of = {.i32 = p}}); - wasmParamsHlp(v, std::forward(args)...); -} - -template -inline void -wasmParamsHlp(std::vector& v, std::int64_t p, Types&&... args) -{ - v.push_back({.type = WasmTypes::WtI64, .of = {.i64 = p}}); - wasmParamsHlp(v, std::forward(args)...); -} - -inline void -wasmParamsHlp(std::vector& v) -{ -} - -template -inline std::vector -wasmParams(Types&&... args) -{ - std::vector v; - v.reserve(sizeof...(args)); - wasmParamsHlp(v, std::forward(args)...); - return v; -} - template constexpr T adjustWasmEndianessHlp(T x) diff --git a/src/libxrpl/tx/wasm/HostFuncImplGetter.cpp b/src/libxrpl/tx/wasm/HostFuncImplGetter.cpp index 4ae0c72426..ce2de57a0b 100644 --- a/src/libxrpl/tx/wasm/HostFuncImplGetter.cpp +++ b/src/libxrpl/tx/wasm/HostFuncImplGetter.cpp @@ -124,9 +124,10 @@ getAnyFieldData(FieldValue const& variantObj) if (uint256 const* const* u = std::get_if(&variantObj)) return Bytes((*u)->begin(), (*u)->end()); - // Unreachable: the variant only holds the two alternatives above. If not, - // it's an xrpld bug -> tecINTERNAL (thrown, caught by HostFuncMain_wrap). - Throw(std::string(hfErrInternal)); // LCOV_EXCL_LINE + // Unreachable: the variant only holds the two alternatives above. If not, it is an + // xrpld bug, and `HostContext::guarded` turns the throw into the engine's fatal + // `Internal` -> tecINTERNAL. + Throw("field value variant holds neither alternative"); // LCOV_EXCL_LINE } static inline bool diff --git a/src/libxrpl/tx/wasm/WasmiVM.cpp b/src/libxrpl/tx/wasm/WasmiVM.cpp deleted file mode 100644 index b299506dd1..0000000000 --- a/src/libxrpl/tx/wasm/WasmiVM.cpp +++ /dev/null @@ -1,960 +0,0 @@ -/* -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _DEBUG -// #define DEBUG_OUTPUT 1 -#endif -// #define SHOW_CALL_TIME 1 - -namespace xrpl { - -wasm_trap_t* -HostFuncMain_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results); - -namespace { - -void -printWasmError(std::string_view msg, wasm_trap_t* trap, beast::Journal jlog) -{ -#ifdef DEBUG_OUTPUT - auto& j = std::cerr; -#else - auto j = jlog.warn(); - if (jlog.active(beast::Severity::Warning)) -#endif - { - wasm_byte_vec_t errorMessage WASM_EMPTY_VEC; - - if (trap != nullptr) - wasm_trap_message(trap, &errorMessage); - - if (errorMessage.size != 0u) - { - j << "WASMI Error: " << msg << ", " - << std::string_view(errorMessage.data, errorMessage.size - 1); - } - else - { - j << "WASMI Error: " << msg; - } - - if (errorMessage.size != 0u) - wasm_byte_vec_delete(&errorMessage); - } - - if (trap != nullptr) - wasm_trap_delete(trap); - -#ifdef DEBUG_OUTPUT - j << std::endl; -#endif -} -// LCOV_EXCL_STOP - -// Extract a trap's message into a std::string (the only signal the C API gives -// for classification; see the trap-signal constants in WasmCommon.h). Does not -// take ownership of `trap`. -std::string -trapMessage(wasm_trap_t* trap) -{ - if (trap == nullptr) - return {}; // LCOV_EXCL_LINE - wasm_byte_vec_t msg WASM_EMPTY_VEC; - wasm_trap_message(trap, &msg); - std::string out; - if (msg.size != 0u) - { - // wasm_trap_message NUL-terminates, so drop the trailing NUL. - out.assign(msg.data, msg.size - 1); - wasm_byte_vec_delete(&msg); - } - return out; -} - -} // namespace - -class WasmiRuntimeWrapper : public WasmRuntimeWrapper -{ - InstanceWrapper& iw_; - -public: - WasmiRuntimeWrapper(InstanceWrapper& iw) : iw_(iw) - { - } - - Wmem - getMem() override - { - return iw_.getMem(); - } - - std::int64_t - getGas() override - { - return iw_.getGas(); - } - - std::int64_t - setGas(std::int64_t gas) override - { - return iw_.setGas(gas); - } - - std::int64_t - getTransferLimit() override - { - return iw_.getTransferLimit(); - } - - std::int64_t - setTransferLimit(std::int64_t x) override - { - return iw_.setTransferLimit(x); - } -}; - -InstancePtr -InstanceWrapper::init( - StorePtr& s, - ModulePtr& m, - WasmExternVec& expt, - WasmExternVec const& imports, - beast::Journal j) -{ - wasm_trap_t* trap = nullptr; - InstancePtr mi = InstancePtr( - wasm_instance_new(s.get(), m.get(), imports.get(), &trap), &wasm_instance_delete); - - if (!mi || (trap != nullptr)) - { - printWasmError("can't create instance", trap, j); - Throw("can't create instance"); - } - wasm_instance_exports(mi.get(), expt.get()); - return mi; -} - -InstanceWrapper& -InstanceWrapper::operator=(InstanceWrapper&& o) -{ - if (this == &o) - return *this; // LCOV_EXCL_LINE - - store_ = o.store_; - o.store_ = nullptr; - exports_ = std::move(o.exports_); - memIdx_ = o.memIdx_; - o.memIdx_ = -1; - instance_ = std::move(o.instance_); - - j_ = o.j_; - - return *this; -} - -FuncInfo -InstanceWrapper::getFunc(std::string_view funcName, WasmExporttypeVec const& exportTypes) const -{ - wasm_func_t const* f = nullptr; - wasm_functype_t const* ft = nullptr; - - if (!instance_) - Throw("no instance"); // LCOV_EXCL_LINE - - if (exportTypes.empty()) - Throw("no export"); // LCOV_EXCL_LINE - if (exportTypes.size() != exports_.size()) - Throw("invalid export"); // LCOV_EXCL_LINE - - for (unsigned i = 0; i < exportTypes.size(); ++i) - { - auto const* expType(exportTypes[i]); - - wasm_name_t const* name = wasm_exporttype_name(expType); - wasm_externtype_t const* exnType = wasm_exporttype_type(expType); - if (wasm_externtype_kind(exnType) == WASM_EXTERN_FUNC) - { - if (funcName != std::string_view(name->data, name->size)) - continue; - - auto const* exn(exports_[i]); - if (wasm_extern_kind(exn) != WASM_EXTERN_FUNC) - Throw("invalid export"); // LCOV_EXCL_LINE - - ft = wasm_externtype_as_functype_const(exnType); - f = wasm_extern_as_func_const(exn); - break; - } - } - - if ((f == nullptr) || (ft == nullptr)) - Throw("can't find function <" + std::string(funcName) + ">"); - - return {f, ft}; -} - -Wmem -InstanceWrapper::getMem() const -{ - if (memIdx_ >= 0) - { - auto* e(exports_[memIdx_]); - wasm_memory_t* mem = wasm_extern_as_memory(e); - return Wmem(wasm_memory_data(mem), wasm_memory_data_size(mem)); - } - - wasm_memory_t* mem = nullptr; - for (int i = 0; i < exports_.size(); ++i) - { - auto* e(exports_[i]); - if (wasm_extern_kind(e) == WASM_EXTERN_MEMORY) - { - memIdx_ = i; - mem = wasm_extern_as_memory(e); - break; - } - } - - if (mem == nullptr) - return {}; // LCOV_EXCL_LINE - - return Wmem(wasm_memory_data(mem), wasm_memory_data_size(mem)); -} - -std::int64_t -InstanceWrapper::getGas() const -{ - if (store_ == nullptr) - return -1; // LCOV_EXCL_LINE - std::uint64_t gas = 0; - wasm_store_get_fuel(store_, &gas); - return static_cast(gas); -} - -std::int64_t -InstanceWrapper::setGas(std::int64_t gas) const -{ - if (store_ == nullptr) - return -1; // LCOV_EXCL_LINE - - if (gas < 0) - gas = std::numeric_limits::max(); - wasmi_error_t* err = wasm_store_set_fuel(store_, static_cast(gas)); - if (err != nullptr) - { - // LCOV_EXCL_START - printWasmError("Can't set instance gas", nullptr, j_); - wasmi_error_delete(err); - return -1; - // LCOV_EXCL_STOP - } - - return gas; -} - -std::int64_t -InstanceWrapper::getTransferLimit() const -{ - if (store_ == nullptr) - return -1; // LCOV_EXCL_LINE - - return transferLimit_; -} - -std::int64_t -InstanceWrapper::setTransferLimit(std::int64_t x) -{ - if (store_ == nullptr) - return -1; // LCOV_EXCL_LINE - if (x < 0) - { - transferLimit_ = std::numeric_limits::max(); - } - else - { - transferLimit_ = x; - } - - return transferLimit_; -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -ModulePtr -ModuleWrapper::init(StorePtr& s, Bytes const& wasmBin, beast::Journal j) -{ - wasm_byte_vec_t const code{ - .size = wasmBin.size(), - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) - .data = const_cast(reinterpret_cast(wasmBin.data()))}; - ModulePtr m = ModulePtr(wasm_module_new(s.get(), &code), &wasm_module_delete); - if (!m) - throw std::runtime_error("can't create module"); - - return m; -} - -ModuleWrapper::ModuleWrapper( - StorePtr& s, - Bytes const& wasmBin, - bool instantiate, - ImportVec const& imports, - beast::Journal j) - : module_(init(s, wasmBin, j)), j_(j) -{ - wasm_module_exports(module_.get(), exportTypes_.get()); - auto wimports = buildImports(s, imports); - if (instantiate) - { - addInstance(s, wimports); - } -} - -// LCOV_EXCL_START -ModuleWrapper& -ModuleWrapper::operator=(ModuleWrapper&& o) -{ - if (this == &o) - return *this; - - module_ = std::move(o.module_); - instanceWrap_ = std::move(o.instanceWrap_); - exportTypes_ = std::move(o.exportTypes_); - j_ = o.j_; - - return *this; -} - -// LCOV_EXCL_STOP - -static WasmValtypeVec -makeImpParams(WasmImportFunc const& imp) -{ - auto const paramSize = imp.params.size(); - if (paramSize == 0u) - return {}; - - WasmValtypeVec v(paramSize); - - for (unsigned i = 0; i < paramSize; ++i) - { - auto const vt = imp.params[i]; - switch (vt) - { - case WasmTypes::WtI32: - v[i] = wasm_valtype_new_i32(); - break; - case WasmTypes::WtI64: - v[i] = wasm_valtype_new_i64(); - break; - // LCOV_EXCL_START - default: - throw std::runtime_error("invalid import type"); - // LCOV_EXCL_STOP - } - } - return v; -} - -static WasmValtypeVec -makeImpReturn(WasmImportFunc const& imp) -{ - if (!imp.result) - return {}; // LCOV_EXCL_LINE - - WasmValtypeVec v(1); - switch (*imp.result) - { - case WasmTypes::WtI32: - v[0] = wasm_valtype_new_i32(); - break; - // LCOV_EXCL_START - case WasmTypes::WtI64: - v[0] = wasm_valtype_new_i64(); - break; - default: - throw std::runtime_error("invalid return type"); - // LCOV_EXCL_STOP - } - return v; -} - -WasmExternVec -ModuleWrapper::buildImports(StorePtr& s, ImportVec const& imports) const -{ - WasmImporttypeVec importTypes; - wasm_module_imports(module_.get(), importTypes.get()); - - if (importTypes.empty()) - return {}; - if (imports.empty()) - Throw("Empty imports"); - - WasmExternVec wimports(importTypes.size()); - - unsigned impCnt = 0; - for (unsigned i = 0; i < importTypes.size(); ++i) - { - wasm_importtype_t const* importType = importTypes[i]; - - // wasm_name_t const* mn = wasm_importtype_module(importtype); - // auto modName = std::string_view(mn->data, mn->num_elems); - wasm_name_t const* fn = wasm_importtype_name(importType); - auto fieldName = std::string_view(fn->data, fn->size); - - wasm_externkind_t const itype = wasm_externtype_kind(wasm_importtype_type(importType)); - if (itype != WASM_EXTERN_FUNC) - { - Throw( - "Invalid import type " + std::to_string(itype)); // LCOV_EXCL_LINE - } - - // for multi-module support - // if ((W_ENV != modName) && (W_HOST_LIB != modName)) - // continue; - - auto const it = imports.find(fieldName); - if (it == imports.end()) - { - printWasmError("Import not found: " + std::string(fieldName), nullptr, j_); - continue; // print all missed import - } - - WasmUserData const& obj = it->second; - WasmImportFunc const& imp = obj.second; - - WasmValtypeVec params(makeImpParams(imp)); - WasmValtypeVec results(makeImpReturn(imp)); - - std::unique_ptr const ftype( - wasm_functype_new(params.get(), results.get()), &wasm_functype_delete); - - params.release(); - results.release(); - - wasm_func_t* func = - wasm_func_new_with_env(s.get(), ftype.get(), HostFuncMain_wrap, (void*)&obj, nullptr); - if (func == nullptr) - { - Throw( - "can't create import function " + std::string(imp.name)); // LCOV_EXCL_LINE - } - - wimports[i] = wasm_func_as_extern(func); - ++impCnt; - } - - if (impCnt != importTypes.size()) - { - printWasmError( - std::string("Imports not finished: ") + std::to_string(impCnt) + "/" + - std::to_string(importTypes.size()), - nullptr, - j_); - Throw("Missing imports"); - } - - return wimports; -} - -wasm_functype_t const* -ModuleWrapper::getFuncType(std::string_view funcName) const -{ - for (size_t i = 0; i < exportTypes_.size(); i++) - { - auto const* expType(exportTypes_[i]); - wasm_name_t const* name = wasm_exporttype_name(expType); - wasm_externtype_t const* exnType = wasm_exporttype_type(expType); - if (wasm_externtype_kind(exnType) == WASM_EXTERN_FUNC && - funcName == std::string_view(name->data, name->size)) - { - return wasm_externtype_as_functype_const(exnType); - } - } - - throw std::runtime_error("can't find function <" + std::string(funcName) + ">"); -} - -// 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; -// } - -////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// void -// WasmiEngine::clearModules() -// { -// modules.clear(); -// store.reset(); // to free the memory before creating new store -// store = {wasm_store_new(engine.get()), &wasm_store_delete}; -// } - -std::unique_ptr -WasmiEngine::init() -{ - wasm_config_t* config = wasm_config_new(); - if (config == nullptr) - { - return std::unique_ptr{ - nullptr, &wasm_engine_delete}; // LCOV_EXCL_LINE - } - wasmi_config_consume_fuel_set(config, true); - wasmi_config_ignore_custom_sections_set(config, true); - wasmi_config_wasm_mutable_globals_set(config, false); - wasmi_config_wasm_multi_value_set(config, false); - wasmi_config_wasm_sign_extension_set(config, false); - wasmi_config_wasm_saturating_float_to_int_set(config, false); - wasmi_config_wasm_bulk_memory_set(config, false); - wasmi_config_wasm_reference_types_set(config, false); - wasmi_config_wasm_tail_call_set(config, false); - wasmi_config_wasm_extended_const_set(config, false); - wasmi_config_floats_set(config, false); - wasmi_config_wasm_multi_memory_set(config, false); - wasmi_config_wasm_custom_page_sizes_set(config, false); - wasmi_config_wasm_memory64_set(config, false); - wasmi_config_wasm_wide_arithmetic_set(config, false); - - return std::unique_ptr( - wasm_engine_new_with_config(config), &wasm_engine_delete); -} - -int -WasmiEngine::addModule( - Bytes const& wasmCode, - bool instantiate, - ImportVec const& imports, - int64_t gas) -{ - moduleWrap_.reset(); - store_.reset(); // to free the memory before creating new store - store_ = {wasm_store_new_with_memory_max_pages(engine_.get(), maxPages), &wasm_store_delete}; - - if (gas < 0) - gas = std::numeric_limits::max(); - wasmi_error_t* err = wasm_store_set_fuel(store_.get(), static_cast(gas)); - if (err != nullptr) - { - // LCOV_EXCL_START - printWasmError("Error setting gas", nullptr, j_); - wasmi_error_delete(err); - throw std::runtime_error("can't set gas"); - // LCOV_EXCL_STOP - } - - moduleWrap_ = std::make_unique(store_, wasmCode, instantiate, imports, j_); - - if (!moduleWrap_) - throw std::runtime_error("can't create module wrapper"); // LCOV_EXCL_LINE - - return moduleWrap_ ? 0 : -1; -} - -// int -// WasmiEngine::addInstance() -// { -// return module->addInstance(store.get()); -// } - -std::vector -WasmiEngine::convertParams(std::vector const& params) -{ - std::vector v; - v.reserve(params.size()); - for (auto const& p : params) - { - switch (p.type) - { - case WasmTypes::WtI32: - v.push_back(WASM_I32_VAL(p.of.i32)); - break; - // LCOV_EXCL_START - case WasmTypes::WtI64: - v.push_back(WASM_I64_VAL(p.of.i64)); - break; - default: - throw std::runtime_error( - "unknown parameter type: " + std::to_string(static_cast(p.type))); - break; - // LCOV_EXCL_STOP - } - } - - return v; -} - -int -WasmiEngine::compareParamTypes(wasm_valtype_vec_t const* ftp, std::vector const& p) -{ - if (ftp->size != p.size()) - return std::min(ftp->size, p.size()); - - for (unsigned i = 0; i < ftp->size; ++i) - { - auto const t1 = wasm_valtype_kind(ftp->data[i]); - auto const t2 = p[i].kind; - if (t1 != t2) - return i; - } - - return -1; -} - -// LCOV_EXCL_START -void -WasmiEngine::addParam(std::vector& in, int32_t p) -{ - in.emplace_back(); - auto& el(in.back()); - memset(&el, 0, sizeof(el)); - el = WASM_I32_VAL(p); // WASM_I32; -} - -// LCOV_EXCL_STOP - -void -WasmiEngine::addParam(std::vector& in, int64_t p) -{ - in.emplace_back(); - auto& el(in.back()); - el = WASM_I64_VAL(p); -} - -template -WasmiResult -WasmiEngine::call(std::string_view func, Types&&... args) -{ - // Lookup our export function - auto f = getFunc(func); - return call(f, std::forward(args)...); -} - -template -WasmiResult -WasmiEngine::call(FuncInfo const& f, Types&&... args) -{ - std::vector in; - return call(f, in, std::forward(args)...); -} - -#ifdef SHOW_CALL_TIME -static inline uint64_t -usecs() -{ - uint64_t x = std::chrono::duration_cast( - std::chrono::high_resolution_clock::now().time_since_epoch()) - .count(); - return x; -} -#endif - -template -WasmiResult -WasmiEngine::call(FuncInfo const& f, std::vector& in) -{ - WasmiResult ret(NR); - wasm_val_vec_t const inv = in.empty() ? wasm_val_vec_t WASM_EMPTY_VEC - : wasm_val_vec_t{.size = in.size(), .data = in.data()}; - -#ifdef SHOW_CALL_TIME - auto const start = usecs(); -#endif - - wasm_trap_t* trap = wasm_func_call(f.first, &inv, ret.r.get()); - -#ifdef SHOW_CALL_TIME - auto const finish = usecs(); - auto const delta_ms = (finish - start) / 1000; - std::cout << "wasm_func_call: " << delta_ms << "ms" << std::endl; -#endif - - if (trap) - { - // Classify the trap into a TER by matching tokens as substrings of the - // message (see the trap-signal constants in WasmCommon.h for why). - std::string const msg = trapMessage(trap); - auto const has = [&msg](std::string_view token) { return msg.contains(token); }; - if (has(hfErrInternal)) - { - ret.ter = tecINTERNAL; - } - else if (has(hfErrOutOfGas) || has(wasmiTrapOutOfFuel)) - { - ret.ter = tecOUT_OF_GAS; - } - else - { - ret.ter = tecFAILED_PROCESSING; - } - printWasmError("failure to call func", trap, j_); - } - - return ret; -} - -template -WasmiResult -WasmiEngine::call(FuncInfo const& f, std::vector& in, std::int32_t p, Types&&... args) -{ - addParam(in, p); - return call(f, in, std::forward(args)...); -} - -template -WasmiResult -WasmiEngine::call(FuncInfo const& f, std::vector& in, std::int64_t p, Types&&... args) -{ - addParam(in, p); - return call(f, in, std::forward(args)...); -} - -template -WasmiResult -WasmiEngine::call(FuncInfo const& f, std::vector& in, Bytes const& p, Types&&... args) -{ - return call(f, in, p.data(), p.size(), std::forward(args)...); -} - -static inline void -checkImports(ImportVec const& imports, HostFunctions* hfs) -{ - for (auto const& obj : imports) - { - if (hfs != &obj.second.first.get()) - Throw("Imports hf unsync"); - } -} - -std::expected, WasmTER> -WasmiEngine::run( - Bytes const& wasmCode, - HostFunctions& hfs, - int64_t gas, - std::string_view funcName, - std::vector const& params, - ImportVec const& imports, - beast::Journal j) -{ - if (gas <= 0) - return std::unexpected(WasmTER{.ter = temBAD_AMOUNT, .cost = std::nullopt}); - - try - { - checkImports(imports, &hfs); - return runHlp(wasmCode, hfs, gas, funcName, params, imports, j); - } - catch (std::exception const& e) - { - printWasmError(std::string("exception: ") + e.what(), nullptr, j); - } - // LCOV_EXCL_START - catch (...) - { - printWasmError(std::string("exception: unknown"), nullptr, j); - } - // LCOV_EXCL_STOP - // An exception escaping the engine is an xrpld-side fault -> tecINTERNAL, - // no gas. Genuine wasm faults don't throw; they surface as traps in runHlp. - return std::unexpected(WasmTER{.ter = tecINTERNAL, .cost = std::nullopt}); -} - -std::expected, WasmTER> -WasmiEngine::runHlp( - Bytes const& wasmCode, - HostFunctions& hfs, - int64_t gas, - std::string_view funcName, - std::vector const& params, - ImportVec const& imports, - beast::Journal j) -{ - // currently only 1 module support, possible parallel UT run - std::scoped_lock const lg(m_); - j_ = j; - - if (wasmCode.empty()) - throw std::runtime_error("empty module"); - if (!hfs.checkSelf()) - throw std::runtime_error("hfs isn't clean"); - - // Create and instantiate the module. - [[maybe_unused]] int const m = addModule(wasmCode, true, imports, gas); - - if (!moduleWrap_ || !moduleWrap_->getInstance()) - throw std::runtime_error("no instance"); // LCOV_EXCL_LINE - - auto clearRT = [](HostFunctions* p) { p->resetRT(); }; - std::unique_ptr const clearGuard(&hfs, clearRT); - WasmiRuntimeWrapper iw(getRT()); - hfs.setRT(iw); - - // Call main - auto const f = getFunc(!funcName.empty() ? funcName : "_start"); - auto const* ftp = wasm_functype_params(f.second); - - // not const because passed directly to VM function (which accept non - // const) - auto p = convertParams(params); - - if (int const comp = compareParamTypes(ftp, p); comp >= 0) - throw std::runtime_error("invalid parameter type #" + std::to_string(comp)); - - auto const res = call<1>(f, p); - - if (gas == -1) - gas = std::numeric_limits::max(); - - if (res.ter.has_value()) - { - // call() already classified the trap (see WasmiEngine::call). - // tecINTERNAL is an xrpld-side bug: report no gas. - if (*res.ter == tecINTERNAL) - return std::unexpected(WasmTER{.ter = tecINTERNAL, .cost = std::nullopt}); - - // Out-of-gas / wasm faults report gas (caller writes it to metadata). - // Force fuel to 0 on out-of-gas so cost is the full limit (wasmi leaves - // nonzero leftover fuel on its own out-of-fuel trap). - if (*res.ter == tecOUT_OF_GAS) - iw.setGas(0); - - return std::unexpected(WasmTER{.ter = *res.ter, .cost = gas - moduleWrap_->getGas()}); - } - - if (res.r.empty()) - { - Throw( - "<" + std::string(funcName) + "> return nothing"); // LCOV_EXCL_LINE - } - - if (res.r[0].kind != WASM_I32) - { - Throw( - "<" + std::string(funcName) + - "> return type mismatch, ret: " + std::to_string(static_cast(res.r[0].kind))); - } - - WasmResult const ret{.result = res.r[0].of.i32, .cost = gas - moduleWrap_->getGas()}; - - // #ifdef DEBUG_OUTPUT - // auto& j = std::cerr; - // #else - // auto j = j_.debug(); - // #endif - // j << "WASMI Res: " << ret.result << " cost: " << ret.cost << std::endl; - - return ret; -} - -NotTEC -WasmiEngine::check( - Bytes const& wasmCode, - HostFunctions& hfs, - std::string_view funcName, - std::vector const& params, - ImportVec const& imports, - beast::Journal j) -{ - try - { - checkImports(imports, &hfs); - return checkHlp(wasmCode, hfs, funcName, params, imports, j); - } - catch (std::exception const& e) - { - printWasmError(std::string("exception: ") + e.what(), nullptr, j); - } - // LCOV_EXCL_START - catch (...) - { - printWasmError(std::string("exception: unknown"), nullptr, j); - } - // LCOV_EXCL_STOP - - return temBAD_WASM; -} - -NotTEC -WasmiEngine::checkHlp( - Bytes const& wasmCode, - HostFunctions& hfs, - std::string_view funcName, - std::vector const& params, - ImportVec const& imports, - beast::Journal j) -{ - // currently only 1 module support, possible parallel UT run - std::scoped_lock const lg(m_); - j_ = j; - - // Create and instantiate the module. - if (wasmCode.empty()) - throw std::runtime_error("empty module"); - - int const m = addModule(wasmCode, false, imports, -1); - if ((m < 0) || !moduleWrap_) - throw std::runtime_error("no module"); // LCOV_EXCL_LINE - - // Looking for a func and compare parameter types - auto const f = moduleWrap_->getFuncType(!funcName.empty() ? funcName : "_start"); - auto const* ftp = wasm_functype_params(f); - auto const p = convertParams(params); - - if (int const comp = compareParamTypes(ftp, p); comp >= 0) - throw std::runtime_error("invalid parameter type #" + std::to_string(comp)); - - return tesSUCCESS; -} - -wasm_trap_t* -WasmiEngine::newTrap(std::string const& txt) -{ - static char empty[1] = {0}; - wasm_message_t msg = {.size = 1, .data = empty}; - - if (!txt.empty()) - wasm_name_new(&msg, txt.size() + 1, txt.c_str()); // include 0 - - wasm_trap_t* trap = wasm_trap_new(store_.get(), &msg); // NOLINT - - if (!txt.empty()) - wasm_byte_vec_delete(&msg); - - return trap; -} - -} // namespace xrpl -*/ diff --git a/src/test/app/TestHostFunctions.h b/src/test/app/TestHostFunctions.h deleted file mode 100644 index a3ded89f33..0000000000 --- a/src/test/app/TestHostFunctions.h +++ /dev/null @@ -1,538 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -namespace xrpl::test { - -class TestLedgerDataProvider : public HostFunctions -{ - jtx::Env& env_; - -public: - TestLedgerDataProvider(jtx::Env& env) : HostFunctions(env.journal), env_(env) - { - } - - [[nodiscard]] std::expected - getLedgerSqn() const override - { - return env_.current()->seq(); - } -}; - -class TestHostFunctions : public HostFunctions -{ -protected: - test::jtx::Env& env_; - AccountID accountID_; - Bytes data_; - -public: - TestHostFunctions(test::jtx::Env& env) : HostFunctions(env.journal), env_(env) - { - accountID_ = env.master.id(); - std::string t = "10000"; - data_ = Bytes{t.begin(), t.end()}; - } - - [[nodiscard]] std::expected - getLedgerSqn() const override - { - return 12345; - } - - [[nodiscard]] std::expected - getParentLedgerTime() const override - { - return 67890; - } - - [[nodiscard]] std::expected - getParentLedgerHash() const override - { - return env_.current()->header().parentHash; - } - - [[nodiscard]] std::expected - getBaseFee() const override - { - return 10; - } - - [[nodiscard]] std::expected - isAmendmentEnabled(uint256 const& amendmentId) const override - { - return 1; - } - - [[nodiscard]] std::expected - isAmendmentEnabled(std::string_view const& amendmentName) const override - { - return 1; - } - - std::expected - cacheLedgerObj(uint256 const& objId, int32_t cacheIdx) override - { - return 1; - } - - [[nodiscard]] std::expected - getTxField(SField const& fname) const override - { - if (fname == sfAccount) - return Bytes(accountID_.begin(), accountID_.end()); - - if (fname == sfFee) - { - int64_t x = 235; - auto const* p = reinterpret_cast(&x); - return Bytes{p, p + sizeof(x)}; - } - - if (fname == sfSequence) - { - auto const x = getLedgerSqn(); - if (!x) - return std::unexpected(x.error()); - std::uint32_t const data = x.value(); - auto const* b = reinterpret_cast(&data); - auto const* e = reinterpret_cast(&data + 1); - return Bytes{b, e}; - } - - return Bytes(); - } - - [[nodiscard]] std::expected - getCurrentLedgerObjField(SField const& fname) const override - { - auto const& sn = fname.getName(); - if (sn == "Destination" || sn == "Account") - return Bytes(accountID_.begin(), accountID_.end()); - if (sn == "Data") - return data_; - if (sn == "FinishAfter") - { - auto t = env_.current()->parentCloseTime().time_since_epoch().count(); - std::string s = std::to_string(t); - return Bytes{s.begin(), s.end()}; - } - - return std::unexpected(HostFunctionError::Unimplemented); - } - - [[nodiscard]] std::expected - getLedgerObjField(int32_t, SField const& fname) const override - { - if (fname == sfBalance) - { - int64_t x = 10'000; - auto const* p = reinterpret_cast(&x); - return Bytes{p, p + sizeof(x)}; - } - - if (fname == sfAccount) - return Bytes(accountID_.begin(), accountID_.end()); - - return data_; - } - - [[nodiscard]] std::expected - getTxNestedField(FieldLocator const& locator) const override - { - if (locator.size() == 1) - { - int32_t const* l = locator.data(); - int32_t const sfield = l[0]; - if (sfield == sfAccount.getCode()) - return Bytes(accountID_.begin(), accountID_.end()); - } - - uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2, - 0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92, - 0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00}; - return Bytes(&a[0], &a[sizeof(a)]); - } - - [[nodiscard]] std::expected - getCurrentLedgerObjNestedField(FieldLocator const& locator) const override - { - if (locator.size() == 1) - { - int32_t const* l = locator.data(); - int32_t const sfield = l[0]; - if (sfield == sfAccount.getCode()) - return Bytes(accountID_.begin(), accountID_.end()); - } - - uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2, - 0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92, - 0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00}; - return Bytes(&a[0], &a[sizeof(a)]); - } - - [[nodiscard]] std::expected - getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const override - { - if (locator.size() == 1) - { - int32_t const* l = locator.data(); - int32_t const sfield = l[0]; - if (sfield == sfAccount.getCode()) - return Bytes(accountID_.begin(), accountID_.end()); - } - - uint8_t const a[] = {0x2b, 0x6a, 0x23, 0x2a, 0xa4, 0xc4, 0xbe, 0x41, 0xbf, 0x49, 0xd2, - 0x45, 0x9f, 0xa4, 0xa0, 0x34, 0x7e, 0x1b, 0x54, 0x3a, 0x4c, 0x92, - 0xfc, 0xee, 0x08, 0x21, 0xc0, 0x20, 0x1e, 0x2e, 0x9a, 0x00}; - return Bytes(&a[0], &a[sizeof(a)]); - } - - [[nodiscard]] std::expected - getTxArrayLen(SField const& fname) const override - { - return 32; - } - - [[nodiscard]] std::expected - getCurrentLedgerObjArrayLen(SField const& fname) const override - { - return 32; - } - - [[nodiscard]] std::expected - getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const override - { - return 32; - } - - [[nodiscard]] std::expected - getTxNestedArrayLen(FieldLocator const& locator) const override - { - return 32; - } - - [[nodiscard]] std::expected - getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const override - { - return 32; - } - - [[nodiscard]] std::expected - getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const override - { - return 32; - } - - std::expected - updateData(Slice const& data) override - { - return data.size(); - } - - [[nodiscard]] std::expected - checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey) const override - { - return 1; - } - - [[nodiscard]] std::expected - computeSha512HalfHash(Slice const& data) const override - { - return env_.current()->header().parentHash; - } - - [[nodiscard]] std::expected - accountKeylet(AccountID const& account) const override - { - if (!account) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::account(account); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - ammKeylet(Asset const& issue1, Asset const& issue2) const override - { - if (issue1 == issue2) - return std::unexpected(HostFunctionError::InvalidParams); - if (issue1.holds() || issue2.holds()) - return std::unexpected(HostFunctionError::InvalidParams); - auto const keylet = keylet::amm(issue1, issue2); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - checkKeylet(AccountID const& account, std::uint32_t seq) const override - { - if (!account) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::check(account, seq); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType) - const override - { - if (!subject || !issuer || credentialType.empty() || - credentialType.size() > kMaxCredentialTypeLength) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::credential(subject, issuer, credentialType); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - escrowKeylet(AccountID const& account, std::uint32_t seq) const override - { - if (!account) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::escrow(account, seq); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - oracleKeylet(AccountID const& account, std::uint32_t documentId) const override - { - if (!account) - return std::unexpected(HostFunctionError::InvalidAccount); - auto const keylet = keylet::oracle(account, documentId); - return Bytes{keylet.key.begin(), keylet.key.end()}; - } - - [[nodiscard]] std::expected - getNFT(AccountID const& account, uint256 const& nftId) const override - { - if (!account || !nftId) - return std::unexpected(HostFunctionError::InvalidParams); - - std::string s = "https://ripple.com"; - return Bytes(s.begin(), s.end()); - } - - [[nodiscard]] std::expected - getNFTIssuer(uint256 const& nftId) const override - { - return Bytes(accountID_.begin(), accountID_.end()); - } - - [[nodiscard]] std::expected - getNFTTaxon(uint256 const& nftId) const override - { - return 4; - } - - [[nodiscard]] std::expected - getNFTFlags(uint256 const& nftId) const override - { - return 8; - } - - [[nodiscard]] std::expected - getNFTTransferFee(uint256 const& nftId) const override - { - return 10; - } - - [[nodiscard]] std::expected - getNFTSequence(uint256 const& nftId) const override - { - return 4; - } - - template - void - log(std::string_view const& msg, F&& dataFn) const - { -#ifdef DEBUG_OUTPUT - auto& j = std::cerr; -#else - if (!getJournal().active(beast::Severity::Trace)) - return; - auto j = getJournal().trace(); -#endif - j << "WasmTrace: " << msg << " " << dataFn(); - -#ifdef DEBUG_OUTPUT - j << std::endl; -#endif - } - - [[nodiscard]] std::expected - trace(std::string_view const& msg, Slice const& data, bool asHex) const override - { - if (!asHex) - { - log(msg, [&data] { - return std::string_view(reinterpret_cast(data.data()), data.size()); - }); - } - else - { - log(msg, [&data] { - std::string hex; - hex.reserve(data.size() * 2); - boost::algorithm::hex(data.begin(), data.end(), std::back_inserter(hex)); - return hex; - }); - } - - return 0; - } - - [[nodiscard]] std::expected - traceNum(std::string_view const& msg, int64_t data) const override - { - log(msg, [data] { return data; }); - return 0; - } - - [[nodiscard]] std::expected - traceAccount(std::string_view const& msg, AccountID const& account) const override - { - log(msg, [&account] { return toBase58(account); }); - return 0; - } - - [[nodiscard]] std::expected - traceFloat(std::string_view const& msg, Slice const& data) const override - { - log(msg, [&data] { return wasm_float::floatToString(data); }); - return 0; - } - - [[nodiscard]] std::expected - traceAmount(std::string_view const& msg, STAmount const& amount) const override - { - log(msg, [&amount] { return amount.getFullText(); }); - return 0; - } - - [[nodiscard]] std::expected - floatFromInt(int64_t x, int32_t mode) const override - { - return wasm_float::floatFromIntImpl(x, mode); - } - - [[nodiscard]] std::expected - floatFromUint(uint64_t x, int32_t mode) const override - { - return wasm_float::floatFromUintImpl(x, mode); - } - - [[nodiscard]] std::expected - floatFromSTAmount(STAmount const& x, int32_t mode) const override - { - return wasm_float::floatFromSTAmountImpl(x, mode); - } - - [[nodiscard]] std::expected - floatFromSTNumber(STNumber const& x, int32_t mode) const override - { - return wasm_float::floatFromSTNumberImpl(x, mode); - } - - [[nodiscard]] std::expected - floatToInt(Slice const& x, int32_t mode) const override - { - return wasm_float::floatToIntImpl(x, mode); - } - - [[nodiscard]] std::expected - floatToMantExp(Slice const& x) const override - { - return wasm_float::floatToMantExpImpl(x); - } - - [[nodiscard]] std::expected - floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const override - { - return wasm_float::floatFromMantExpImpl(mantissa, exponent, mode); - } - - [[nodiscard]] std::expected - floatCompare(Slice const& x, Slice const& y) const override - { - return wasm_float::floatCompareImpl(x, y); - } - - [[nodiscard]] std::expected - floatAdd(Slice const& x, Slice const& y, int32_t mode) const override - { - return wasm_float::floatAddImpl(x, y, mode); - } - - [[nodiscard]] std::expected - floatSubtract(Slice const& x, Slice const& y, int32_t mode) const override - { - return wasm_float::floatSubtractImpl(x, y, mode); - } - - [[nodiscard]] std::expected - floatMultiply(Slice const& x, Slice const& y, int32_t mode) const override - { - return wasm_float::floatMultiplyImpl(x, y, mode); - } - - [[nodiscard]] std::expected - floatDivide(Slice const& x, Slice const& y, int32_t mode) const override - { - return wasm_float::floatDivideImpl(x, y, mode); - } - - [[nodiscard]] std::expected - floatRoot(Slice const& x, int32_t n, int32_t mode) const override - { - return wasm_float::floatRootImpl(x, n, mode); - } - - [[nodiscard]] std::expected - floatPower(Slice const& x, int32_t n, int32_t mode) const override - { - return wasm_float::floatPowerImpl(x, n, mode); - } -}; - -class TestHostFunctionsSink : public TestHostFunctions -{ - test::StreamSink sink_; - -public: - explicit TestHostFunctionsSink(test::jtx::Env& env) - : TestHostFunctions(env), sink_(beast::Severity::Debug) - { - j_ = beast::Journal(sink_); - } - - test::StreamSink& - getSink() - { - return sink_; - } -}; - -} // namespace xrpl::test diff --git a/src/test/app/Wasm_test.cpp b/src/test/app/Wasm_test.cpp deleted file mode 100644 index d3a265ca14..0000000000 --- a/src/test/app/Wasm_test.cpp +++ /dev/null @@ -1,471 +0,0 @@ -/* -#include -#ifdef _DEBUG -// #define DEBUG_OUTPUT 1 -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include // IWYU pragma: keep -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include - -namespace xrpl::test { - -bool -testGetDataIncrement(); - -using Add_proto = int32_t(int32_t, int32_t); -static wasm_trap_t* -add(HostFunctions&, wasm_val_vec_t const* params, wasm_val_vec_t* results) -{ - int32_t const val1 = params->data[0].of.i32; - int32_t const val2 = params->data[1].of.i32; - // printf("Host function \"Add\": %d + %d\n", Val1, Val2); - results->data[0] = WASM_I32_VAL(val1 + val2); - return nullptr; -} - -std::vector -hexToBytes(std::string const& hex) -{ - auto const ws = boost::algorithm::unhex(hex); - return Bytes(ws.begin(), ws.end()); -} - -struct Wasm_test : public beast::unit_test::Suite -{ - void - checkResult( - std::expected, WasmTER> re, - int32_t expectedResult, - int64_t expectedCost, - std::source_location const location = std::source_location::current()) - { - auto const lineStr = " (" + std::to_string(location.line()) + ")"; - if (BEAST_EXPECTS(re.has_value(), transToken(re.error().ter) + lineStr)) - { - BEAST_EXPECTS(re->result == expectedResult, std::to_string(re->result) + lineStr); - BEAST_EXPECTS(re->cost == expectedCost, std::to_string(re->cost) + lineStr); - } - } - - void - testGetDataHelperFunctions() - { - testcase("getData helper functions"); - BEAST_EXPECT(testGetDataIncrement()); - } - - void - testWasmLib() - { - testcase("wasm lib test"); - // clang-format off - // The WASM module buffer. // - Bytes 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(); - - HostFunctions hfs; - ImportVec imports; - WasmImpFunc(imports, "func-add", add, hfs); - - auto re = vm.run(wasm, hfs, 10'000'000, "addTwo", wasmParams(1234, 5678), imports); - - // if (res) printf("invokeAdd get the result: %d\n", res.value()); - - checkResult(re, 6'912, 59); - } - - void - testBadWasm() - { - testcase("bad wasm test"); - - using namespace test::jtx; - - Env const env{*this}; - HostFunctions hfs(env.journal); - - { - auto wasm = hexToBytes("00000000"); - std::string const funcName("mock_escrow"); - - auto re = runEscrowWasm(wasm, hfs, 15, funcName, {}); - BEAST_EXPECT(!re); - } - - { - auto wasm = hexToBytes("00112233445566778899AA"); - std::string const funcName("mock_escrow"); - - auto const re = preflightEscrowWasm(wasm, hfs, funcName); - BEAST_EXPECT(!isTesSuccess(re)); - } - - { - // FinishFunction wrong function name - // pub fn bad() -> bool { - // unsafe { host_lib::getLedgerSqn() >= 5 } - // } - auto const badWasm = hexToBytes( - "0061736d010000000105016000017f02190108686f73745f6c69620c6765" - "744c656467657253716e00000302010005030100100611027f00418080c0" - "000b7f00418080c0000b072b04066d656d6f727902000362616400010a5f" - "5f646174615f656e6403000b5f5f686561705f6261736503010a09010700" - "100041044a0b004d0970726f64756365727302086c616e67756167650104" - "52757374000c70726f6365737365642d6279010572757374631d312e3835" - "2e31202834656231363132353020323032352d30332d31352900490f7461" - "726765745f6665617475726573042b0f6d757461626c652d676c6f62616c" - "732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a" - "6d756c746976616c7565"); - - auto const re = preflightEscrowWasm(badWasm, hfs, escrowFunctionName); - BEAST_EXPECT(!isTesSuccess(re)); - } - } - - void - testWasmLedgerSqn() - { - testcase("Wasm get ledger sequence"); - - auto ledgerSqnWasm = hexToBytes(kLedgerSqnWasmHex); - - using namespace test::jtx; - - Env env{*this}; - TestLedgerDataProvider hfs(env); - ImportVec imports; - WASM_IMPORT_FUNC2(imports, getLedgerSqn, "ldgr_index", hfs, 33); - auto& engine = WasmEngine::instance(); - - auto re = - engine.run(ledgerSqnWasm, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); - - checkResult(re, 0, 440); - - env.close(); - env.close(); - - // empty module, throwing exception - re = engine.run({}, hfs, 1'000'000, escrowFunctionName, {}, imports, env.journal); - BEAST_EXPECT(!re); - env.close(); - } - - void - testHFCost() - { - testcase("wasm test host functions cost"); - - using namespace test::jtx; - - Env env(*this); - { - auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); - - auto& engine = WasmEngine::instance(); - - TestHostFunctions hfs(env); - auto imp = createWasmImport(hfs); - for (auto& i : imp) - i.second.second.gas = 0; - - auto re = engine.run( - allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal); - - checkResult(re, 1, 27'617); - - env.close(); - } - - env.close(); - env.close(); - env.close(); - env.close(); - env.close(); - - { - auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); - - auto& engine = WasmEngine::instance(); - - TestHostFunctions hfs(env); - auto const imp = createWasmImport(hfs); - - auto re = engine.run( - allHostFuncWasm, hfs, 1'000'000, escrowFunctionName, {}, imp, env.journal); - - checkResult(re, 1, 70'877); - - env.close(); - } - - // not enough gas - { - auto const allHostFuncWasm = hexToBytes(kAllHostFunctionsWasmHex); - - auto& engine = WasmEngine::instance(); - - TestHostFunctions hfs(env); - auto const imp = createWasmImport(hfs); - - auto re = - engine.run(allHostFuncWasm, hfs, 200, escrowFunctionName, {}, imp, env.journal); - - if (BEAST_EXPECT(!re)) - { - // Running out of gas now terminates with tecOUT_OF_GAS (was - // previously collapsed into tecFAILED_PROCESSING). - BEAST_EXPECTS( - re.error().ter == tecOUT_OF_GAS, std::to_string(TERtoInt(re.error().ter))); - } - - env.close(); - } - } - - void - testEscrowWasmDN() - { - testcase("escrow wasm devnet test"); - - auto const allHFWasm = hexToBytes(kAllHostFunctionsWasmHex); - - using namespace test::jtx; - Env env{*this}; - { - TestHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {}); - checkResult(re, 1, 70'877); - } - - { - // Invalid gas limit (0) should be rejected (boundary condition) - TestHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, -1, escrowFunctionName, {}); - BEAST_EXPECT(!re.has_value()); - BEAST_EXPECT(re.error().ter == temBAD_AMOUNT); - } - - { - // Invalid gas limit (-1) should be rejected - TestHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 0, escrowFunctionName, {}); - BEAST_EXPECT(!re.has_value()); - BEAST_EXPECT(re.error().ter == temBAD_AMOUNT); - } - - { - // max() gas - TestHostFunctions hfs(env); - auto re = runEscrowWasm( - allHFWasm, hfs, std::numeric_limits::max(), escrowFunctionName, {}); - checkResult(re, 1, 70'877); - } - - { // fail because trying to access nonexistent field - struct FieldNotFoundHostFunctions : public TestHostFunctions - { - explicit FieldNotFoundHostFunctions(Env& env) : TestHostFunctions(env) - { - } - [[nodiscard]] std::expected - getTxField(SField const& fname) const override - { - return std::unexpected(HostFunctionError::FieldNotFound); - } - }; - - FieldNotFoundHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {}); - checkResult(re, -201, 29'502); - } - - { // fail because trying to allocate more than MAX_PAGES memory - struct OversizedFieldHostFunctions : public TestHostFunctions - { - explicit OversizedFieldHostFunctions(Env& env) : TestHostFunctions(env) - { - } - [[nodiscard]] std::expected - getTxField(SField const& fname) const override - { - return Bytes((128 + 1) * 64 * 1024, 1); - } - }; - - OversizedFieldHostFunctions hfs(env); - auto re = runEscrowWasm(allHFWasm, hfs, 100'000, escrowFunctionName, {}); - checkResult(re, -201, 29'502); - } - } - - void - testCodecovWasm() - { - testcase("Codecov wasm test"); - - using namespace test::jtx; - - Env env{*this}; - - auto const codecovWasm = hexToBytes(kCodecovTestsWasmHex); - TestHostFunctions hfs(env); - - auto const allowance = 204'624; - auto re = runEscrowWasm(codecovWasm, hfs, allowance, escrowFunctionName, {}); - - checkResult(re, 1, allowance); - } - - void - testBadAlign() - { - testcase("Wasm Bad Align"); - - // bad_align.c - auto const badAlignWasm = hexToBytes(kBadAlignWasmHex); - - using namespace test::jtx; - - Env env{*this}; - TestHostFunctions hfs(env); - auto imports = createWasmImport(hfs); - - { // Calls float_from_uint with bad alignment. - // Can be checked through codecov - auto& engine = WasmEngine::instance(); - - auto re = engine.run(badAlignWasm, hfs, 1'000'000, "test", {}, imports, env.journal); - if (BEAST_EXPECTS(re, transToken(re.error().ter))) - { - BEAST_EXPECTS(re->result == 0x47308594, std::to_string(re->result)); - } - } - - env.close(); - } - - void - testSwapBytes() - { - testcase("Wasm swap bytes"); - - uint64_t const swapDataU64 = 0x123456789abcdeffull; - uint64_t const reverseSwapDataU64 = 0xffdebc9a78563412ull; - int64_t const swapDataI64 = 0x123456789abcdeffll; - int64_t const reverseSwapDataI64 = 0xffdebc9a78563412ll; - - uint32_t const swapDataU32 = 0x12789aff; - uint32_t const reverseSwapDataU32 = 0xff9a7812; - int32_t const swapDataI32 = 0x12789aff; - int32_t const reverseSwapDataI32 = 0xff9a7812; - - uint16_t const swapDataU16 = 0x12ff; - uint16_t const reverseSwapDataU16 = 0xff12; - int16_t const swapDataI16 = 0x12ff; - int16_t const reverseSwapDataI16 = 0xff12; - - uint64_t b1 = swapDataU64; - int64_t b2 = swapDataI64; - b1 = adjustWasmEndianessHlp(b1); - b2 = adjustWasmEndianessHlp(b2); - BEAST_EXPECT(b1 == reverseSwapDataU64); - BEAST_EXPECT(b2 == reverseSwapDataI64); - b1 = adjustWasmEndianessHlp(b1); - b2 = adjustWasmEndianessHlp(b2); - BEAST_EXPECT(b1 == swapDataU64); - BEAST_EXPECT(b2 == swapDataI64); - - uint32_t b3 = swapDataU32; - int32_t b4 = swapDataI32; - b3 = adjustWasmEndianessHlp(b3); - b4 = adjustWasmEndianessHlp(b4); - BEAST_EXPECT(b3 == reverseSwapDataU32); - BEAST_EXPECT(b4 == reverseSwapDataI32); - b3 = adjustWasmEndianessHlp(b3); - b4 = adjustWasmEndianessHlp(b4); - BEAST_EXPECT(b3 == swapDataU32); - BEAST_EXPECT(b4 == swapDataI32); - - uint16_t b5 = swapDataU16; - int16_t b6 = swapDataI16; - b5 = adjustWasmEndianessHlp(b5); - b6 = adjustWasmEndianessHlp(b6); - BEAST_EXPECT(b5 == reverseSwapDataU16); - BEAST_EXPECT(b6 == reverseSwapDataI16); - b5 = adjustWasmEndianessHlp(b5); - b6 = adjustWasmEndianessHlp(b6); - BEAST_EXPECT(b5 == swapDataU16); - BEAST_EXPECT(b6 == swapDataI16); - } - - void - run() override - { - using namespace test::jtx; - - testGetDataHelperFunctions(); - testWasmLib(); - testBadWasm(); - testWasmLedgerSqn(); - - testHFCost(); - testEscrowWasmDN(); - - testCodecovWasm(); - - testBadAlign(); - testSwapBytes(); - } -}; - -BEAST_DEFINE_TESTSUITE(Wasm, app, xrpl); - -} // namespace xrpl::test -*/ diff --git a/src/test/app/wasm_fixtures/.gitignore b/src/test/app/wasm_fixtures/.gitignore deleted file mode 100644 index 08b2e8a256..0000000000 --- a/src/test/app/wasm_fixtures/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -**/target -**/debug -*.wasm diff --git a/src/test/app/wasm_fixtures/all_host_functions/Cargo.lock b/src/test/app/wasm_fixtures/all_host_functions/Cargo.lock deleted file mode 100644 index 48771d1506..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/Cargo.lock +++ /dev/null @@ -1,171 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "all_host_functions" -version = "0.1.0" -dependencies = [ - "xrpl-wasm-stdlib", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "typenum" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf" -dependencies = [ - "bs58", - "quote", - "sha2", - "syn", -] - -[[package]] -name = "xrpl-wasm-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf" -dependencies = [ - "xrpl-macros", -] diff --git a/src/test/app/wasm_fixtures/all_host_functions/Cargo.toml b/src/test/app/wasm_fixtures/all_host_functions/Cargo.toml deleted file mode 100644 index fb0c44562a..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "all_host_functions" -version = "0.1.0" -edition = "2024" - -# This empty workspace definition keeps this project independent of the parent workspace -[workspace] - -[lib] -crate-type = ["cdylib"] - -[dependencies] -xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" } - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" -opt-level = "z" -lto = true diff --git a/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs b/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs deleted file mode 100644 index a40aa91d6a..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs +++ /dev/null @@ -1,799 +0,0 @@ -#![cfg_attr(target_arch = "wasm32", no_std)] - -#[cfg(not(target_arch = "wasm32"))] -extern crate std; - -// -// Host Functions Test -// Tests 26 host functions (across 7 categories) -// -// With craft you can run this test with: -// craft test --project host_functions_test --test-case host_functions_test -// -// Amount Format Update: -// - XRP amounts now return as 8-byte serialized rippled objects -// - IOU and MPT amounts return in variable-length serialized format -// - Format details: https://xrpl.org/docs/references/protocol/binary-format#amount-fields -// -// Error Code Ranges: -// -100 to -199: Ledger Header Functions (3 functions) -// -200 to -299: Transaction Data Functions (5 functions) -// -300 to -399: Current Ledger Object Functions (4 functions) -// -400 to -499: Any Ledger Object Functions (5 functions) -// -500 to -599: Keylet Generation Functions (4 functions) -// -600 to -699: Utility Functions (4 functions) -// -700 to -799: Data Update Functions (1 function) -// - -use xrpl_std::core::current_tx::escrow_finish::EscrowFinish; -use xrpl_std::core::current_tx::traits::TransactionCommonFields; -use xrpl_std::host; -use xrpl_std::host::trace::{trace, trace_account_buf, trace_data, trace_num, DataRepr}; -use xrpl_std::sfield; - -#[unsafe(no_mangle)] -pub extern "C" fn escrow_finish() -> i32 { - let _ = trace("=== HOST FUNCTIONS TEST ==="); - let _ = trace("Testing 26 host functions"); - - // Category 1: Ledger Header Data Functions (3 functions) - // Error range: -100 to -199 - match test_ledger_header_functions() { - 0 => (), - err => return err, - } - - // Category 2: Transaction Data Functions (5 functions) - // Error range: -200 to -299 - match test_transaction_data_functions() { - 0 => (), - err => return err, - } - - // Category 3: Current Ledger Object Functions (4 functions) - // Error range: -300 to -399 - match test_current_ledger_object_functions() { - 0 => (), - err => return err, - } - - // Category 4: Any Ledger Object Functions (5 functions) - // Error range: -400 to -499 - match test_any_ledger_object_functions() { - 0 => (), - err => return err, - } - - // Category 5: Keylet Generation Functions (4 functions) - // Error range: -500 to -599 - match test_keylet_generation_functions() { - 0 => (), - err => return err, - } - - // Category 6: Utility Functions (4 functions) - // Error range: -600 to -699 - match test_utility_functions() { - 0 => (), - err => return err, - } - - // Category 7: Data Update Functions (1 function) - // Error range: -700 to -799 - match test_data_update_functions() { - 0 => (), - err => return err, - } - - let _ = trace("SUCCESS: All host function tests passed!"); - 1 // Success return code for WASM finish function -} - -/// Test Category 1: Ledger Header Data Functions (3 functions) -/// - get_ledger_sqn() - Get ledger sequence number -/// - get_parent_ledger_time() - Get parent ledger timestamp -/// - get_parent_ledger_hash() - Get parent ledger hash -fn test_ledger_header_functions() -> i32 { - let _ = trace("--- Category 1: Ledger Header Functions ---"); - - // Test 1.1: get_ledger_sqn() - should return current ledger sequence number - let mut sqn_buffer = [0u8; 4]; - let sqn_result = unsafe { host::ldgr_index(sqn_buffer.as_mut_ptr(), sqn_buffer.len()) }; - - if sqn_result <= 0 { - let _ = trace_num("ERROR: get_ledger_sqn failed:", sqn_result as i64); - return -101; // Ledger sequence number test failed - } - let ledger_sqn = u32::from_be_bytes(sqn_buffer); - let _ = trace_num("Ledger sequence number:", ledger_sqn as i64); - - // Test 1.2: get_parent_ledger_time() - should return parent ledger timestamp - let mut time_buffer = [0u8; 4]; - let time_result = - unsafe { host::parent_ldgr_time(time_buffer.as_mut_ptr(), time_buffer.len()) }; - - if time_result <= 0 { - let _ = trace_num("ERROR: get_parent_ledger_time failed:", time_result as i64); - return -102; // Parent ledger time test failed - } - let parent_ledger_time = u32::from_be_bytes(time_buffer); - let _ = trace_num("Parent ledger time:", parent_ledger_time as i64); - - // Test 1.3: get_parent_ledger_hash() - should return parent ledger hash (32 bytes) - let mut hash_buffer = [0u8; 32]; - let hash_result = - unsafe { host::parent_ldgr_hash(hash_buffer.as_mut_ptr(), hash_buffer.len()) }; - - if hash_result != 32 { - let _ = trace_num( - "ERROR: get_parent_ledger_hash wrong length:", - hash_result as i64, - ); - return -103; // Parent ledger hash test failed - should be exactly 32 bytes - } - let _ = trace_data("Parent ledger hash:", &hash_buffer, DataRepr::AsHex); - - let _ = trace("SUCCESS: Ledger header functions"); - 0 -} - -/// Test Category 2: Transaction Data Functions (5 functions) -/// Tests all functions for accessing current transaction data -fn test_transaction_data_functions() -> i32 { - let _ = trace("--- Category 2: Transaction Data Functions ---"); - - // Test 2.1: get_tx_field() - Basic transaction field access - // Test with Account field (required, 20 bytes) - let mut account_buffer = [0u8; 20]; - let account_len = unsafe { - host::tx_field( - sfield::Account.into(), - account_buffer.as_mut_ptr(), - account_buffer.len(), - ) - }; - - if account_len != 20 { - let _ = trace_num( - "ERROR: get_tx_field(Account) wrong length:", - account_len as i64, - ); - return -201; // Basic transaction field test failed - } - let _ = trace_account_buf("Transaction Account:", &account_buffer); - - // Test with Fee field (XRP amount - 8 bytes in new serialized format) - // New format: XRP amounts are always 8 bytes (positive: value | cPositive flag, negative: just value) - let mut fee_buffer = [0u8; 8]; - let fee_len = unsafe { - host::tx_field( - sfield::Fee.into(), - fee_buffer.as_mut_ptr(), - fee_buffer.len(), - ) - }; - - if fee_len != 8 { - let _ = trace_num( - "ERROR: get_tx_field(Fee) wrong length (expected 8 bytes for XRP):", - fee_len as i64, - ); - return -202; // Fee field test failed - XRP amounts should be exactly 8 bytes - } - let _ = trace_num("Transaction Fee length:", fee_len as i64); - let _ = trace_data( - "Transaction Fee (serialized XRP amount):", - &fee_buffer, - DataRepr::AsHex, - ); - - // Test with Sequence field (required, 4 bytes uint32) - let mut seq_buffer = [0u8; 4]; - let seq_len = unsafe { - host::tx_field( - sfield::Sequence.into(), - seq_buffer.as_mut_ptr(), - seq_buffer.len(), - ) - }; - - if seq_len != 4 { - let _ = trace_num( - "ERROR: get_tx_field(Sequence) wrong length:", - seq_len as i64, - ); - return -203; // Sequence field test failed - } - let _ = trace_data("Transaction Sequence:", &seq_buffer, DataRepr::AsHex); - - // NOTE: get_tx_field2() through get_tx_field6() have been deprecated. - // Use get_tx_field() with appropriate parameters for all transaction field access. - - // Test 2.2: get_tx_nested_field() - Nested field access with locator - let locator = [ - 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, - ]; // Two int32s in little-endian: [1, 0] - let mut nested_buffer = [0u8; 32]; - let nested_result = unsafe { - host::tx_inner( - locator.as_ptr(), - locator.len(), - nested_buffer.as_mut_ptr(), - nested_buffer.len(), - ) - }; - - if nested_result < 0 { - let _ = trace_num( - "INFO: get_tx_nested_field not applicable:", - nested_result as i64, - ); - // Expected - locator may not match transaction structure - } else { - let _ = trace_num("Nested field length:", nested_result as i64); - let _ = trace_data( - "Nested field:", - &nested_buffer[..nested_result as usize], - DataRepr::AsHex, - ); - } - - // Test 2.3: get_tx_array_len() - Get array length - let signers_len = unsafe { host::tx_arr_len(sfield::Signers.into()) }; - let _ = trace_num("Signers array length:", signers_len as i64); - - let memos_len = unsafe { host::tx_arr_len(sfield::Memos.into()) }; - let _ = trace_num("Memos array length:", memos_len as i64); - - // Test 2.4: get_tx_nested_array_len() - Get nested array length with locator - let nested_array_len = unsafe { host::tx_inner_arr_len(locator.as_ptr(), locator.len()) }; - - if nested_array_len < 0 { - let _ = trace_num( - "INFO: get_tx_nested_array_len not applicable:", - nested_array_len as i64, - ); - } else { - let _ = trace_num("Nested array length:", nested_array_len as i64); - } - - let _ = trace("SUCCESS: Transaction data functions"); - 0 -} - -/// Test Category 3: Current Ledger Object Functions (4 functions) -/// Tests functions that access the current ledger object being processed -fn test_current_ledger_object_functions() -> i32 { - let _ = trace("--- Category 3: Current Ledger Object Functions ---"); - - // Test 3.1: get_current_ledger_obj_field() - Access field from current ledger object - // Test with Balance field (XRP amount - 8 bytes in new serialized format) - let mut balance_buffer = [0u8; 8]; - let balance_result = unsafe { - host::home_le_field( - sfield::Balance.into(), - balance_buffer.as_mut_ptr(), - balance_buffer.len(), - ) - }; - - if balance_result <= 0 { - let _ = trace_num( - "INFO: get_current_ledger_obj_field(Balance) failed (may be expected):", - balance_result as i64, - ); - // This might fail if current ledger object doesn't have balance field - } else if balance_result == 8 { - let _ = trace_num( - "Current object balance length (XRP amount):", - balance_result as i64, - ); - let _ = trace_data( - "Current object balance (serialized XRP amount):", - &balance_buffer, - DataRepr::AsHex, - ); - } else { - let _ = trace_num( - "Current object balance length (non-XRP amount):", - balance_result as i64, - ); - let _ = trace_data( - "Current object balance:", - &balance_buffer[..balance_result as usize], - DataRepr::AsHex, - ); - } - - // Test with Account field - let mut current_account_buffer = [0u8; 20]; - let current_account_result = unsafe { - host::home_le_field( - sfield::Account.into(), - current_account_buffer.as_mut_ptr(), - current_account_buffer.len(), - ) - }; - - if current_account_result <= 0 { - let _ = trace_num( - "INFO: get_current_ledger_obj_field(Account) failed:", - current_account_result as i64, - ); - } else { - let _ = trace_account_buf("Current ledger object account:", ¤t_account_buffer); - } - - // Test 3.2: get_current_ledger_obj_nested_field() - Nested field access - let locator = [ - 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, - ]; // Two int32s in little-endian: [1, 0] - let mut current_nested_buffer = [0u8; 32]; - let current_nested_result = unsafe { - host::home_le_inner( - locator.as_ptr(), - locator.len(), - current_nested_buffer.as_mut_ptr(), - current_nested_buffer.len(), - ) - }; - - if current_nested_result < 0 { - let _ = trace_num( - "INFO: get_current_ledger_obj_nested_field not applicable:", - current_nested_result as i64, - ); - } else { - let _ = trace_num("Current nested field length:", current_nested_result as i64); - let _ = trace_data( - "Current nested field:", - ¤t_nested_buffer[..current_nested_result as usize], - DataRepr::AsHex, - ); - } - - // Test 3.3: get_current_ledger_obj_array_len() - Array length in current object - let current_array_len = unsafe { host::home_le_arr_len(sfield::Signers.into()) }; - let _ = trace_num( - "Current object Signers array length:", - current_array_len as i64, - ); - - // Test 3.4: get_current_ledger_obj_nested_array_len() - Nested array length - let current_nested_array_len = - unsafe { host::home_le_inner_arr_len(locator.as_ptr(), locator.len()) }; - - if current_nested_array_len < 0 { - let _ = trace_num( - "INFO: get_current_ledger_obj_nested_array_len not applicable:", - current_nested_array_len as i64, - ); - } else { - let _ = trace_num( - "Current nested array length:", - current_nested_array_len as i64, - ); - } - - let _ = trace("SUCCESS: Current ledger object functions"); - 0 -} - -/// Test Category 4: Any Ledger Object Functions (5 functions) -/// Tests functions that work with cached ledger objects -fn test_any_ledger_object_functions() -> i32 { - let _ = trace("--- Category 4: Any Ledger Object Functions ---"); - - // First we need to cache a ledger object to test the other functions - // Get the account from transaction and generate its keylet - let escrow_finish = EscrowFinish; - let account_id = escrow_finish.get_account().unwrap(); - - // Test 4.1: cache_ledger_obj() - Cache a ledger object - let mut keylet_buffer = [0u8; 32]; - let keylet_result = unsafe { - host::accountroot_id( - account_id.0.as_ptr(), - account_id.0.len(), - keylet_buffer.as_mut_ptr(), - keylet_buffer.len(), - ) - }; - - if keylet_result != 32 { - let _ = trace_num( - "ERROR: accountroot_id failed for caching test:", - keylet_result as i64, - ); - return -401; // Keylet generation failed for caching test - } - - let cache_result = unsafe { host::cache_le(keylet_buffer.as_ptr(), keylet_result as usize, 0) }; - - if cache_result <= 0 { - let _ = trace_num( - "INFO: cache_ledger_obj failed (expected with test fixtures):", - cache_result as i64, - ); - // Test fixtures may not contain the account object - this is expected - // We'll test the interface but expect failures - - // Test 4.2-4.5 with invalid slot (should fail gracefully) - let mut test_buffer = [0u8; 32]; - - // Test get_ledger_obj_field with invalid slot - let field_result = unsafe { - host::le_field( - 1, - sfield::Balance.into(), - test_buffer.as_mut_ptr(), - test_buffer.len(), - ) - }; - if field_result < 0 { - let _ = trace_num( - "INFO: get_ledger_obj_field failed as expected (no cached object):", - field_result as i64, - ); - } - - // Test get_ledger_obj_nested_field with invalid slot - let locator = [ - 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, - ]; // Two int32s in little-endian: [1, 0] - let nested_result = unsafe { - host::le_inner( - 1, - locator.as_ptr(), - locator.len(), - test_buffer.as_mut_ptr(), - test_buffer.len(), - ) - }; - if nested_result < 0 { - let _ = trace_num( - "INFO: get_ledger_obj_nested_field failed as expected:", - nested_result as i64, - ); - } - - // Test get_ledger_obj_array_len with invalid slot - let array_result = unsafe { host::le_arr_len(1, sfield::Signers.into()) }; - if array_result < 0 { - let _ = trace_num( - "INFO: get_ledger_obj_array_len failed as expected:", - array_result as i64, - ); - } - - // Test get_ledger_obj_nested_array_len with invalid slot - let nested_array_result = - unsafe { host::le_inner_arr_len(1, locator.as_ptr(), locator.len()) }; - if nested_array_result < 0 { - let _ = trace_num( - "INFO: get_ledger_obj_nested_array_len failed as expected:", - nested_array_result as i64, - ); - } - - let _ = trace("SUCCESS: Any ledger object functions (interface tested)"); - return 0; - } - - // If we successfully cached an object, test the access functions - let slot = cache_result; - let _ = trace_num("Successfully cached object in slot:", slot as i64); - - // Test 4.2: get_ledger_obj_field() - Access field from cached object - let mut cached_balance_buffer = [0u8; 8]; - let cached_balance_result = unsafe { - host::le_field( - slot, - sfield::Balance.into(), - cached_balance_buffer.as_mut_ptr(), - cached_balance_buffer.len(), - ) - }; - - if cached_balance_result <= 0 { - let _ = trace_num( - "INFO: get_ledger_obj_field(Balance) failed:", - cached_balance_result as i64, - ); - } else if cached_balance_result == 8 { - let _ = trace_num( - "Cached object balance length (XRP amount):", - cached_balance_result as i64, - ); - let _ = trace_data( - "Cached object balance (serialized XRP amount):", - &cached_balance_buffer, - DataRepr::AsHex, - ); - } else { - let _ = trace_num( - "Cached object balance length (non-XRP amount):", - cached_balance_result as i64, - ); - let _ = trace_data( - "Cached object balance:", - &cached_balance_buffer[..cached_balance_result as usize], - DataRepr::AsHex, - ); - } - - // Test 4.3: get_ledger_obj_nested_field() - Nested field from cached object - let locator = [ - 0x01_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, 0x00_u8, - ]; // Two int32s in little-endian: [1, 0] - let mut cached_nested_buffer = [0u8; 32]; - let cached_nested_result = unsafe { - host::le_inner( - slot, - locator.as_ptr(), - locator.len(), - cached_nested_buffer.as_mut_ptr(), - cached_nested_buffer.len(), - ) - }; - - if cached_nested_result < 0 { - let _ = trace_num( - "INFO: get_ledger_obj_nested_field not applicable:", - cached_nested_result as i64, - ); - } else { - let _ = trace_num("Cached nested field length:", cached_nested_result as i64); - let _ = trace_data( - "Cached nested field:", - &cached_nested_buffer[..cached_nested_result as usize], - DataRepr::AsHex, - ); - } - - // Test 4.4: get_ledger_obj_array_len() - Array length from cached object - let cached_array_len = unsafe { host::le_arr_len(slot, sfield::Signers.into()) }; - let _ = trace_num( - "Cached object Signers array length:", - cached_array_len as i64, - ); - - // Test 4.5: get_ledger_obj_nested_array_len() - Nested array length from cached object - let cached_nested_array_len = - unsafe { host::le_inner_arr_len(slot, locator.as_ptr(), locator.len()) }; - - if cached_nested_array_len < 0 { - let _ = trace_num( - "INFO: get_ledger_obj_nested_array_len not applicable:", - cached_nested_array_len as i64, - ); - } else { - let _ = trace_num( - "Cached nested array length:", - cached_nested_array_len as i64, - ); - } - - let _ = trace("SUCCESS: Any ledger object functions"); - 0 -} - -/// Test Category 5: Keylet Generation Functions (4 functions) -/// Tests keylet generation functions for different ledger entry types -fn test_keylet_generation_functions() -> i32 { - let _ = trace("--- Category 5: Keylet Generation Functions ---"); - - let escrow_finish = EscrowFinish; - let account_id = escrow_finish.get_account().unwrap(); - - // Test 5.1: accountroot_id() - Generate keylet for account - let mut accountroot_id_buffer = [0u8; 32]; - let accountroot_id_result = unsafe { - host::accountroot_id( - account_id.0.as_ptr(), - account_id.0.len(), - accountroot_id_buffer.as_mut_ptr(), - accountroot_id_buffer.len(), - ) - }; - - if accountroot_id_result != 32 { - let _ = trace_num( - "ERROR: accountroot_id failed:", - accountroot_id_result as i64, - ); - return -501; // Account keylet generation failed - } - let _ = trace_data("Account keylet:", &accountroot_id_buffer, DataRepr::AsHex); - - // Test 5.2: credential_keylet() - Generate keylet for credential - let mut credential_keylet_buffer = [0u8; 32]; - let credential_keylet_result = unsafe { - host::credential_id( - account_id.0.as_ptr(), // Subject - account_id.0.len(), - account_id.0.as_ptr(), // Issuer - same account for test - account_id.0.len(), - b"TestType".as_ptr(), // Credential type - 9usize, // Length of "TestType" - credential_keylet_buffer.as_mut_ptr(), - credential_keylet_buffer.len(), - ) - }; - - if credential_keylet_result <= 0 { - let _ = trace_num( - "INFO: credential_keylet failed (expected - interface issue):", - credential_keylet_result as i64, - ); - // This is expected to fail due to unusual parameter types - } else { - let _ = trace_data( - "Credential keylet:", - &credential_keylet_buffer[..credential_keylet_result as usize], - DataRepr::AsHex, - ); - } - - // Test 5.3: escrow_keylet() - Generate keylet for escrow - let mut escrow_keylet_buffer = [0u8; 32]; - let sequence_number: i32 = 1000; - let sequence_number_bytes = sequence_number.to_be_bytes(); - let escrow_keylet_result = unsafe { - host::escrow_id( - account_id.0.as_ptr(), - account_id.0.len(), - sequence_number_bytes.as_ptr(), - sequence_number_bytes.len(), - escrow_keylet_buffer.as_mut_ptr(), - escrow_keylet_buffer.len(), - ) - }; - - if escrow_keylet_result != 32 { - let _ = trace_num("ERROR: escrow_keylet failed:", escrow_keylet_result as i64); - return -503; // Escrow keylet generation failed - } - let _ = trace_data("Escrow keylet:", &escrow_keylet_buffer, DataRepr::AsHex); - - // Test 5.4: oracle_keylet() - Generate keylet for oracle - let mut oracle_keylet_buffer = [0u8; 32]; - let document_id: i32 = 42; - let document_id_bytes = document_id.to_be_bytes(); - let oracle_keylet_result = unsafe { - host::oracle_id( - account_id.0.as_ptr(), - account_id.0.len(), - document_id_bytes.as_ptr(), - document_id_bytes.len(), - oracle_keylet_buffer.as_mut_ptr(), - oracle_keylet_buffer.len(), - ) - }; - - if oracle_keylet_result != 32 { - let _ = trace_num("ERROR: oracle_keylet failed:", oracle_keylet_result as i64); - return -504; // Oracle keylet generation failed - } - let _ = trace_data("Oracle keylet:", &oracle_keylet_buffer, DataRepr::AsHex); - - let _ = trace("SUCCESS: Keylet generation functions"); - 0 -} - -/// Test Category 6: Utility Functions (4 functions) -/// Tests utility functions for hashing, NFT access, and tracing -fn test_utility_functions() -> i32 { - let _ = trace("--- Category 6: Utility Functions ---"); - - // Test 6.1: compute_sha512_half() - SHA512 hash computation (first 32 bytes) - let test_data = b"Hello, XRPL WASM world!"; - let mut hash_output = [0u8; 32]; - let hash_result = unsafe { - host::sha512_half( - test_data.as_ptr(), - test_data.len(), - hash_output.as_mut_ptr(), - hash_output.len(), - ) - }; - - if hash_result != 32 { - let _ = trace_num("ERROR: compute_sha512_half failed:", hash_result as i64); - return -601; // SHA512 half computation failed - } - let _ = trace_data("Input data:", test_data, DataRepr::AsHex); - let _ = trace_data("SHA512 half hash:", &hash_output, DataRepr::AsHex); - - // Test 6.2: get_nft() - NFT data retrieval - let escrow_finish = EscrowFinish; - let account_id = escrow_finish.get_account().unwrap(); - let nft_id = [0u8; 32]; // Dummy NFT ID for testing - let mut nft_buffer = [0u8; 256]; - let nft_result = unsafe { - host::nft_uri( - account_id.0.as_ptr(), - account_id.0.len(), - nft_id.as_ptr(), - nft_id.len(), - nft_buffer.as_mut_ptr(), - nft_buffer.len(), - ) - }; - - if nft_result <= 0 { - let _ = trace_num( - "INFO: get_nft failed (expected - no such NFT):", - nft_result as i64, - ); - // This is expected - test account likely doesn't own the dummy NFT - } else { - let _ = trace_num("NFT data length:", nft_result as i64); - let _ = trace_data( - "NFT data:", - &nft_buffer[..nft_result as usize], - DataRepr::AsHex, - ); - } - - // Test 6.3: trace() - Debug logging with data - let trace_message = b"Test trace message"; - let trace_data_payload = b"payload"; - let trace_result = unsafe { - host::trace( - trace_message.as_ptr(), - trace_message.len(), - trace_data_payload.as_ptr(), - trace_data_payload.len(), - 1, // as_hex = true - ) - }; - - if trace_result < 0 { - let _ = trace_num("ERROR: trace() failed:", trace_result as i64); - return -603; // Trace function failed - } - let _ = trace_num("Trace function bytes written:", trace_result as i64); - - // Test 6.4: trace_num() - Debug logging with number - let test_number = 42i64; - let trace_num_result = trace_num("Test number trace", test_number); - - use xrpl_std::host::Result; - match trace_num_result { - Result::Ok(_) => { - let _ = trace_num("Trace_num function succeeded", 0); - } - Result::Err(_) => { - let _ = trace_num("ERROR: trace_num() failed:", -604); - return -604; // Trace number function failed - } - } - - let _ = trace("SUCCESS: Utility functions"); - 0 -} - -/// Test Category 7: Data Update Functions (1 function) -/// Tests the function for modifying the current ledger entry -fn test_data_update_functions() -> i32 { - let _ = trace("--- Category 7: Data Update Functions ---"); - - // Test 7.1: update_data() - Update current ledger entry data - let update_payload = b"Updated ledger entry data from WASM test"; - - let update_result = unsafe { host::set_data(update_payload.as_ptr(), update_payload.len()) }; - - if update_result != update_payload.len() as i32 { - let _ = trace_num("ERROR: update_data failed:", update_result as i64); - return -701; // Data update failed - } - - let _ = trace_data( - "Successfully updated ledger entry with:", - update_payload, - DataRepr::AsHex, - ); - let _ = trace("SUCCESS: Data update functions"); - 0 -} diff --git a/src/test/app/wasm_fixtures/all_keylets/Cargo.lock b/src/test/app/wasm_fixtures/all_keylets/Cargo.lock deleted file mode 100644 index 5da5b26f66..0000000000 --- a/src/test/app/wasm_fixtures/all_keylets/Cargo.lock +++ /dev/null @@ -1,171 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "all_keylets" -version = "0.0.1" -dependencies = [ - "xrpl-wasm-stdlib", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "typenum" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e" -dependencies = [ - "bs58", - "quote", - "sha2", - "syn", -] - -[[package]] -name = "xrpl-wasm-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#21c522f34a24b460297ebb6be1822680459bf37e" -dependencies = [ - "xrpl-macros", -] diff --git a/src/test/app/wasm_fixtures/all_keylets/Cargo.toml b/src/test/app/wasm_fixtures/all_keylets/Cargo.toml deleted file mode 100644 index ad53fd62b1..0000000000 --- a/src/test/app/wasm_fixtures/all_keylets/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -edition = "2024" -name = "all_keylets" -version = "0.0.1" - -# This empty workspace definition keeps this project independent of the parent workspace -[workspace] - -[lib] -crate-type = ["cdylib"] - -[profile.release] -lto = true -opt-level = 's' -panic = "abort" - -[dependencies] -xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" } - -[profile.dev] -panic = "abort" diff --git a/src/test/app/wasm_fixtures/all_keylets/src/lib.rs b/src/test/app/wasm_fixtures/all_keylets/src/lib.rs deleted file mode 100644 index f0a4e5abb5..0000000000 --- a/src/test/app/wasm_fixtures/all_keylets/src/lib.rs +++ /dev/null @@ -1,176 +0,0 @@ -#![cfg_attr(target_arch = "wasm32", no_std)] - -#[cfg(not(target_arch = "wasm32"))] -extern crate std; - -use crate::host::{Error, Result, Result::Err, Result::Ok}; -use xrpl_std::core::keylets; -use xrpl_std::core::ledger_objects::current_escrow::get_current_escrow; -use xrpl_std::core::ledger_objects::current_escrow::CurrentEscrow; -use xrpl_std::core::ledger_objects::ledger_object; -use xrpl_std::core::ledger_objects::traits::CurrentEscrowFields; -use xrpl_std::core::ledger_objects::LedgerObjectFieldGetter; -use xrpl_std::core::types::currency::Currency; -use xrpl_std::core::types::issue::{IouIssue, Issue, XrpIssue}; -use xrpl_std::core::types::mpt_id::MptId; -use xrpl_std::host; -use xrpl_std::host::trace::{trace, trace_acct, trace_data, trace_num, DataRepr}; -use xrpl_std::sfield; - -pub fn object_exists( - keylet_result: Result, - keylet_type: &str, - sfield: sfield::SField, -) -> Result { - let field = CODE; - match keylet_result { - Ok(keylet) => { - let _ = trace_data(keylet_type, &keylet, DataRepr::AsHex); - - let slot = unsafe { host::cache_le(keylet.as_ptr(), keylet.len(), 0) }; - if slot <= 0 { - let _ = trace_num("Error: ", slot.into()); - return Err(Error::from_code(slot)); - } - if field == 0 { - let new_field = sfield::PreviousTxnID; - let _ = trace_num("Getting field: ", new_field.clone().into()); - match ledger_object::get_field(slot, new_field) { - Ok(data) => { - let _ = trace_data("Field data: ", &data.0, DataRepr::AsHex); - } - Err(result_code) => { - let _ = trace_num("Error getting field: ", result_code.into()); - return Err(result_code); - } - } - } else { - let _ = trace_num("Getting field: ", field.into()); - match ledger_object::get_field(slot, sfield) { - Ok(_data) => { - let _ = trace("Field data: retrieved"); - } - Err(result_code) => { - let _ = trace_num("Error getting field: ", result_code.into()); - return Err(result_code); - } - } - } - - Ok(true) - } - Err(error) => { - let _ = trace_num("Error getting keylet: ", error.into()); - Err(error) - } - } -} - -#[unsafe(no_mangle)] -pub extern "C" fn escrow_finish() -> i32 { - let _ = trace("$$$$$ STARTING WASM EXECUTION $$$$$"); - - let escrow: CurrentEscrow = get_current_escrow(); - - let account = escrow.get_account().unwrap_or_panic(); - let _ = trace_acct("Account:", &account); - - let destination = escrow.get_destination().unwrap_or_panic(); - let _ = trace_acct("Destination:", &destination); - - let mut seq = 5; - - macro_rules! check_object_exists { - ($keylet:expr, $type:expr, $field:expr) => { - match object_exists($keylet, $type, $field) { - Ok(_exists) => { - // false isn't returned - let _ = trace(concat!( - $type, - " object exists, proceeding with escrow finish." - )); - } - Err(error) => { - let _ = trace_num("Current seq value:", seq.try_into().unwrap()); - return error.code(); - } - } - }; - } - - let accountroot_id = keylets::accountroot_id(&account); - check_object_exists!(accountroot_id, "Account", sfield::Account); - - let currency_code: &[u8; 3] = b"USD"; - let currency: Currency = Currency::from(*currency_code); - let trustline_id = keylets::trustline_id(&account, &destination, ¤cy); - check_object_exists!(trustline_id, "Trustline", sfield::Generic); - seq += 1; - - let asset1 = Issue::XRP(XrpIssue {}); - let asset2 = Issue::IOU(IouIssue::new(destination, currency)); - check_object_exists!(keylets::amm_id(&asset1, &asset2), "AMM", sfield::Account); - - let check_id = keylets::check_id(&account, seq); - check_object_exists!(check_id, "Check", sfield::Account); - seq += 1; - - let cred_type: &[u8] = b"termsandconditions"; - let credential_id = keylets::credential_id(&account, &account, cred_type); - check_object_exists!(credential_id, "Credential", sfield::Subject); - seq += 1; - - let delegate_id = keylets::delegate_id(&account, &destination); - check_object_exists!(delegate_id, "Delegate", sfield::Account); - seq += 1; - - let deposit_preauth_id = keylets::deposit_preauth_id(&account, &destination); - check_object_exists!(deposit_preauth_id, "DepositPreauth", sfield::Account); - seq += 1; - - let did_id = keylets::did_id(&account); - check_object_exists!(did_id, "DID", sfield::Account); - seq += 1; - - let escrow_id = keylets::escrow_id(&account, seq); - check_object_exists!(escrow_id, "Escrow", sfield::Account); - seq += 1; - - let mpt_issuance_id = keylets::mpt_issuance_id(&account, seq); - let mpt_id = MptId::new(seq.try_into().unwrap(), account); - check_object_exists!(mpt_issuance_id, "MPTIssuance", sfield::Issuer); - seq += 1; - - let mptoken_id = keylets::mptoken_id(&mpt_id, &destination); - check_object_exists!(mptoken_id, "MPToken", sfield::Account); - - let nft_offer_id = keylets::nft_offer_id(&destination, 6); - check_object_exists!(nft_offer_id, "NFTokenOffer", sfield::Owner); - - let offer_id = keylets::offer_id(&account, seq); - check_object_exists!(offer_id, "Offer", sfield::Account); - seq += 1; - - let paychan_id = keylets::paychan_id(&account, &destination, seq); - check_object_exists!(paychan_id, "PayChannel", sfield::Account); - seq += 1; - - let pd_id = keylets::permissioned_domain_id(&account, seq); - check_object_exists!(pd_id, "PermissionedDomain", sfield::Owner); - seq += 1; - - let signers_id = keylets::signers_id(&account); - check_object_exists!(signers_id, "SignerList", sfield::Generic); - seq += 1; - - seq += 1; // ticket sequence number is one greater - let ticket_id = keylets::ticket_id(&account, seq); - check_object_exists!(ticket_id, "Ticket", sfield::Account); - seq += 1; - - let vault_id = keylets::vault_id(&account, seq); - check_object_exists!(vault_id, "Vault", sfield::Account); - // seq += 1; - - 1 // All keylets exist, finish the escrow. -} diff --git a/src/test/app/wasm_fixtures/bad_align.c b/src/test/app/wasm_fixtures/bad_align.c deleted file mode 100644 index 560245e762..0000000000 --- a/src/test/app/wasm_fixtures/bad_align.c +++ /dev/null @@ -1,42 +0,0 @@ -#include - -int32_t float_from_uint(uint8_t const *, int32_t, uint8_t *, int32_t, int32_t); -int32_t check_id(uint8_t const *, int32_t, uint8_t const *, int32_t, uint8_t *, - int32_t); - -uint8_t e_data1[32 * 1024]; -uint8_t e_data2[32 * 1024]; - -int32_t test1() -{ - e_data1[1] = 0xFF; - e_data1[2] = 0xFF; - e_data1[3] = 0xFF; - e_data1[4] = 0xFF; - e_data1[5] = 0xFF; - e_data1[6] = 0xFF; - e_data1[7] = 0xFF; - e_data1[8] = 0xFF; - int32_t result = float_from_uint(&e_data1[1], 8, &e_data1[35], 12, 0); - return result >= 0 ? *((int32_t *)(&e_data1[36])) : result; -} - -int32_t test2() -{ - // Set up misaligned uint32 (seq) at offset 1 - e_data2[1] = 0xFF; - e_data2[2] = 0xFF; - e_data2[3] = 0xFF; - e_data2[4] = 0xFF; - // Set up valid non-zero AccountID (20 bytes) at offset 10 - for (int i = 0; i < 20; i++) - e_data2[10 + i] = i + 1; - // Call check_id with misaligned uint32 at &e_data2[1] to hit line 72 in - // HostFuncWrapper.cpp - int32_t result = check_id(&e_data2[10], 20, &e_data2[1], 4, &e_data2[35], 32); - // Return the misaligned value directly to validate it was read correctly (-1 - // if all 0xFF) - return result >= 0 ? *((int32_t *)(&e_data2[36])) : result; -} - -int32_t test() { return test1() + test2(); } diff --git a/src/test/app/wasm_fixtures/codecov_tests/Cargo.lock b/src/test/app/wasm_fixtures/codecov_tests/Cargo.lock deleted file mode 100644 index d7d91db071..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/Cargo.lock +++ /dev/null @@ -1,171 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "codecov_tests" -version = "0.0.1" -dependencies = [ - "xrpl-wasm-stdlib", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "typenum" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf" -dependencies = [ - "bs58", - "quote", - "sha2", - "syn", -] - -[[package]] -name = "xrpl-wasm-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=renames#9822d645870908a79d87a57b0244caa6359cb9cf" -dependencies = [ - "xrpl-macros", -] diff --git a/src/test/app/wasm_fixtures/codecov_tests/Cargo.toml b/src/test/app/wasm_fixtures/codecov_tests/Cargo.toml deleted file mode 100644 index 1cc49ac490..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -edition = "2024" -name = "codecov_tests" -version = "0.0.1" - -# This empty workspace definition keeps this project independent of the parent workspace -[workspace] - -[lib] -crate-type = ["cdylib"] - -[profile.release] -lto = true -opt-level = 's' -panic = "abort" - -[dependencies] -xrpl-std = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-wasm-stdlib", branch = "renames" } diff --git a/src/test/app/wasm_fixtures/codecov_tests/src/host_bindings_loose.rs b/src/test/app/wasm_fixtures/codecov_tests/src/host_bindings_loose.rs deleted file mode 100644 index 6204dff0a2..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/src/host_bindings_loose.rs +++ /dev/null @@ -1,47 +0,0 @@ -//TODO add docs after discussing the interface -//Note that Craft currently does not honor the rounding modes -#[allow(unused)] -pub const FLOAT_ROUNDING_MODES_TO_NEAREST: i32 = 0; -#[allow(unused)] -pub const FLOAT_ROUNDING_MODES_TOWARDS_ZERO: i32 = 1; -#[allow(unused)] -pub const FLOAT_ROUNDING_MODES_DOWNWARD: i32 = 2; -#[allow(unused)] -pub const FLOAT_ROUNDING_MODES_UPWARD: i32 = 3; - -// pub enum RippledRoundingModes{ -// ToNearest = 0, -// TowardsZero = 1, -// DOWNWARD = 2, -// UPWARD = 3 -// } - -#[allow(unused)] -#[link(wasm_import_module = "host_lib")] -unsafe extern "C" { - pub fn parent_ldgr_hash(out_buff_ptr: i32, out_buff_len: i32) -> i32; - - pub fn cache_le(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32; - - pub fn tx_inner_arr_len(locator_ptr: i32, locator_len: i32) -> i32; - - pub fn accountroot_id( - account_ptr: i32, - account_len: i32, - out_buff_ptr: *mut u8, - out_buff_len: usize, - ) -> i32; - - pub fn trustline_id( - account1_ptr: *const u8, - account1_len: usize, - account2_ptr: *const u8, - account2_len: usize, - currency_ptr: i32, - currency_len: i32, - out_buff_ptr: *mut u8, - out_buff_len: usize, - ) -> i32; - - pub fn trace_num(msg_read_ptr: i32, msg_read_len: i32, number: i64) -> i32; -} diff --git a/src/test/app/wasm_fixtures/codecov_tests/src/lib.rs b/src/test/app/wasm_fixtures/codecov_tests/src/lib.rs deleted file mode 100644 index 59f16155d2..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/src/lib.rs +++ /dev/null @@ -1,1782 +0,0 @@ -#![cfg_attr(target_arch = "wasm32", no_std)] - -#[cfg(not(target_arch = "wasm32"))] -extern crate std; - -use core::panic; -use xrpl_std::core::current_tx::escrow_finish::{get_current_escrow_finish, EscrowFinish}; -use xrpl_std::core::current_tx::traits::TransactionCommonFields; -use xrpl_std::core::keylets; -use xrpl_std::core::locator::Locator; -use xrpl_std::core::types::blob::DEFAULT_BLOB_SIZE; -use xrpl_std::core::types::issue::Issue; -use xrpl_std::core::types::issue::XrpIssue; -use xrpl_std::core::types::mpt_id::MptId; -use xrpl_std::host; -use xrpl_std::host::error_codes; -use xrpl_std::host::trace::{trace, trace_num as trace_number}; -use xrpl_std::sfield; -use xrpl_std::types::XRPL_CONTRACT_DATA_SIZE; - -mod host_bindings_loose; -include!("host_bindings_loose.rs"); - -fn check_result(result: i32, expected: i32, test_name: &'static str) { - match result { - code if code == expected => { - let _ = trace_number(test_name, code.into()); - } - code if code >= 0 => { - let _ = trace(test_name); - let _ = trace_number("TEST FAILED", code.into()); - panic!("Unexpected success code: {}", code); - } - code => { - let _ = trace(test_name); - let _ = trace_number("TEST FAILED", code.into()); - panic!("Error code: {}", code); - } - } -} - -fn with_buffer(mut f: F) -> R -where - F: FnMut(*mut u8, usize) -> R, -{ - let mut buf = [0u8; N]; - f(buf.as_mut_ptr(), buf.len()) -} - -#[unsafe(no_mangle)] -pub extern "C" fn escrow_finish() -> i32 { - let _ = trace("$$$$$ STARTING WASM EXECUTION $$$$$"); - - // ######################################## - // Step #1: Test all host function happy paths - // Note: not testing all the keylet functions, - // that's in a separate test file (all_keylets). - // The float tests are also in a separate file (float_tests). - // ######################################## - with_buffer::<4, _, _>(|ptr, len| { - check_result(unsafe { host::ldgr_index(ptr, len) }, 4, "ldgr_index"); - }); - with_buffer::<4, _, _>(|ptr, len| { - check_result( - unsafe { host::parent_ldgr_time(ptr, len) }, - 4, - "parent_ldgr_time", - ); - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { host::parent_ldgr_hash(ptr, len) }, - 32, - "parent_ldgr_hash", - ); - }); - with_buffer::<4, _, _>(|ptr, len| { - check_result(unsafe { host::base_fee(ptr, len) }, 4, "base_fee"); - }); - let amendment_name: &[u8] = b"test_amendment"; - let amendment_id: [u8; 32] = [1; 32]; - check_result( - unsafe { host::amendment_enabled(amendment_name.as_ptr(), amendment_name.len()) }, - 1, - "amendment_enabled", - ); - check_result( - unsafe { host::amendment_enabled(amendment_id.as_ptr(), amendment_id.len()) }, - 1, - "amendment_enabled", - ); - let tx: EscrowFinish = get_current_escrow_finish(); - let account = tx.get_account().unwrap_or_panic(); // get_tx_field under the hood - let keylet = keylets::accountroot_id(&account).unwrap_or_panic(); // accountroot_id under the hood - check_result( - unsafe { host::cache_le(keylet.as_ptr(), keylet.len(), 0) }, - 1, - "cache_le", - ); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::home_le_field(sfield::Account.into(), ptr, len) }, - 20, - "home_le_field", - ); - }); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::le_field(1, sfield::Account.into(), ptr, len) }, - 20, - "le_field", - ); - }); - let mut locator = Locator::new(); - locator.pack(sfield::Account); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::tx_inner(locator.as_ptr(), locator.len(), ptr, len) }, - 20, - "tx_inner", - ); - }); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::home_le_inner(locator.as_ptr(), locator.len(), ptr, len) }, - 20, - "home_le_inner", - ); - }); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::le_inner(1, locator.as_ptr(), locator.len(), ptr, len) }, - 20, - "le_inner", - ); - }); - check_result( - unsafe { host::tx_arr_len(sfield::Memos.into()) }, - 32, - "tx_arr_len", - ); - check_result( - unsafe { host::home_le_arr_len(sfield::Memos.into()) }, - 32, - "home_le_arr_len", - ); - check_result( - unsafe { host::le_arr_len(1, sfield::Memos.into()) }, - 32, - "le_arr_len", - ); - check_result( - unsafe { host::tx_inner_arr_len(locator.as_ptr(), locator.len()) }, - 32, - "tx_inner_arr_len", - ); - check_result( - unsafe { host::home_le_inner_arr_len(locator.as_ptr(), locator.len()) }, - 32, - "home_le_inner_arr_len", - ); - check_result( - unsafe { host::le_inner_arr_len(1, locator.as_ptr(), locator.len()) }, - 32, - "le_inner_arr_len", - ); - check_result( - unsafe { host::set_data(account.0.as_ptr(), account.0.len()) }, - 20, - "set_data", - ); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { host::sha512_half(locator.as_ptr(), locator.len(), ptr, len) }, - 32, - "sha512_half", - ); - }); - let message: &[u8] = b"test message"; - let pubkey: &[u8] = b"test pubkey"; //tx.get_public_key().unwrap_or_panic(); - let signature: &[u8] = b"test signature"; - check_result( - unsafe { - host::check_sig( - message.as_ptr(), - message.len(), - pubkey.as_ptr(), - pubkey.len(), - signature.as_ptr(), - signature.len(), - ) - }, - 1, - "check_sig", - ); - - let nft_id: [u8; 32] = amendment_id; - with_buffer::<18, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_uri( - account.0.as_ptr(), - account.0.len(), - nft_id.as_ptr(), - nft_id.len(), - ptr, - len, - ) - }, - 18, - "nft_uri", - ) - }); - with_buffer::<20, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_issuer(nft_id.as_ptr(), nft_id.len(), ptr, len) }, - 20, - "nft_issuer", - ) - }); - with_buffer::<4, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_taxon(nft_id.as_ptr(), nft_id.len(), ptr, len) }, - 4, - "nft_taxon", - ) - }); - check_result( - unsafe { host::nft_flags(nft_id.as_ptr(), nft_id.len()) }, - 8, - "nft_flags", - ); - check_result( - unsafe { host::nft_xfer_fee(nft_id.as_ptr(), nft_id.len()) }, - 10, - "nft_xfer_fee", - ); - with_buffer::<4, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_serial(nft_id.as_ptr(), nft_id.len(), ptr, len) }, - 4, - "nft_serial", - ) - }); - let message = "testing trace"; - check_result( - unsafe { - host::trace_acct( - message.as_ptr(), - message.len(), - account.0.as_ptr(), - account.0.len(), - ) - }, - 0, - "trace_acct", - ); - let amount = &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F]; // 95 drops of XRP - check_result( - unsafe { - host::trace_amt( - message.as_ptr(), - message.len(), - amount.as_ptr(), - amount.len(), - ) - }, - 0, - "trace_amt", - ); - let amount = &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; // 0 drops of XRP - check_result( - unsafe { - host::trace_amt( - message.as_ptr(), - message.len(), - amount.as_ptr(), - amount.len(), - ) - }, - 0, - "trace_amt_zero", - ); - - // ######################################## - // Step #2: Test set_data edge cases - // ######################################## - check_result( - unsafe { host_bindings_loose::parent_ldgr_hash(-1, 4) }, - error_codes::INVALID_PARAMS, - "parent_ldgr_hash_neg_ptr", - ); - with_buffer::<4, _, _>(|ptr, _len| { - check_result( - unsafe { host_bindings_loose::parent_ldgr_hash(ptr as i32, -1) }, - error_codes::INVALID_PARAMS, - "parent_ldgr_hash_neg_len", - ) - }); - with_buffer::<3, _, _>(|ptr, len| { - check_result( - unsafe { host_bindings_loose::parent_ldgr_hash(ptr as i32, len as i32) }, - error_codes::BUFFER_TOO_SMALL, - "parent_ldgr_hash_buf_too_small", - ) - }); - with_buffer::<4, _, _>(|ptr, _len| { - check_result( - unsafe { host_bindings_loose::parent_ldgr_hash(ptr as i32, 1_000_000_000) }, - error_codes::POINTER_OUT_OF_BOUNDS, - "parent_ldgr_hash_len_too_long", - ) - }); - - // ######################################## - // Step #3: Test getData[Type] edge cases - // ######################################## - - // SField - check_result( - unsafe { host::tx_arr_len(2) }, // not a valid SField value - error_codes::INVALID_FIELD, - "tx_arr_len_invalid_sfield", - ); - - // Slice - check_result( - unsafe { host_bindings_loose::tx_inner_arr_len(-1, locator.len() as i32) }, - error_codes::INVALID_PARAMS, - "tx_inner_arr_len_neg_ptr", - ); - check_result( - unsafe { host_bindings_loose::tx_inner_arr_len(locator.as_ptr() as i32, -1) }, - error_codes::INVALID_PARAMS, - "tx_inner_arr_len_neg_len", - ); - let long_len = DEFAULT_BLOB_SIZE + 1; - check_result( - unsafe { host_bindings_loose::tx_inner_arr_len(locator.as_ptr() as i32, long_len as i32) }, - error_codes::DATA_FIELD_TOO_LARGE, - "tx_inner_arr_len_too_long", - ); - check_result( - unsafe { - host_bindings_loose::tx_inner_arr_len( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "tx_inner_arr_len_ptr_oob", - ); - - // uint32 - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::check_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr().wrapping_add(1_000_000_000), - 8, - ptr, - len, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "check_id_oob_len_u32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::check_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "check_id_wrong_len_u32", - ) - }); - - // uint64 - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_from_uint( - locator.as_ptr().wrapping_add(1_000_000_000), - 8, - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_from_uint_len_oob", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_from_uint( - locator.as_ptr(), - locator.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::INVALID_PARAMS, - "float_from_uint_wrong_len_uint64", - ) - }); - - // uint256 - check_result( - unsafe { - host_bindings_loose::cache_le( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - 1, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "cache_le_ptr_oob", - ); - check_result( - unsafe { host_bindings_loose::cache_le(locator.as_ptr() as i32, locator.len() as i32, 1) }, - error_codes::INVALID_PARAMS, - "cache_le_wrong_len", - ); - - // AccountID - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host_bindings_loose::accountroot_id( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - ptr, - len, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "accountroot_id_len_oob", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host_bindings_loose::accountroot_id( - locator.as_ptr() as i32, - locator.len() as i32, - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "accountroot_id_wrong_len", - ) - }); - - // Currency - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host_bindings_loose::trustline_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - ptr, - len, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trustline_id_len_oob_currency", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host_bindings_loose::trustline_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - locator.as_ptr() as i32, - locator.len() as i32, - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "trustline_id_wrong_len_currency", - ) - }); - - // Issue - let asset1_bytes = Issue::XRP(XrpIssue {}).as_bytes(); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - asset1_bytes.as_ptr(), - asset1_bytes.len(), - locator.as_ptr().wrapping_add(1_000_000_000), - locator.len(), - ptr, - len, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "amm_id_len_oob_asset2", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - asset1_bytes.as_ptr(), - asset1_bytes.len(), - locator.as_ptr(), - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "amm_id_len_wrong_len_asset2", - ) - }); - let currency: &[u8] = b"USD00000000000000000"; // 20 bytes - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - asset1_bytes.as_ptr(), - asset1_bytes.len(), - currency.as_ptr(), - currency.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "amm_id_len_wrong_non_xrp_currency_len", - ) - }); - let xrp_issue: &[u8] = &[0; 40]; // 40 bytes - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - xrp_issue.as_ptr(), - xrp_issue.len(), - asset1_bytes.as_ptr(), - asset1_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "amm_id_len_wrong_xrp_currency_len", - ) - }); - let mptid = MptId::new(1, account); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - mptid.as_ptr(), - mptid.len(), - asset1_bytes.as_ptr(), - asset1_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "amm_id_mpt", - ) - }); - - // string - check_result( - unsafe { - host_bindings_loose::trace_num( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - 42, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trace_num_oob_str", - ); - - // ######################################## - // Step #4: Test other host function edge cases - // ######################################## - - // invalid SFields - - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::tx_field(2, ptr, len) }, - error_codes::INVALID_FIELD, - "tx_field_invalid_sfield", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::home_le_field(2, ptr, len) }, - error_codes::INVALID_FIELD, - "home_le_field_invalid_sfield", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::le_field(1, 2, ptr, len) }, - error_codes::INVALID_FIELD, - "le_field_invalid_sfield", - ); - }); - check_result( - unsafe { host::tx_arr_len(2) }, - error_codes::INVALID_FIELD, - "tx_arr_len_invalid_sfield", - ); - check_result( - unsafe { host::home_le_arr_len(2) }, - error_codes::INVALID_FIELD, - "home_le_arr_len_invalid_sfield", - ); - check_result( - unsafe { host::le_arr_len(1, 2) }, - error_codes::INVALID_FIELD, - "le_arr_len_invalid_sfield", - ); - - // invalid Slice - - check_result( - unsafe { host::amendment_enabled(amendment_name.as_ptr(), long_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "amendment_enabled_too_big_slice", - ); - check_result( - unsafe { host::amendment_enabled(amendment_name.as_ptr(), 65) }, - error_codes::DATA_FIELD_TOO_LARGE, - "amendment_enabled_too_long", - ); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::tx_inner(locator.as_ptr(), long_len, ptr, len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "tx_inner_too_big_slice", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::home_le_inner(locator.as_ptr(), long_len, ptr, len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "home_le_inner_too_big_slice", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::le_inner(1, locator.as_ptr(), long_len, ptr, len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "le_inner_too_big_slice", - ); - }); - check_result( - unsafe { host::tx_inner_arr_len(locator.as_ptr(), long_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "tx_inner_arr_len_too_big_slice", - ); - check_result( - unsafe { host::home_le_inner_arr_len(locator.as_ptr(), long_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "home_le_inner_arr_len_too_big_slice", - ); - check_result( - unsafe { host::le_inner_arr_len(1, locator.as_ptr(), long_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "le_inner_arr_len_too_big_slice", - ); - let too_big_data_len = XRPL_CONTRACT_DATA_SIZE + 1; - check_result( - unsafe { host::set_data(locator.as_ptr(), too_big_data_len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "set_data_too_big_slice", - ); - check_result( - unsafe { - host::check_sig( - message.as_ptr(), - long_len, - pubkey.as_ptr(), - pubkey.len(), - signature.as_ptr(), - signature.len(), - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "check_sig", - ); - check_result( - unsafe { - host::check_sig( - message.as_ptr(), - message.len(), - pubkey.as_ptr(), - long_len, - signature.as_ptr(), - signature.len(), - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "check_sig", - ); - check_result( - unsafe { - host::check_sig( - message.as_ptr(), - message.len(), - pubkey.as_ptr(), - pubkey.len(), - signature.as_ptr(), - long_len, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "check_sig", - ); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::sha512_half(locator.as_ptr(), long_len, ptr, len) }, - error_codes::DATA_FIELD_TOO_LARGE, - "sha512_half_too_big_slice", - ); - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::amm_id( - asset1_bytes.as_ptr(), - long_len, - asset1_bytes.as_ptr(), - asset1_bytes.len(), - ptr, - len, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "amm_id_too_big_slice", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::credential_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), - long_len, - ptr, - len, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "credential_id_too_big_slice", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::mptoken_id( - mptid.as_ptr(), - long_len, - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "mptoken_id_too_big_slice_mptid", - ) - }); - check_result( - unsafe { - host::trace( - message.as_ptr(), - message.len(), - locator.as_ptr().wrapping_add(1_000_000_000), - locator.len(), - 0, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trace_oob_slice", - ); - let float: [u8; 8] = [0xD4, 0x83, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00]; - check_result( - unsafe { - host::trace_xfloat( - message.as_ptr(), - message.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trace_xfloat_oob_slice", - ); - check_result( - unsafe { - host::trace_amt( - message.as_ptr(), - message.len(), - locator.as_ptr().wrapping_add(1_000_000_000), - locator.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trace_amt_oob_slice", - ); - check_result( - unsafe { - host::float_cmp( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_cmp_oob_slice1", - ); - check_result( - unsafe { - host::float_cmp( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_cmp_oob_slice2", - ); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_add( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_add_oob_slice1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_add( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_add_oob_slice2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_sub( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_sub_oob_slice1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_sub( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_sub_oob_slice2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_mult( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_mult_oob_slice1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_mult( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_mult_oob_slice2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_div( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - float.as_ptr(), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_div_oob_slice1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_div( - float.as_ptr(), - float.len(), - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_div_oob_slice2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_root( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - 3, - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_root_oob_slice", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::float_pow( - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - 3, - ptr, - len, - FLOAT_ROUNDING_MODES_TO_NEAREST, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "float_pow_oob_slice", - ) - }); - - // invalid UInt32 - - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::escrow_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "escrow_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::mpt_issuance_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "mpt_issuance_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_offer_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "nft_offer_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::offer_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "offer_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::oracle_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "oracle_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::paychan_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "paychan_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::permissioned_domain_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "permissioned_domain_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::ticket_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "ticket_id_wrong_size_uint32", - ) - }); - with_buffer::<32, _, _>(|ptr, len| { - check_result( - unsafe { - host::vault_id( - account.0.as_ptr(), - account.0.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "vault_id_wrong_size_uint32", - ) - }); - - // invalid UInt256 - - check_result( - unsafe { host::cache_le(locator.as_ptr(), locator.len(), 0) }, - error_codes::INVALID_PARAMS, - "cache_le_wrong_size_uint256", - ); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_uri( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "nft_uri_wrong_size_uint256", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_issuer(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "nft_issuer_wrong_size_uint256", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_taxon(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "nft_taxon_wrong_size_uint256", - ) - }); - check_result( - unsafe { host::nft_flags(locator.as_ptr(), locator.len()) }, - error_codes::INVALID_PARAMS, - "nft_flags_wrong_size_uint256", - ); - check_result( - unsafe { host::nft_xfer_fee(locator.as_ptr(), locator.len()) }, - error_codes::INVALID_PARAMS, - "nft_xfer_fee_wrong_size_uint256", - ); - with_buffer::<4, _, _>(|ptr, len| { - check_result( - unsafe { host::nft_serial(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "nft_serial_wrong_size_uint256", - ) - }); - - // invalid AccountID - - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::accountroot_id(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "accountroot_id_wrong_size_account_id", - ) - }); - let seq: i32 = 1; - let seq_bytes = seq.to_be_bytes(); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::check_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "check_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::credential_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // valid slice size - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "credential_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::credential_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - locator.as_ptr(), // valid slice size - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "credential_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::delegate_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "delegate_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::delegate_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "delegate_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::deposit_preauth_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "deposit_preauth_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::deposit_preauth_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "deposit_preauth_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::did_id(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "did_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::escrow_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "escrow_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::trustline_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - currency.as_ptr(), - currency.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "trustline_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::trustline_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - currency.as_ptr(), - currency.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "trustline_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::mpt_issuance_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "mpt_issuance_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::mptoken_id( - mptid.as_ptr(), - mptid.len(), - locator.as_ptr(), - locator.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "mptoken_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_offer_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "nft_offer_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::offer_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "offer_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::oracle_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "oracle_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::paychan_id( - locator.as_ptr(), // invalid AccountID size - locator.len(), - account.0.as_ptr(), - account.0.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "paychan_id_wrong_size_account_id1", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::paychan_id( - account.0.as_ptr(), - account.0.len(), - locator.as_ptr(), // invalid AccountID size - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "paychan_id_wrong_size_account_id2", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::permissioned_domain_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "permissioned_domain_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { host::signers_id(locator.as_ptr(), locator.len(), ptr, len) }, - error_codes::INVALID_PARAMS, - "signers_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::ticket_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "ticket_id_wrong_size_account_id", - ) - }); - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::vault_id( - locator.as_ptr(), - locator.len(), - seq_bytes.as_ptr(), - seq_bytes.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "vault_id_wrong_size_account_id", - ) - }); - let uint256: &[u8] = b"00000000000000000000000000000001"; - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::nft_uri( - locator.as_ptr(), - locator.len(), - uint256.as_ptr(), - uint256.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "nft_uri_wrong_size_account_id", - ) - }); - check_result( - unsafe { - host::trace_acct( - message.as_ptr(), - message.len(), - locator.as_ptr(), - locator.len(), - ) - }, - error_codes::INVALID_PARAMS, - "trace_acct_wrong_size_account_id", - ); - - // invalid Currency was already tested above - // invalid string - - check_result( - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - uint256.as_ptr(), - uint256.len(), - 0, - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trace_oob_string", - ); - check_result( - unsafe { - host::trace_xfloat( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - float.as_ptr(), - float.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trace_xfloat_oob_string", - ); - check_result( - unsafe { - host::trace_acct( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - account.0.as_ptr(), - account.0.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trace_acct_oob_string", - ); - check_result( - unsafe { - host::trace_amt( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - amount.as_ptr(), - amount.len(), - ) - }, - error_codes::POINTER_OUT_OF_BOUNDS, - "trace_amt_oob_string", - ); - - // trace too large - - check_result( - unsafe { - host::trace( - locator.as_ptr(), - locator.len(), - locator.as_ptr(), - long_len, - 0, - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "trace_too_long", - ); - check_result( - unsafe { host::trace_num(locator.as_ptr(), long_len, 1) }, - error_codes::DATA_FIELD_TOO_LARGE, - "trace_num_too_long", - ); - check_result( - unsafe { host::trace_xfloat(message.as_ptr(), long_len, float.as_ptr(), float.len()) }, - error_codes::DATA_FIELD_TOO_LARGE, - "trace_xfloat_too_long", - ); - check_result( - unsafe { - host::trace_acct( - message.as_ptr(), - long_len, - account.0.as_ptr(), - account.0.len(), - ) - }, - error_codes::DATA_FIELD_TOO_LARGE, - "trace_acct_too_long", - ); - check_result( - unsafe { host::trace_amt(message.as_ptr(), long_len, amount.as_ptr(), amount.len()) }, - error_codes::DATA_FIELD_TOO_LARGE, - "trace_amt_too_long", - ); - - // trace amount errors - - check_result( - unsafe { - host::trace_amt( - message.as_ptr(), - message.len(), - locator.as_ptr(), - locator.len(), - ) - }, - error_codes::INVALID_PARAMS, - "trace_amt_wrong_length", - ); - - // other misc errors - - with_buffer::<2, _, _>(|ptr, len| { - check_result( - unsafe { - host::mptoken_id( - locator.as_ptr(), - locator.len(), - account.0.as_ptr(), - account.0.len(), - ptr, - len, - ) - }, - error_codes::INVALID_PARAMS, - "mptoken_id_mptid_wrong_length", - ) - }); - check_result( - unsafe { - host::trace( - message.as_ptr(), - message.len(), - locator.as_ptr(), - locator.len(), - 2, - ) - }, - error_codes::INVALID_PARAMS, - "trace_invalid_as_hex", - ); - - // ensure that the Slice index desync issue is fixed - let empty: &[u8] = b""; - check_result( - unsafe { - host::trace_acct( - empty.as_ptr(), - empty.len(), - account.0.as_ptr(), - account.0.len(), - ) - }, - 0, - "trace_acct_check_desync", - ); - - 1 // <-- If we get here, finish the escrow. -} diff --git a/src/test/app/wasm_fixtures/copyFixtures.py b/src/test/app/wasm_fixtures/copyFixtures.py deleted file mode 100644 index 8e457b71e2..0000000000 --- a/src/test/app/wasm_fixtures/copyFixtures.py +++ /dev/null @@ -1,287 +0,0 @@ -# cspell: disable -import os -import re -import shlex -import subprocess -import sys -import tempfile -import zipfile -from difflib import get_close_matches - -OPT = "-Oz" -BASE_PATH = os.path.abspath(os.path.dirname(__file__)) - - -def pascal_case(name): - return "".join(word[:1].upper() + word[1:] for word in re.split(r"[_\W]+", name)) - - -def normalize_name(name): - name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name) - return re.sub(r"[^a-z0-9]", "", name.lower()) - - -def fixture_key(name): - name = normalize_name(name).removeprefix("k") - return name.removesuffix("wasmhex").removesuffix("hex") - - -def declared_fixtures(): - h_path = os.path.join(BASE_PATH, "fixtures.h") - with open(h_path, "r", encoding="utf8") as f: - return re.findall( - r"extern std::string const ([A-Za-z_][A-Za-z0-9_]*);", f.read() - ) - - -def find_fixture_name(project_name, suffix): - default = re.sub(r"_([a-z])", lambda m: m.group(1).upper(), project_name) + suffix - k_default = f"k{pascal_case(project_name)}{suffix}" - declarations = declared_fixtures() - normalized = {normalize_name(name): name for name in declarations} - fixture_keys = {fixture_key(name): name for name in declarations} - - for name in (default, k_default): - if normalize_name(name) in normalized: - return normalized[normalize_name(name)] - - project_key = normalize_name(project_name) - matches = [ - name - for key, name in fixture_keys.items() - if key.endswith(project_key) - or key.startswith(project_key) - or project_key.endswith(key) - or project_key.startswith(key) - ] - if len(matches) == 1: - return matches[0] - - close = get_close_matches(project_key, fixture_keys.keys(), n=1, cutoff=0.82) - if close: - return fixture_keys[close[0]] - - return k_default - - -def fixture_cpp_path(fixture_name): - pattern = rf"extern std::string const {fixture_name} =" - for file_name in os.listdir(BASE_PATH): - if not file_name.endswith(".cpp"): - continue - cpp_path = os.path.join(BASE_PATH, file_name) - with open(cpp_path, "r", encoding="utf8") as f: - if re.search(pattern, f.read()): - return cpp_path - return os.path.join(BASE_PATH, "fixtures.cpp") - - -def update_fixture(project_name, wasm, suffix="WasmHex"): - fixture_name = find_fixture_name(project_name, suffix) - print(f"Updating fixture: {fixture_name}") - - cpp_path = fixture_cpp_path(fixture_name) - h_path = os.path.join(BASE_PATH, "fixtures.h") - with open(cpp_path, "r", encoding="utf8") as f: - cpp_content = f.read() - - pattern = rf'extern std::string const {fixture_name} =[ \n]+"[^;]*;' - if re.search(pattern, cpp_content, flags=re.MULTILINE): - updated_cpp_content = re.sub( - pattern, - f'extern std::string const {fixture_name} = "{wasm}";', - cpp_content, - flags=re.MULTILINE, - ) - else: - with open(h_path, "r", encoding="utf8") as f: - h_content = f.read() - updated_h_content = ( - h_content.rstrip() + f"\n\nextern std::string const {fixture_name};\n" - ) - with open(h_path, "w", encoding="utf8") as f: - f.write(updated_h_content) - updated_cpp_content = ( - cpp_content.rstrip() - + f'\n\nextern std::string const {fixture_name} = "{wasm}";\n' - ) - - with open(cpp_path, "w", encoding="utf8") as f: - f.write(updated_cpp_content) - - -def read_wasm_hex(path): - with open(path, "rb") as f: - return f.read().hex() - - -def process_rust(project_name): - project_path = os.path.join(BASE_PATH, project_name) - wasm_location = os.path.join( - project_path, "target", "wasm32v1-none", "release", f"{project_name}.wasm" - ) - try: - subprocess.run( - ["cargo", "build", "--target", "wasm32v1-none", "--release"], - cwd=project_path, - check=True, - ) - subprocess.run( - ["wasm-opt", wasm_location, OPT, "-o", wasm_location], check=True - ) - print(f"WASM file for {project_name} has been built and optimized.") - except FileNotFoundError as e: - print(f"exec error: {e.filename} is required to build Rust fixtures") - sys.exit(1) - except subprocess.CalledProcessError as e: - print(f"exec error: {e}") - sys.exit(1) - - update_fixture(project_name, read_wasm_hex(wasm_location)) - - -def process_c(project_name): - project_path = os.path.join(BASE_PATH, f"{project_name}.c") - wasm_path = os.path.join(BASE_PATH, f"{project_name}.wasm") - cc = os.environ.get("CC") - sysroot = os.environ.get("SYSROOT") - if not cc or not sysroot: - print("exec error: CC and SYSROOT are required to build C fixtures") - sys.exit(1) - - build_cmd = [ - *shlex.split(cc), - f"--sysroot={sysroot}", - "-O3", - "-ffast-math", - "--target=wasm32", - "-fno-exceptions", - "-fno-threadsafe-statics", - "-fvisibility=default", - "-Wl,--export-all", - "-Wl,--no-entry", - "-Wl,--allow-undefined", - "-DNDEBUG", - "--no-standard-libraries", - "-fno-builtin-memset", - "-o", - wasm_path, - project_path, - ] - try: - subprocess.run(build_cmd, check=True) - subprocess.run(["wasm-opt", wasm_path, OPT, "-o", wasm_path], check=True) - print( - f"WASM file for {project_name} has been built with WASI support using clang." - ) - except FileNotFoundError as e: - print(f"exec error: {e.filename} is required to build C fixtures") - sys.exit(1) - except subprocess.CalledProcessError as e: - print(f"exec error: {e}") - sys.exit(1) - - update_fixture(project_name, read_wasm_hex(wasm_path)) - - -def wat_to_wasm(wat_path, wasm_path): - build_cmd = ["wat2wasm", wat_path, "-o", wasm_path] - try: - subprocess.run(build_cmd, check=True) - print(f"WASM file for {os.path.basename(wat_path)} has been built.") - except FileNotFoundError: - print("exec error: wat2wasm is required to build WAT fixtures") - sys.exit(1) - except subprocess.CalledProcessError as e: - print(f"exec error: {e}") - sys.exit(1) - - -def process_wat_file(wat_path): - project_name = os.path.splitext(os.path.basename(wat_path))[0] - with open(wat_path, "r", encoding="utf8") as f: - if "(module" not in f.read(): - print(f"Skipping WAT fixture without a module: {project_name}") - return - - with tempfile.TemporaryDirectory() as tmpdir: - wasm_path = os.path.join(tmpdir, f"{project_name}.wasm") - wat_to_wasm(wat_path, wasm_path) - update_fixture(project_name, read_wasm_hex(wasm_path), "Hex") - - -def process_wat_zip(zip_path): - project_name = os.path.splitext(os.path.basename(zip_path))[0] - with tempfile.TemporaryDirectory() as tmpdir: - with zipfile.ZipFile(zip_path) as archive: - wat_names = [name for name in archive.namelist() if name.endswith(".wat")] - if len(wat_names) != 1: - print(f"exec error: expected one .wat file in {zip_path}") - sys.exit(1) - archive.extract(wat_names[0], tmpdir) - - wasm_path = os.path.join(tmpdir, f"{project_name}.wasm") - wat_to_wasm(os.path.join(tmpdir, wat_names[0]), wasm_path) - update_fixture(project_name, read_wasm_hex(wasm_path), "Hex") - - -def process_wat(project_name): - candidates = [ - os.path.join(BASE_PATH, f"{project_name}.wat"), - os.path.join(BASE_PATH, "wat", f"{project_name}.wat"), - os.path.join(BASE_PATH, "wat", f"{project_name}.zip"), - ] - for path in candidates: - if os.path.isfile(path): - if path.endswith(".zip"): - process_wat_zip(path) - else: - process_wat_file(path) - return - - print(f"exec error: fixture {project_name} not found") - sys.exit(1) - - -if __name__ == "__main__": - if len(sys.argv) > 2: - print("Usage: python copyFixtures.py []") - sys.exit(1) - - if len(sys.argv) == 2: - project_name = os.path.splitext(os.path.basename(sys.argv[1]))[0] - if os.path.isfile(os.path.join(BASE_PATH, project_name, "Cargo.toml")): - process_rust(project_name) - elif os.path.isfile(os.path.join(BASE_PATH, f"{project_name}.c")): - process_c(project_name) - else: - process_wat(project_name) - print("Fixture has been processed.") - else: - dirs = [ - d - for d in os.listdir(BASE_PATH) - if os.path.isfile(os.path.join(BASE_PATH, d, "Cargo.toml")) - ] - c_files = [f for f in os.listdir(BASE_PATH) if f.endswith(".c")] - wat_files = [f for f in os.listdir(BASE_PATH) if f.endswith(".wat")] - wat_path = os.path.join(BASE_PATH, "wat") - wat_fixture_files = [ - f - for f in (os.listdir(wat_path) if os.path.isdir(wat_path) else []) - if f.endswith((".wat", ".zip")) - ] - - for d in sorted(dirs): - process_rust(d) - for c in sorted(c_files): - process_c(c[:-2]) - for wat in sorted(wat_files): - process_wat_file(os.path.join(BASE_PATH, wat)) - for wat_fixture in sorted(wat_fixture_files): - path = os.path.join(wat_path, wat_fixture) - if wat_fixture.endswith(".zip"): - process_wat_zip(path) - else: - process_wat_file(path) - print("All fixtures have been processed.") diff --git a/src/test/app/wasm_fixtures/fixtures.cpp b/src/test/app/wasm_fixtures/fixtures.cpp deleted file mode 100644 index 6ff902717e..0000000000 --- a/src/test/app/wasm_fixtures/fixtures.cpp +++ /dev/null @@ -1,657 +0,0 @@ -// TODO: consider moving these to separate files (and figure out the build) - -#include - -#include - -extern std::string const kLedgerSqnWasmHex = - "0061736d01000000010e0360027f7f017f6000006000017f02120103656e760a6c6467725f696e6465780000030302" - "01020503010002063f0a7f01418088040b7f004180080b7f004180080b7f004180080b7f00418088040b7f00418008" - "0b7f00418088040b7f00418080080b7f0041000b7f0041010b07b1010c066d656d6f72790200115f5f7761736d5f63" - "616c6c5f63746f727300010d657363726f775f66696e69736800020c5f5f64736f5f68616e646c6503010a5f5f6461" - "74615f656e6403020b5f5f737461636b5f6c6f7703030c5f5f737461636b5f6869676803040d5f5f676c6f62616c5f" - "6261736503050b5f5f686561705f6261736503060a5f5f686561705f656e6403070d5f5f6d656d6f72795f62617365" - "03080c5f5f7461626c655f6261736503090a3d0202000b3801037f230041106b220024002000410c6a410410002101" - "200028020c2102200041106a2400200141054100200241054f1b20014100481b0b007f0970726f647563657273010c" - "70726f6365737365642d62790105636c616e675f31392e312e352d776173692d73646b202868747470733a2f2f6769" - "746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a656374206162346235613264623538323935386166316565" - "33303861373930636664623432626432343732302900490f7461726765745f6665617475726573042b0f6d75746162" - "6c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a6d756c746976616c" - "7565"; - -extern std::string const kAllHostFunctionsWasmHex = - "0061736d0100000001540c60027f7f017f60037f7f7f017f60047f7f7f7f017f60017f017f60067f7f7f7f7f7f017f" - "60037f7f7f0060057f7f7f7f7f017f60037f7f7e017f60087f7f7f7f7f7f7f7f017f60017f0060027f7f006000017f" - "02dc041a08686f73745f6c69620874785f6669656c64000108686f73745f6c69620974726163655f6e756d00070868" - "6f73745f6c6962057472616365000608686f73745f6c69620a6c6467725f696e646578000008686f73745f6c696210" - "706172656e745f6c6467725f74696d65000008686f73745f6c696210706172656e745f6c6467725f68617368000008" - "686f73745f6c69620874785f696e6e6572000208686f73745f6c69620a74785f6172725f6c656e000308686f73745f" - "6c69621074785f696e6e65725f6172725f6c656e000008686f73745f6c69620d686f6d655f6c655f6669656c640001" - "08686f73745f6c69620d686f6d655f6c655f696e6e6572000208686f73745f6c69620f686f6d655f6c655f6172725f" - "6c656e000308686f73745f6c696215686f6d655f6c655f696e6e65725f6172725f6c656e000008686f73745f6c6962" - "0863616368655f6c65000108686f73745f6c69620d63726564656e7469616c5f6964000808686f73745f6c69620965" - "7363726f775f6964000408686f73745f6c6962096f7261636c655f6964000408686f73745f6c69620b736861353132" - "5f68616c66000208686f73745f6c6962076e66745f757269000408686f73745f6c6962087365745f64617461000008" - "686f73745f6c6962086c655f6669656c64000208686f73745f6c6962086c655f696e6e6572000608686f73745f6c69" - "620a6c655f6172725f6c656e000008686f73745f6c6962106c655f696e6e65725f6172725f6c656e000108686f7374" - "5f6c69620e6163636f756e74726f6f745f6964000208686f73745f6c69620a74726163655f616363740002030c0b09" - "0a05050b05000101030005030100110619037f01418080c0000b7f0041af99c0000b7f0041b099c0000b073504066d" - "656d6f727902000d657363726f775f66696e697368001e0a5f5f646174615f656e6403010b5f5f686561705f626173" - "6503020a911e0b990101027f230041306b220124002000027f418180202001411c6a4114100022024114470440417f" - "20022002417f4e1b210241010c010b200020012f001c3b0001200041036a2001411e6a2d00003a0000200120012900" - "233703082001200141286a29000037000d200128001f21022000410d6a200129000d37000020002001290308370208" - "41000b3a000020002002360204200141306a24000b460020012d00004101460440418080c000410b20013402041001" - "000b20002001290001370000200041106a200141116a280000360000200041086a200141096a2900003700000b1900" - "200241094f0440000b20002002360204200020013602000b1900200241214f0440000b200020023602042000200136" - "02000ba91b01097f230041b0036b22002400418b80c000411b41014100410010021a41a680c0004119410141004100" - "10021a41e780c000412b41014100410010021a2000410036027002400240024002400240024002400240200041f000" - "6a220741041003220141004a0440419281c00041172000280270220141187420014180fe0371410874722001410876" - "4180fe037120014118767272ad10011a200041003602900120004190016a220341041004220141004c0d0141a981c0" - "004113200028029001220141187420014180fe03714108747220014108764180fe037120014118767272ad10011a20" - "0041c8016a22024200370300200041c0016a22054200370300200041b8016a22044200370300200042003703b00120" - "0041b0016a22064120100522014120470d0241bc81c000411320064120410110021a41cf81c0004120410141004100" - "10021a41dc82c000412e41014100410010021a200041a0016a410036020020004198016a4200370300200042003703" - "90014181802020034114100022014114470d03418a83c00041142003101f2000420037034841888018200041c8006a" - "22034108100022014108470d04419e83c0004117420810011a41b583c000412820034108410110021a200041003602" - "3041848008200041306a22034104100022014104470d0541dd83c000411520034104410110021a200041f4006a4100" - "36000020004100360071200041013a0070200242003703002005420037030020044200370300200042003703b00102" - "4020074108200641201006220141004e044041f283c00041142001ad10011a200041286a20062001101d418684c000" - "410d2000280228200028022c410110021a0c010b419384c00041292001ac10011a0b41bc84c00041154183803c1007" - "ac10011a41d184c00041134189803c1007ac10011a0240200041f0006a41081008220141004e044041e484c0004114" - "2001ad10011a0c010b41f884c000412d2001ac10011a0b41a585c000412341014100410010021a41de86c000413341" - "014100410010021a2000420037034841828018200041c8006a220141081009220341004c0d06200341084604404191" - "87c000412b420810011a41bc87c000412f20014108410110021a0c080b41eb87c000412f2003ad10011a200041206a" - "200041c8006a2003101c419a88c000411720002802202000280224410110021a0c070b41bf82c000411d2001ac1001" - "1a419b7f21020c070b419a82c00041252001ac10011a419a7f21020c060b41ef81c000412b2001ac10011a41997f21" - "020c050b41b486c000412a2001ac10011a41b77e21020c040b41f385c00041c1002001ac10011a41b67e21020c030b" - "41c885c000412b2001ac10011a41b57e21020c020b41b188c00041c5002003ac10011a0b200041a0016a4100360200" - "20004198016a4200370300200042003703900102404181802020004190016a220341141009220141004a044041f688" - "c000411e2003101f0c010b419489c00041332001ac10011a0b200041f4006a41003600002000410036007120004101" - "3a0070200041c8016a4200370300200041c0016a4200370300200041b8016a4200370300200042003703b001024020" - "0041f0006a4108200041b0016a22014120100a220341004e044041c789c000411c2003ad10011a200041186a200120" - "03101d41e389c00041152000280218200028021c410110021a0c010b41f889c00041392003ac10011a0b41b18ac000" - "41244183803c100bac10011a0240200041f0006a4108100c220141004e044041d58ac000411c2001ad10011a0c010b" - "41f18ac000413d2001ac10011a0b41ae8bc000412841014100410010021a41d68bc000412f41014100410010021a20" - "0041b0016a2203101a200041f0006a22012003101b200041a8016a4200370300200041a0016a420037030020004198" - "016a4200370300200042003703900102400240024002400240200120004190016a2203102022014120460440200341" - "204100100d220441004a044041858cc00041232004ad10011a200042003703302004200041306a2201410810212203" - "41004c0d022003410846044041a88cc000412a420810011a41d28cc000412e20014108410110021a0c060b41808dc0" - "00412e2003ad10011a200041106a200041306a2003101c41ae8dc000411620002802102000280214410110021a0c05" - "0b41e68fc000413c2004ac10011a200041c8016a4200370300200041c0016a4200370300200041b8016a4200370300" - "200042003703b0014101200041b0016a4120102122014100480d020c030b41ba92c000412e2001ac10011a41ef7c21" - "020c050b41c48dc000412b2003ac10011a0c020b41a290c00041c1002001ac10011a0b200041cc006a410036000020" - "004100360049200041013a00484101200041c8006a200041b0016a10222201410048044041e390c00041352001ac10" - "011a0b4101102322014100480440419891c00041322001ac10011a0b4101200041c8006a10242201410048044041ca" - "91c00041392001ac10011a0b418392c000413741014100410010021a0c010b200041cc006a41003600002000410036" - "0049200041013a0048200041c8016a4200370300200041c0016a4200370300200041b8016a42003703002000420037" - "03b00102402004200041c8006a200041b0016a22011022220341004e044041ef8dc000411b2003ad10011a20004108" - "6a20012003101d418a8ec00041142000280208200028020c410110021a0c010b419e8ec00041312003ac10011a0b41" - "cf8ec000412320041023ac10011a02402004200041c8006a1024220141004e044041f28ec000411b2001ad10011a0c" - "010b418d8fc00041352001ac10011a0b41c28fc000412441014100410010021a0b41e892c000412f41014100410010" - "021a200041b0016a2201101a200041306a22042001101b200041e0006a4200370300200041d8006a42003703002000" - "41d0006a420037030020004200370348024002400240024002402004200041c8006a22031020220141204604404197" - "93c000410f20034120410110021a20004188016a420037030020004180016a4200370300200041f8006a4200370300" - "200042003703700240200441142004411441a693c0004109200041f0006a22014120100e220341004a044020002001" - "2003101d41ae93c000411220002802002000280204410110021a0c010b41c093c000413c2003ac10011a0b200041a8" - "016a22064200370300200041a0016a2202420037030020004198016a22054200370300200042003703900120004180" - "808cc07e360268200041306a22034114200041e8006a410420004190016a22084120100f22014120470d0141fc93c0" - "00410e20084120410110021a200041c8016a4200370300200041c0016a4200370300200041b8016a42003703002000" - "42003703b001200041808080d00236026c20034114200041ec006a4104200041b0016a22044120101022014120470d" - "02418a94c000410e20044120410110021a419894c000412441014100410010021a419195c000412541014100410010" - "021a20004188016a420037030020004180016a4200370300200041f8006a42003703002000420037037041b695c000" - "4117200041f0006a22034120101122014120470d0341cd95c000410b41b695c0004117410110021a41d895c0004111" - "20034120410110021a2004101a200041c8006a22072004101b20064200370300200242003703002005420037030020" - "0042003703900102404100200422026b410371220320026a220520024d0d0020030440200321010340200241003a00" - "00200241016a2102200141016b22010d000b0b200341016b4107490d000340200241003a0000200241076a41003a00" - "00200241066a41003a0000200241056a41003a0000200241046a41003a0000200241036a41003a0000200241026a41" - "003a0000200241016a41003a0000200241086a22022005470d000b0b200541800220036b2201417c716a220220054b" - "0440034020054100360200200541046a22052002490d000b0b024020022001410371220120026a22034f0d00200122" - "0504400340200241003a0000200241016a2102200541016b22050d000b0b200141016b4107490d000340200241003a" - "0000200241076a41003a0000200241066a41003a0000200241056a41003a0000200241046a41003a0000200241036a" - "41003a0000200241026a41003a0000200241016a41003a0000200241086a22022003470d000b0b0240200741142008" - "412020044180021012220141004a044041e995c00041102001ad10011a20014181024f0d0641f995c0004109200420" - "01410110021a0c010b418296c000412e2001ac10011a0b41b096c000411241c296c00041074101100222014100480d" - "0541c996c000411d2001ad10011a41e696c0004111422a1001410048044041ad97c000411a42a47b10011a41a47b21" - "020c070b41f796c000411c420010011a41012102419397c000411a41014100410010021a41ff97c000412941014100" - "410010021a41a898c000412810132201412846044041d098c000412741a898c0004128410110021a41f798c000411e" - "41014100410010021a41bf80c000412841014100410010021a0c070b419599c000411a2001ac10011a41c37a21020c" - "060b41f494c000411d2001ac10011a418b7c21020c050b41d894c000411c2001ac10011a41897c21020c040b41bc94" - "c000411c2001ac10011a41887c21020c030b41dd97c00041222001ac10011a41a77b21020c020b000b41c797c00041" - "162001ac10011a41a57b21020b200041b0036a240020020b0d00200020012002411410191a0b0c0020004114200141" - "2010180b0e002000418280182001200210140b0e002000200141082002412010150b0a0020004183803c10160b0a00" - "20002001410810170b0bb9190100418080c0000baf196572726f725f636f64653d3d3d3d20484f53542046554e4354" - "494f4e532054455354203d3d3d54657374696e6720323620686f73742066756e6374696f6e73535543434553533a20" - "416c6c20686f73742066756e6374696f6e20746573747320706173736564212d2d2d2043617465676f727920313a20" - "4c6564676572204865616465722046756e6374696f6e73202d2d2d4c65646765722073657175656e6365206e756d62" - "65723a506172656e74206c65646765722074696d653a506172656e74206c656467657220686173683a535543434553" - "533a204c6564676572206865616465722066756e6374696f6e734552524f523a206765745f706172656e745f6c6564" - "6765725f686173682077726f6e67206c656e6774683a4552524f523a206765745f706172656e745f6c65646765725f" - "74696d65206661696c65643a4552524f523a206765745f6c65646765725f73716e206661696c65643a2d2d2d204361" - "7465676f727920323a205472616e73616374696f6e20446174612046756e6374696f6e73202d2d2d5472616e736163" - "74696f6e204163636f756e743a5472616e73616374696f6e20466565206c656e6774683a5472616e73616374696f6e" - "20466565202873657269616c697a65642058525020616d6f756e74293a5472616e73616374696f6e2053657175656e" - "63653a4e6573746564206669656c64206c656e6774683a4e6573746564206669656c643a494e464f3a206765745f74" - "785f6e65737465645f6669656c64206e6f74206170706c696361626c653a5369676e657273206172726179206c656e" - "6774683a4d656d6f73206172726179206c656e6774683a4e6573746564206172726179206c656e6774683a494e464f" - "3a206765745f74785f6e65737465645f61727261795f6c656e206e6f74206170706c696361626c653a535543434553" - "533a205472616e73616374696f6e20646174612066756e6374696f6e734552524f523a206765745f74785f6669656c" - "642853657175656e6365292077726f6e67206c656e6774683a4552524f523a206765745f74785f6669656c64284665" - "65292077726f6e67206c656e67746820286578706563746564203820627974657320666f7220585250293a4552524f" - "523a206765745f74785f6669656c64284163636f756e74292077726f6e67206c656e6774683a2d2d2d204361746567" - "6f727920333a2043757272656e74204c6564676572204f626a6563742046756e6374696f6e73202d2d2d4375727265" - "6e74206f626a6563742062616c616e6365206c656e677468202858525020616d6f756e74293a43757272656e74206f" - "626a6563742062616c616e6365202873657269616c697a65642058525020616d6f756e74293a43757272656e74206f" - "626a6563742062616c616e6365206c656e67746820286e6f6e2d58525020616d6f756e74293a43757272656e74206f" - "626a6563742062616c616e63653a494e464f3a206765745f63757272656e745f6c65646765725f6f626a5f6669656c" - "642842616c616e636529206661696c656420286d6179206265206578706563746564293a43757272656e74206c6564" - "676572206f626a656374206163636f756e743a494e464f3a206765745f63757272656e745f6c65646765725f6f626a" - "5f6669656c64284163636f756e7429206661696c65643a43757272656e74206e6573746564206669656c64206c656e" - "6774683a43757272656e74206e6573746564206669656c643a494e464f3a206765745f63757272656e745f6c656467" - "65725f6f626a5f6e65737465645f6669656c64206e6f74206170706c696361626c653a43757272656e74206f626a65" - "6374205369676e657273206172726179206c656e6774683a43757272656e74206e6573746564206172726179206c65" - "6e6774683a494e464f3a206765745f63757272656e745f6c65646765725f6f626a5f6e65737465645f61727261795f" - "6c656e206e6f74206170706c696361626c653a535543434553533a2043757272656e74206c6564676572206f626a65" - "63742066756e6374696f6e732d2d2d2043617465676f727920343a20416e79204c6564676572204f626a6563742046" - "756e6374696f6e73202d2d2d5375636365737366756c6c7920636163686564206f626a65637420696e20736c6f743a" - "436163686564206f626a6563742062616c616e6365206c656e677468202858525020616d6f756e74293a4361636865" - "64206f626a6563742062616c616e6365202873657269616c697a65642058525020616d6f756e74293a436163686564" - "206f626a6563742062616c616e6365206c656e67746820286e6f6e2d58525020616d6f756e74293a43616368656420" - "6f626a6563742062616c616e63653a494e464f3a206765745f6c65646765725f6f626a5f6669656c642842616c616e" - "636529206661696c65643a436163686564206e6573746564206669656c64206c656e6774683a436163686564206e65" - "73746564206669656c643a494e464f3a206765745f6c65646765725f6f626a5f6e65737465645f6669656c64206e6f" - "74206170706c696361626c653a436163686564206f626a656374205369676e657273206172726179206c656e677468" - "3a436163686564206e6573746564206172726179206c656e6774683a494e464f3a206765745f6c65646765725f6f62" - "6a5f6e65737465645f61727261795f6c656e206e6f74206170706c696361626c653a535543434553533a20416e7920" - "6c6564676572206f626a6563742066756e6374696f6e73494e464f3a2063616368655f6c65646765725f6f626a2066" - "61696c65642028657870656374656420776974682074657374206669787475726573293a494e464f3a206765745f6c" - "65646765725f6f626a5f6669656c64206661696c656420617320657870656374656420286e6f20636163686564206f" - "626a656374293a494e464f3a206765745f6c65646765725f6f626a5f6e65737465645f6669656c64206661696c6564" - "2061732065787065637465643a494e464f3a206765745f6c65646765725f6f626a5f61727261795f6c656e20666169" - "6c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f626a5f6e65737465645f617272" - "61795f6c656e206661696c65642061732065787065637465643a535543434553533a20416e79206c6564676572206f" - "626a6563742066756e6374696f6e732028696e7465726661636520746573746564294552524f523a206163636f756e" - "74726f6f745f6964206661696c656420666f722063616368696e6720746573743a2d2d2d2043617465676f72792035" - "3a204b65796c65742047656e65726174696f6e2046756e6374696f6e73202d2d2d4163636f756e74206b65796c6574" - "3a546573745479706543726564656e7469616c206b65796c65743a494e464f3a2063726564656e7469616c5f6b6579" - "6c6574206661696c656420286578706563746564202d20696e74657266616365206973737565293a457363726f7720" - "6b65796c65743a4f7261636c65206b65796c65743a535543434553533a204b65796c65742067656e65726174696f6e" - "2066756e6374696f6e734552524f523a206f7261636c655f6b65796c6574206661696c65643a4552524f523a206573" - "63726f775f6b65796c6574206661696c65643a4552524f523a206163636f756e74726f6f745f6964206661696c6564" - "3a2d2d2d2043617465676f727920363a205574696c6974792046756e6374696f6e73202d2d2d48656c6c6f2c205852" - "504c205741534d20776f726c6421496e70757420646174613a5348413531322068616c6620686173683a4e46542064" - "617461206c656e6774683a4e465420646174613a494e464f3a206765745f6e6674206661696c656420286578706563" - "746564202d206e6f2073756368204e4654293a54657374207472616365206d6573736167657061796c6f6164547261" - "63652066756e6374696f6e206279746573207772697474656e3a54657374206e756d62657220747261636554726163" - "655f6e756d2066756e6374696f6e20737563636565646564535543434553533a205574696c6974792066756e637469" - "6f6e734552524f523a2074726163655f6e756d2829206661696c65643a4552524f523a207472616365282920666169" - "6c65643a4552524f523a20636f6d707574655f7368613531325f68616c66206661696c65643a2d2d2d204361746567" - "6f727920373a2044617461205570646174652046756e6374696f6e73202d2d2d55706461746564206c656467657220" - "656e74727920646174612066726f6d205741534d20746573745375636365737366756c6c792075706461746564206c" - "656467657220656e74727920776974683a535543434553533a2044617461207570646174652066756e6374696f6e73" - "4552524f523a207570646174655f64617461206661696c65643a004d0970726f64756365727302086c616e67756167" - "65010452757374000c70726f6365737365642d6279010572757374631d312e38372e30202831373036376539616320" - "323032352d30352d303929002c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c73" - "2b087369676e2d657874"; - -extern std::string const kAllKeyletsWasmHex = - "0061736d0100000001500a60067f7f7f7f7f7f017f60047f7f7f7f017f60087f7f7f7f7f7f7f7f017f60047f7f7f7f" - "0060037f7f7f017f60037f7f7e017f60057f7f7f7f7f017f6000017f60037f7f7f0060067f7f7f7f7f7e00029f0418" - "08686f73745f6c69620974726163655f6e756d000508686f73745f6c6962057472616365000608686f73745f6c6962" - "0863616368655f6c65000408686f73745f6c6962086c655f6669656c64000108686f73745f6c69620d686f6d655f6c" - "655f6669656c64000408686f73745f6c69620a74726163655f61636374000108686f73745f6c69620e6163636f756e" - "74726f6f745f6964000108686f73745f6c69620c74727573746c696e655f6964000208686f73745f6c696206616d6d" - "5f6964000008686f73745f6c696208636865636b5f6964000008686f73745f6c69620d63726564656e7469616c5f69" - "64000208686f73745f6c69620b64656c65676174655f6964000008686f73745f6c6962126465706f7369745f707265" - "617574685f6964000008686f73745f6c6962066469645f6964000108686f73745f6c696209657363726f775f696400" - "0008686f73745f6c69620f6d70745f69737375616e63655f6964000008686f73745f6c69620a6d70746f6b656e5f69" - "64000008686f73745f6c69620c6e66745f6f666665725f6964000008686f73745f6c6962086f666665725f69640000" - "08686f73745f6c69620a7061796368616e5f6964000208686f73745f6c6962167065726d697373696f6e65645f646f" - "6d61696e5f6964000008686f73745f6c69620a7369676e6572735f6964000108686f73745f6c6962097469636b6574" - "5f6964000008686f73745f6c6962087661756c745f6964000003070603030307080905030100110619037f01418080" - "c0000b7f0041c28ac0000b7f0041d08ac0000b073504066d656d6f727902000d657363726f775f66696e697368001b" - "0a5f5f646174615f656e6403010b5f5f686561705f6261736503020ae8370614002000200120022003418280204282" - "8020101d0b140020002001200220034181802042818020101d0bd10302017f017e230041a0016b2204240002402001" - "2d0000410146044041d780c000411620012802042201ac10001a200041013a0000200020013602040c010b20044118" - "6a200141196a290000370300200441106a200141116a290000370300200441086a200141096a290000370300200420" - "012900013703002002200320044120410110011a2004412041001002220141004c044041d080c00041072001ac1000" - "1a200041013a0000200020013602040c010b418b80c000410f4285801410001a20014185801420044180016a412010" - "032201412047044041af80c0004115417f20012001417f4e1b2201ac10001a200041013a0000200020013602040c01" - "0b200441c2006a20044182016a2d00003a0000200441f0006a20044197016a2900002205370300200441286a220120" - "04418f016a290000370300200441306a22022005370300200441386a22032004419f016a2d00003a0000200420042f" - "0080013b014020042004290087013703202004200428008301360043200441df006a20032d00003a0000200441d700" - "6a2002290300370000200441cf006a20012903003700002004200429032037004741c480c000410c200441406b4120" - "410110011a20004180023b01000b200441a0016a24000bd32c02097f027e23004180076b2200240041ed80c0004123" - "41014100410010011a02402000027f02404181802020004190016a220741141004220641144604402000410e6a2000" - "4192016a22032d00003a000020002000290097013703e80120002000419c016a22012900003700ed01200020002f00" - "90013b010c200020002903e8013703d806200020002900ed013700dd06200020002800930136000f200041186a2000" - "2900dd06370000200020002903d806370013419081c00041082000410c6a2204411410051a41838020200741141004" - "22064114470d03200041226a20032d00003a000020002000290097013703e801200020012900003700ed0120002000" - "2f0090013b0120200020002903e8013703d806200020002900ed013700dd0620002000280093013600232000412c6a" - "20002900dd06370000200020002903d806370027419881c000410c200041206a411410051a200041a8016a22034200" - "370300200041a0016a2201420037030020004198016a42003703002000420037039001200441142007412010062204" - "4120460d01024020044100480440200020043602380c010b2000417f3602380b41010c020b0c020b200041cd006a20" - "03290300370000200041c5006a20012903003700002000413d6a20004198016a290300370000200020002903900137" - "003541000b3a003420004190016a200041346a41a481c00041071019024020002d0090014101460440200028029401" - "2106419c8ac0004112420510001a0c010b4100210641ab81c000413541014100410010011a200041e6006a41c4003a" - "0000200041e0006a4100360200200041eb006a41003a0000200041d5a6013b01642000420037035820004100360067" - "200041a8016a22044200370300200041a0016a2203420037030020004198016a220142003703002000420037039001" - "02402000410c6a4114200041206a4114200041d8006a411420004190016a4120100722074120470440024020074100" - "480440200020073602700c010b2000417f3602700b410121060c010b20004185016a2004290300370000200041fd00" - "6a2003290300370000200041f5006a2001290300370000200020002903900137006d0b200020063a006c2000419001" - "6a200041ec006a41e081c0004109101a20002d00900141014604402000280294012106419c8ac0004112420510001a" - "0c010b4100210641e981c000413741014100410010011a200041f8016a200041306a2204280100360200200041f001" - "6a200041286a220329010037030020004184026a200041e0006a290300220a3702002000418c026a200041e8006a28" - "02002201360200200020002901203703e8012000200029035822093702fc01200041e8066a22052001360200200041" - "e0066a2207200a370300200020093703d806200041f4066a2003290100370200200041fc066a200428010036020020" - "0020002901203702ec0620004190026a200041d8066a22034128101c20004194016a200041e8016a41d000101c2000" - "410136029001200041f0066a220142003703002005420037030020074200370300200042003703d806024041ae8ac0" - "004114200041bc016a412820034120100822034120470440024020034100480440200020033602ec010c010b200041" - "7f3602ec010b410121060c010b20004181026a2001290300370000200041f9016a2005290300370000200041f1016a" - "2007290300370000200020002903d8063700e9010b200020063a00e801200041bc026a200041e8016a41a082c00041" - "03101920002d00bc02410146044020002802c0022106419c8ac0004112420610001a0c010b4100210641a382c00041" - "3141014100410010011a200041063602d80620004180026a22044200370300200041f8016a22034200370300200041" - "f0016a22014200370300200042003703e80102402000410c6a4114200041d8066a4104200041e8016a412010092207" - "4120470440024020074100480440200020073602c8020c010b2000417f3602c8020b410121060c010b200041dd026a" - "2004290300370000200041d5026a2003290300370000200041cd026a2001290300370000200020002903e8013700c5" - "020b200020063a00c402200041e8016a200041c4026a41d482c0004105101920002d00e801410146044020002802ec" - "012106419c8ac0004112420610001a0c010b41d982c000413341014100410010011a20004180026a42003703002000" - "41f8016a4200370300200041f0016a4200370300200042003703e801024002402000410c6a2201411420014114418c" - "83c0004112200041e8016a4120100a2201412047044041d780c0004116417f20012001417f4e1b2206ac10001a0c01" - "0b200041da066a20002d00ea013a0000200041f0026a200041f7016a290000220a370300200041f8026a200041ff01" - "6a290000220937030020004180036a20004187026a2d000022013a0000200041e7066a200a370000200041ef066a20" - "09370000200041f7066a20013a0000200020002f01e8013b01d806200020002900ef0122093703e802200020002800" - "eb013600db06200020093700df06419e83c000410a200041d8066a22014120410110011a2001412041001002220641" - "004c044041d080c00041072006ac10001a0c010b418b80c000410f4298802010001a200641988020200041e8016a41" - "14100322014114460d0141af80c0004115417f20012001417f4e1b2206ac10001a0b419c8ac0004112420710001a0c" - "010b419a80c000411541014100410010011a41a883c000413841014100410010011a230041206b2208240020084118" - "6a22074200370300200841106a22044200370300200841086a220342003703002008420037030020004184036a2201" - "027f2000410c6a22064114200041206a2202411420084120100b220541204704400240200541004804402001200536" - "02040c010b2001417f3602040b41010c010b20012008290300370001200141196a2007290300370000200141116a20" - "04290300370000200141096a200329030037000041000b3a0000200841206a2400200041e8016a2205200141e083c0" - "004108101920002d00e80145044041e883c000413641014100410010011a230041206b22082400200841186a220742" - "00370300200841106a22044200370300200841086a2203420037030020084200370300200041a8036a2201027f2006" - "41142002411420084120100c22024120470440024020024100480440200120023602040c010b2001417f3602040b41" - "010c010b20012008290300370001200141196a2007290300370000200141116a2004290300370000200141096a2003" - "29030037000041000b3a0000200841206a240020052001419e84c000410e101920002d00e801410146044020002802" - "ec012106419c8ac0004112420910001a0c020b41ac84c000413c41014100410010011a230041206b22022400200241" - "186a22074200370300200241106a22044200370300200241086a2203420037030020024200370300200041cc036a22" - "01027f2000410c6a411420024120100d22054120470440024020054100480440200120053602040c010b2001417f36" - "02040b41010c010b20012002290300370001200141196a2007290300370000200141116a2004290300370000200141" - "096a200329030037000041000b3a0000200241206a2400200041e8016a200141e884c0004103101920002d00e80141" - "0146044020002802ec012106419c8ac0004112420a10001a0c020b41eb84c000413141014100410010011a23004130" - "6b220224002002410b36020c200241286a22074200370300200241206a22044200370300200241186a220342003703" - "0020024200370310200041f0036a2201027f2000410c6a41142002410c6a4104200241106a4120100e220541204704" - "40024020054100480440200120053602040c010b2001417f3602040b41010c010b2001200229031037000120014119" - "6a2007290300370000200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a24" - "00200041e8016a2001419c85c0004106101920002d00e801410146044020002802ec012106419c8ac0004112420b10" - "001a0c020b41a285c000413441014100410010011a230041306b220224002002410c36020c200241286a2207420037" - "0300200241206a22044200370300200241186a220342003703002002420037031020004194046a2201027f2000410c" - "6a41142002410c6a4104200241106a4120100f22054120470440024020054100480440200120053602040c010b2001" - "417f3602040b41010c010b20012002290310370001200141196a2007290300370000200141116a2004290300370000" - "200141096a200329030037000041000b3a0000200241306a2400200041fc016a2000411c6a280100360200200041f4" - "016a200041146a2901003702002000200029010c3702ec01200041808080e0003602e801200041d8066a2103230041" - "406a22042400024020012d0000410146044041d780c000411620012802042201ac10001a200341013a000020032001" - "3602040c010b200441206a200141196a290000370300200441186a200141116a290000370300200441106a20014109" - "6a2900003703002004200129000137030841d685c000410b200441086a22014120410110011a024002402001412041" - "001002220141004c044041d080c00041072001ac10001a0c010b418b80c000410f4284802010001a20014184802020" - "04412c6a4114100322014114460d0141af80c0004115417f20012001417f4e1b2201ac10001a0b200341013a000020" - "0320013602040c010b419a80c000411541014100410010011a20034180023b01000b200441406b240020002d00d806" - "410146044020002802dc062106419c8ac0004112420c10001a0c020b41e185c000413941014100410010011a230041" - "206b22022400200241186a22074200370300200241106a22044200370300200241086a220342003703002002420037" - "0300200041b8046a2201027f200041e8016a4118200041206a41142002412010102205412047044002402005410048" - "0440200120053602040c010b2001417f3602040b41010c010b20012002290300370001200141196a20072903003700" - "00200141116a2004290300370000200141096a200329030037000041000b3a0000200241206a2400200041d8066a20" - "01419a86c0004107101920002d00d806410146044020002802dc062106419c8ac0004112420d10001a0c020b41a186" - "c000413541014100410010011a230041306b220224002002410636020c200241286a22074200370300200241206a22" - "044200370300200241186a2203420037030020024200370310200041dc046a2201027f200041206a41142002410c6a" - "4104200241106a4120101122054120470440024020054100480440200120053602040c010b2001417f3602040b4101" - "0c010b20012002290310370001200141196a2007290300370000200141116a2004290300370000200141096a200329" - "030037000041000b3a0000200241306a2400200041d8066a200141d686c000410c101820002d00d806410146044020" - "002802dc062106419c8ac0004112420d10001a0c020b41e286c000413a41014100410010011a230041306b22022400" - "2002410d36020c200241286a22074200370300200241206a22044200370300200241186a2203420037030020024200" - "37031020004180056a2201027f2000410c6a41142002410c6a4104200241106a412010122205412047044002402005" - "4100480440200120053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a20072903" - "00370000200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a2400200041d8" - "066a2001419c87c0004105101920002d00d806410146044020002802dc062106419c8ac0004112420d10001a0c020b" - "41a187c000413341014100410010011a230041306b220224002002410e36020c200241286a22074200370300200241" - "206a22044200370300200241186a2203420037030020024200370310200041a4056a2201027f2000410c6a41142000" - "41206a41142002410c6a4104200241106a4120101322054120470440024020054100480440200120053602040c010b" - "2001417f3602040b41010c010b20012002290310370001200141196a2007290300370000200141116a200429030037" - "0000200141096a200329030037000041000b3a0000200241306a2400200041d8066a200141d487c000410a10192000" - "2d00d806410146044020002802dc062106419c8ac0004112420e10001a0c020b41de87c00041384101410041001001" - "1a230041306b220224002002410f36020c200241286a22074200370300200241206a22044200370300200241186a22" - "03420037030020024200370310200041c8056a2201027f2000410c6a41142002410c6a4104200241106a4120101422" - "054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b200120022903103700" - "01200141196a2007290300370000200141116a2004290300370000200141096a200329030037000041000b3a000020" - "0241306a2400200041d8066a2001419688c0004112101820002d00d806410146044020002802dc062106419c8ac000" - "4112420f10001a0c020b41a888c00041c00041014100410010011a230041206b22022400200241186a220742003703" - "00200241106a22044200370300200241086a2203420037030020024200370300200041ec056a2201027f2000410c6a" - "411420024120101522054120470440024020054100480440200120053602040c010b2001417f3602040b41010c010b" - "20012002290300370001200141196a2007290300370000200141116a2004290300370000200141096a200329030037" - "000041000b3a0000200241206a2400200041d8066a200141e888c000410a101a20002d00d806410146044020002802" - "dc062106419c8ac0004112421010001a0c020b41f288c000413841014100410010011a230041306b22022400200241" - "1236020c200241286a22074200370300200241206a22044200370300200241186a2203420037030020024200370310" - "20004190066a2201027f2000410c6a41142002410c6a4104200241106a412010162205412047044002402005410048" - "0440200120053602040c010b2001417f3602040b41010c010b20012002290310370001200141196a20072903003700" - "00200141116a2004290300370000200141096a200329030037000041000b3a0000200241306a2400200041d8066a20" - "0141aa89c0004106101920002d00d806410146044020002802dc062106419c8ac0004112421210001a0c020b410121" - "0641b089c000413441014100410010011a230041306b220224002002411336020c200241286a220742003703002002" - "41206a22044200370300200241186a2203420037030020024200370310200041b4066a2201027f2000410c6a411420" - "02410c6a4104200241106a4120101722054120470440024020054100480440200120053602040c010b2001417f3602" - "040b41010c010b20012002290310370001200141196a2007290300370000200141116a200429030037000020014109" - "6a200329030037000041000b3a0000200241306a2400200041d8066a200141e489c0004105101920002d00d8064101" - "46044020002802dc062106419c8ac0004112421310001a0c020b41e989c000413341014100410010011a0c010b2000" - "2802ec012106419c8ac0004112420810001a0b20004180076a240020060f0b418080c000410b417f20062006417f4e" - "1bac1000000bfd0401067f200241104f0440024020002000410020006b41037122056a22044f0d0020012103200504" - "40200521060340200020032d00003a0000200341016a2103200041016a2100200641016b22060d000b0b200541016b" - "4107490d000340200020032d00003a0000200041016a200341016a2d00003a0000200041026a200341026a2d00003a" - "0000200041036a200341036a2d00003a0000200041046a200341046a2d00003a0000200041056a200341056a2d0000" - "3a0000200041066a200341066a2d00003a0000200041076a200341076a2d00003a0000200341086a2103200041086a" - "22002004470d000b0b2004200220056b2207417c7122086a21000240200120056a2206410371450440200020044d0d" - "0120062101034020042001280200360200200141046a2101200441046a22042000490d000b0c010b200020044d0d00" - "2006410374220541187121032006417c71220241046a2101410020056b411871210520022802002102034020042002" - "2003762001280200220220057472360200200141046a2101200441046a22042000490d000b0b200741037121022006" - "20086a21010b02402000200020026a22064f0d002002410771220304400340200020012d00003a0000200141016a21" - "01200041016a2100200341016b22030d000b0b200241016b4107490d000340200020012d00003a0000200041016a20" - "0141016a2d00003a0000200041026a200141026a2d00003a0000200041036a200141036a2d00003a0000200041046a" - "200141046a2d00003a0000200041056a200141056a2d00003a0000200041066a200141066a2d00003a000020004107" - "6a200141076a2d00003a0000200141086a2101200041086a22002006470d000b0b0b940201017f230041406a220624" - "00024020012d0000410146044041d780c000411620012802042201ac10001a200041013a0000200020013602040c01" - "0b200641206a200141196a290000370300200641186a200141116a290000370300200641106a200141096a29000037" - "03002006200129000137030820022003200641086a22014120410110011a024002402001412041001002220141004c" - "044041d080c00041072001ac10001a0c010b418b80c000410f200510001a200120042006412c6a4114100322014114" - "460d0141af80c0004115417f20012001417f4e1b2201ac10001a0b200041013a0000200020013602040c010b419a80" - "c000411541014100410010011a20004180023b01000b200641406b24000b0bb80a0100418080c0000bae0a6572726f" - "725f636f64653d47657474696e67206669656c643a204669656c6420646174613a207265747269657665644572726f" - "722067657474696e67206669656c643a204669656c6420646174613a204572726f723a204572726f72206765747469" - "6e67206b65796c65743a202424242424205354415254494e47205741534d20455845435554494f4e20242424242441" - "63636f756e743a44657374696e6174696f6e3a4163636f756e744163636f756e74206f626a65637420657869737473" - "2c2070726f63656564696e67207769746820657363726f772066696e6973682e54727573746c696e6554727573746c" - "696e65206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973" - "682e414d4d414d4d206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f7720" - "66696e6973682e436865636b436865636b206f626a656374206578697374732c2070726f63656564696e6720776974" - "6820657363726f772066696e6973682e7465726d73616e64636f6e646974696f6e7343726564656e7469616c437265" - "64656e7469616c206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066" - "696e6973682e44656c656761746544656c6567617465206f626a656374206578697374732c2070726f63656564696e" - "67207769746820657363726f772066696e6973682e4465706f736974507265617574684465706f7369745072656175" - "7468206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e697368" - "2e444944444944206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066" - "696e6973682e457363726f77457363726f77206f626a656374206578697374732c2070726f63656564696e67207769" - "746820657363726f772066696e6973682e4d505449737375616e63654d505449737375616e6365206f626a65637420" - "6578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e4d50546f6b656e4d50" - "546f6b656e206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e" - "6973682e4e46546f6b656e4f666665724e46546f6b656e4f66666572206f626a656374206578697374732c2070726f" - "63656564696e67207769746820657363726f772066696e6973682e4f666665724f66666572206f626a656374206578" - "697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e5061794368616e6e656c50" - "61794368616e6e656c206f626a656374206578697374732c2070726f63656564696e67207769746820657363726f77" - "2066696e6973682e5065726d697373696f6e6564446f6d61696e5065726d697373696f6e6564446f6d61696e206f62" - "6a656374206578697374732c2070726f63656564696e67207769746820657363726f772066696e6973682e5369676e" - "65724c6973745369676e65724c697374206f626a656374206578697374732c2070726f63656564696e672077697468" - "20657363726f772066696e6973682e5469636b65745469636b6574206f626a656374206578697374732c2070726f63" - "656564696e67207769746820657363726f772066696e6973682e5661756c745661756c74206f626a65637420657869" - "7374732c2070726f63656564696e67207769746820657363726f772066696e6973682e43757272656e742073657120" - "76616c75653a004d0970726f64756365727302086c616e6775616765010452757374000c70726f6365737365642d62" - "79010572757374631d312e38372e30202831373036376539616320323032352d30352d303929002c0f746172676574" - "5f6665617475726573022b0f6d757461626c652d676c6f62616c732b087369676e2d657874"; - -extern std::string const kCodecovTestsWasmHex = - "0061736d0100000001570b60067f7f7f7f7f7f017f60047f7f7f7f017f60027f7f017f60037f7f7f017f60077f7f7f" - "7f7f7f7f017f60057f7f7f7f7f017f60087f7f7f7f7f7f7f7f017f60017f017f60037f7f7e017f60047f7f7f7f0060" - "00017f02c60a3b08686f73745f6c6962057472616365000508686f73745f6c69620974726163655f6e756d00080868" - "6f73745f6c69620a6c6467725f696e646578000208686f73745f6c696210706172656e745f6c6467725f74696d6500" - "0208686f73745f6c696210706172656e745f6c6467725f68617368000208686f73745f6c696208626173655f666565" - "000208686f73745f6c696211616d656e646d656e745f656e61626c6564000208686f73745f6c69620874785f666965" - "6c64000308686f73745f6c69620e6163636f756e74726f6f745f6964000108686f73745f6c69620863616368655f6c" - "65000308686f73745f6c69620d686f6d655f6c655f6669656c64000308686f73745f6c6962086c655f6669656c6400" - "0108686f73745f6c69620874785f696e6e6572000108686f73745f6c69620d686f6d655f6c655f696e6e6572000108" - "686f73745f6c6962086c655f696e6e6572000508686f73745f6c69620a74785f6172725f6c656e000708686f73745f" - "6c69620f686f6d655f6c655f6172725f6c656e000708686f73745f6c69620a6c655f6172725f6c656e000208686f73" - "745f6c69621074785f696e6e65725f6172725f6c656e000208686f73745f6c696215686f6d655f6c655f696e6e6572" - "5f6172725f6c656e000208686f73745f6c6962106c655f696e6e65725f6172725f6c656e000308686f73745f6c6962" - "087365745f64617461000208686f73745f6c69620b7368613531325f68616c66000108686f73745f6c696209636865" - "636b5f736967000008686f73745f6c6962076e66745f757269000008686f73745f6c69620a6e66745f697373756572" - "000108686f73745f6c6962096e66745f7461786f6e000108686f73745f6c6962096e66745f666c616773000208686f" - "73745f6c69620c6e66745f786665725f666565000208686f73745f6c69620a6e66745f73657269616c000108686f73" - "745f6c69620a74726163655f61636374000108686f73745f6c69620974726163655f616d74000108686f73745f6c69" - "6208636865636b5f6964000008686f73745f6c69620f666c6f61745f66726f6d5f75696e74000508686f73745f6c69" - "620c74727573746c696e655f6964000608686f73745f6c696206616d6d5f6964000008686f73745f6c69620d637265" - "64656e7469616c5f6964000608686f73745f6c69620a6d70746f6b656e5f6964000008686f73745f6c69620c747261" - "63655f78666c6f6174000108686f73745f6c696209666c6f61745f636d70000108686f73745f6c696209666c6f6174" - "5f616464000408686f73745f6c696209666c6f61745f737562000408686f73745f6c69620a666c6f61745f6d756c74" - "000408686f73745f6c696209666c6f61745f646976000408686f73745f6c69620a666c6f61745f726f6f7400000868" - "6f73745f6c696209666c6f61745f706f77000008686f73745f6c696209657363726f775f6964000008686f73745f6c" - "69620f6d70745f69737375616e63655f6964000008686f73745f6c69620c6e66745f6f666665725f6964000008686f" - "73745f6c6962086f666665725f6964000008686f73745f6c6962096f7261636c655f6964000008686f73745f6c6962" - "0a7061796368616e5f6964000608686f73745f6c6962167065726d697373696f6e65645f646f6d61696e5f69640000" - "08686f73745f6c6962097469636b65745f6964000008686f73745f6c6962087661756c745f6964000008686f73745f" - "6c69620b64656c65676174655f6964000008686f73745f6c6962126465706f7369745f707265617574685f69640000" - "08686f73745f6c6962066469645f6964000108686f73745f6c69620a7369676e6572735f69640001030302090a0503" - "0100110619037f01418080c0000b7f0041cf9bc0000b7f0041d09bc0000b073504066d656d6f727902000d65736372" - "6f775f66696e697368003c0a5f5f646174615f656e6403010b5f5f686561705f6261736503020a8c2f024600024020" - "0020014704402002200341014100410010001a20004100480d01418b80c000410b2000ad1001000b200220032000ac" - "10011a0f0b418b80c000410b2000ac1001000bc22e020b7f017e23004190026b22002400419680c000412341014100" - "410010001a20004100360260200041e0006a220241041002410441888ac000410a103b200041003602602002410410" - "03410441928ac0004110103b200041f8006a22054200370300200041f0006a22014200370300200041e8006a220642" - "0037030020004200370360200241201004412041a28ac0004110103b20004100360260200241041005410441b28ac0" - "004108103b200041106a2208428182848890a0c08001370300200041186a2209428182848890a0c080013703002000" - "41206a220a428182848890a0c080013703002000428182848890a0c0800137030841b980c000410e1006410141c780" - "c0004111103b200041086a41201006410141c780c0004111103b418180202002411410072203411446044002402000" - "412e6a200041e2006a2d00003a0000200020002900673703e8012000200041ec006a2900003700ed01200020002f00" - "603b012c200020002903e8013703a801200020002900ed013700ad012000200028006336002f200041386a20002900" - "ad01370000200020002903a80137003320054200370300200142003703002006420037030020004200370360200041" - "2c6a2205411420024120100822034120470d00200041c2006a20002d00623a0000200041f0016a2207200041ef006a" - "290000220b370300200041cf006a200b370000200041d7006a200041f7006a290000370000200041df006a200041ff" - "006a2d00003a0000200020002f01603b01402000200028006336004320002000290067370047200041406b41204100" - "1009410141d880c0004108103b2001410036020020064200370300200042003703604181802020024114100a411441" - "ba8ac000410d103b20014100360200200642003703002000420037036041014181802020024114100b411441c78ac0" - "004108103b02404100200041e4006a22046b410371220320046a220120044d0d002003044020032106034020044100" - "3a0000200441016a2104200641016b22060d000b0b200341016b4107490d000340200441003a0000200441076a4100" - "3a0000200441066a41003a0000200441056a41003a0000200441046a41003a0000200441036a41003a000020044102" - "6a41003a0000200441016a41003a0000200441086a22042001470d000b0b2001413c20036b2203417c716a22042001" - "4b0440034020014100360200200141046a22012004490d000b0b024020042003410371220320046a22064f0d002003" - "220104400340200441003a0000200441016a2104200141016b22010d000b0b200341016b4107490d00034020044100" - "3a0000200441076a41003a0000200441066a41003a0000200441056a41003a0000200441046a41003a000020044103" - "6a41003a0000200441026a41003a0000200441016a41003a0000200441086a22042006470d000b0b200041043602a0" - "01200041818020360260200041f8016a2203410036020020074200370300200042003703e80120024104200041e801" - "6a22014114100c411441cf8ac0004108103b2003410036020020074200370300200042003703e801200220002802a0" - "0120014114100d411441d78ac000410d103b2003410036020020074200370300200042003703e80141012002200028" - "02a00120014114100e411441e48ac0004108103b4189803c100f412041e080c000410a103b4189803c1010412041ea" - "80c000410f103b41014189803c1011412041f980c000410a103b200220002802a00110124120418381c0004110103b" - "200220002802a00110134120419381c0004115103b4101200220002802a0011014412041a881c0004110103b200541" - "141015411441b881c0004108103b20004180026a220642003703002003420037030020074200370300200042003703" - "e801200220002802a001200141201016412041ec8ac000410b103b41c081c000410c41cc81c000410b41d781c00041" - "0e1017410141e581c0004109103b200041c0016a200a290300370300200041b8016a2009290300370300200041b001" - "6a2008290300370300200020002903083703a801200341003b010020074200370300200042003703e8012005411420" - "0041a8016a22044120200141121018411241f78ac0004107103b2003410036020020074200370300200042003703e8" - "0120044120200141141019411441fe8ac000410a103b200041003602e8012004412020014104101a410441888bc000" - "4109103b20044120101b410841ee81c0004109103b20044120101c410a41f781c000410c103b200041003602e80120" - "04412020014104101d410441918bc000410a103b418382c000410d20054114101e4100419082c000410a103b418382" - "c000410d419a82c0004108101f410041a282c0004109103b418382c000410d41ab82c0004108101f410041b382c000" - "410e103b417f41041004417141c182c0004118103b200041003602e8012001417f10044171419b8bc0004118103b20" - "0041ea016a41003a0000200041003b01e801200141031004417d41b38bc000411e103b200041003602e80120014180" - "94ebdc031004417341d18bc000411d103b4102100f416f41d982c0004119103b417f20002802a0011012417141f282" - "c0004118103b2002417f10124171418a83c0004118103b20024181081012417441a283c0004119103b200041e094eb" - "dc036a220820002802a0011012417341bb83c0004118103b2006420037030020034200370300200742003703002000" - "42003703e8012005411420084108200141201020417341ee8bc0004114103b20064200370300200342003703002007" - "4200370300200042003703e8012005411420054114200141201020417141828cc0004116103b200642003703002003" - "420037030020074200370300200042003703e801200841082001412041001021417341988cc0004117103b20064200" - "3703002003420037030020074200370300200042003703e801200220002802a0012001412041001021417141af8cc0" - "004120103b200820002802a00141011009417341d383c0004110103b200220002802a00141011009417141e383c000" - "4112103b200642003703002003420037030020074200370300200042003703e801200820002802a001200141201008" - "417341cf8cc0004116103b200642003703002003420037030020074200370300200042003703e801200220002802a0" - "01200141201008417141e58cc0004118103b200642003703002003420037030020074200370300200042003703e801" - "2005411420054114200820002802a001200141201022417341fd8cc000411d103b2006420037030020034200370300" - "20074200370300200042003703e8012005411420054114200220002802a0012001412010224171419a8dc000411f10" - "3b200642003703002003420037030020074200370300200042003703e80141bb9bc0004114200820002802a0012001" - "41201023417341b98dc0004115103b200642003703002003420037030020074200370300200042003703e80141bb9b" - "c0004114200220002802a001200141201023417141ce8dc000411b103b200642003703002003420037030020074200" - "370300200042003703e80141bb9bc000411441f583c0004114200141201023417141e98dc0004125103b2006420037" - "03002003420037030020074200370300200042003703e801418984c000412841bb9bc0004114200141201023417141" - "8e8ec0004121103b200041dc016a2000413c6a280100360200200041d4016a200041346a2901003702002000200029" - "012c3702cc01200041808080083602c801200041003b01e801200041c8016a2209411841bb9bc00041142001410210" - "23417141af8ec000410a103b200820002802a001422a1001417341b184c0004111103b200041003b01e80141022001" - "41021007416f41b98ec0004117103b200041003b01e801410220014102100a416f41d08ec000411c103b200041003b" - "01e8014101410220014102100b416f41ec8ec0004117103b4102100f416f41d982c0004119103b41021010416f41c2" - "84c000411e103b410141021011416f41e084c0004119103b41b980c0004181081006417441f984c000411f103b41b9" - "80c00041c10010064174419885c000411a103b200041003b01e801200241810820014102100c417441838fc0004116" - "103b200041003b01e801200241810820014102100d417441998fc000411b103b200041003b01e80141012002418108" - "20014102100e417441b48fc0004116103b20024181081012417441b285c000411e103b20024181081013417441d085" - "c0004123103b410120024181081014417441f385c000411e103b200241812010154174419186c0004116103b418382" - "c00041810841cc81c000410b41d781c000410e1017417441e581c0004109103b418382c000410d41cc81c000418108" - "41d781c000410e1017417441e581c0004109103b418382c000410d41cc81c000410b41d781c0004181081017417441" - "e581c0004109103b200041003b01e8012002418108200141021016417441ca8fc0004119103b200041003b01e80141" - "bb9bc00041810841bb9bc0004114200141021023417441e38fc0004114103b200041003b01e8012005411420054114" - "2002418108200141021024417441f78fc000411b103b200041003b01e8012009418108200541142001410210254174" - "419290c000411e103b418382c000410d200820002802a00141001000417341a786c000410f103b200042d487b6f4c7" - "d4b1c0003700e001418382c000410d200041e095ebdc036a220441081026417341b686c0004116103b418382c00041" - "0d200820002802a001101f417341cc86c0004113103b20044108200041e0016a220841081027417341df86c0004114" - "103b20084108200441081027417341f386c0004114103b200041003b01e80120044108200841082001410241001028" - "417341b090c0004114103b200041003b01e80120084108200441082001410241001028417341c490c0004114103b20" - "0041003b01e80120044108200841082001410241001029417341d890c0004114103b200041003b01e8012008410820" - "0441082001410241001029417341ec90c0004114103b200041003b01e8012004410820084108200141024100102a41" - "73418091c0004115103b200041003b01e8012008410820044108200141024100102a4173419591c0004115103b2000" - "41003b01e8012004410820084108200141024100102b417341aa91c0004114103b200041003b01e801200841082004" - "4108200141024100102b417341be91c0004114103b200041003b01e801200441084103200141024100102c417341d2" - "91c0004114103b200041003b01e801200441084103200141024100102d417341e691c0004113103b20064200370300" - "2003420037030020074200370300200042003703e801200541142005411420014120102e417141f991c000411b103b" - "200642003703002003420037030020074200370300200042003703e801200541142005411420014120102f41714194" - "92c0004121103b200642003703002003420037030020074200370300200042003703e8012005411420054114200141" - "201030417141b592c000411e103b200642003703002003420037030020074200370300200042003703e80120054114" - "20054114200141201031417141d392c000411a103b2006420037030020034200370300200742003703002000420037" - "03e8012005411420054114200141201032417141ed92c000411b103b20064200370300200342003703002007420037" - "0300200042003703e8012005411420054114200541142001412010334171418893c000411c103b2006420037030020" - "03420037030020074200370300200042003703e8012005411420054114200141201034417141a493c0004128103b20" - "0642003703002003420037030020074200370300200042003703e8012005411420054114200141201035417141cc93" - "c000411b103b200642003703002003420037030020074200370300200042003703e801200541142005411420014120" - "1036417141e793c000411a103b200220002802a001410010094171418787c000411b103b200041003b01e801200541" - "14200220002802a0012001410210184171418194c000411a103b200041003b01e801200220002802a0012001410210" - "194171419b94c000411d103b200041003b01e801200220002802a00120014102101a417141b894c000411c103b2002" - "20002802a001101b417141a287c000411c103b200220002802a001101c417141be87c000411f103b200041003602e8" - "01200220002802a00120014104101d417141d494c000411d103b200041003b01e801200220002802a0012001410210" - "08417141f194c0004124103b200041808080083602e801200041003b018e02200220002802a001200141042000418e" - "026a2203410210204171419595c000411e103b200041003b018e02200220002802a001220620054114200220062003" - "41021024417141b395c0004124103b200041003b018e0220054114200220002802a001220620022006200341021024" - "417141d795c0004124103b200041003b018e02200220002802a00120054114200341021037417141fb95c000412210" - "3b200041003b018e0220054114200220002802a0012003410210374171419d96c0004122103b200041003b018e0220" - "0220002802a00120054114200341021038417141bf96c0004129103b200041003b018e0220054114200220002802a0" - "01200341021038417141e896c0004129103b200041003b018e02200220002802a0012003410210394171419197c000" - "411c103b200041003b018e02200220002802a0012001410420034102102e417141ad97c000411f103b200041003b01" - "8e02200220002802a0012005411441f583c0004114200341021022417141cc97c0004123103b200041003b018e0220" - "054114200220002802a00141f583c0004114200341021022417141ef97c0004123103b200041003b018e0220022000" - "2802a0012001410420034102102f4171419298c0004125103b200041003b018e0220094118200220002802a0012003" - "41021025417141b798c0004120103b200041003b018e02200220002802a00120014104200341021030417141d798c0" - "004122103b200041003b018e02200220002802a00120014104200341021031417141f998c000411e103b200041003b" - "018e02200220002802a001200141042003410210324171419799c000411f103b200041003b018e02200220002802a0" - "012005411420014104200341021033417141b699c0004121103b200041003b018e0220054114200220002802a00120" - "014104200341021033417141d799c0004121103b200041003b018e02200220002802a0012001410420034102103441" - "7141f899c000412c103b200041003b018e02200220002802a00120034102103a417141a49ac0004120103b20004100" - "3b018e02200220002802a00120014104200341021035417141c49ac000411f103b200041003b018e02200220002802" - "a00120014104200341021036417141e39ac000411e103b200041003b018e02200220002802a00141dd87c000412020" - "0341021018417141819bc000411d103b418382c000410d200220002802a001101e417141fd87c0004120103b418396" - "abdd03410d41dd87c0004120410010004173419d88c0004110103b418396abdd03410d200841081026417341ad88c0" - "004117103b418396abdd03410d20054114101e417341c488c0004115103b418396abdd03410d41ab82c0004108101f" - "417341d988c0004114103b200220002802a001200241810841001000417441ed88c000410e103b2002418108420110" - "01417441fb88c0004112103b418382c0004181082008410810264174418d89c0004115103b418382c0004181082005" - "4114101e417441a289c0004113103b418382c00041810841ab82c0004108101f417441b589c0004112103b418382c0" - "00410d200220002802a001101f417141c789c0004116103b200041003b018e02200220002802a00120054114200341" - "0210254171419e9bc000411d103b418382c000410d200220002802a00141021000417141dd89c0004114103b410141" - "0020054114101e410041f189c0004117103b20004190026a240041010f0b0b418080c000410b417f20032003417f4e" - "1bac1001000b0ba61b0200418080c0000b89046572726f725f636f64653d54455354204641494c4544242424242420" - "5354415254494e47205741534d20455845435554494f4e202424242424746573745f616d656e646d656e74616d656e" - "646d656e745f656e61626c656463616368655f6c6574785f6172725f6c656e686f6d655f6c655f6172725f6c656e6c" - "655f6172725f6c656e74785f696e6e65725f6172725f6c656e686f6d655f6c655f696e6e65725f6172725f6c656e6c" - "655f696e6e65725f6172725f6c656e7365745f6461746174657374206d65737361676574657374207075626b657974" - "657374207369676e6174757265636865636b5f7369676e66745f666c6167736e66745f786665725f66656574657374" - "696e6720747261636574726163655f61636374400000000000005f74726163655f616d744000000000000000747261" - "63655f616d745f7a65726f706172656e745f6c6467725f686173685f6e65675f70747274785f6172725f6c656e5f69" - "6e76616c69645f736669656c6474785f696e6e65725f6172725f6c656e5f6e65675f70747274785f696e6e65725f61" - "72725f6c656e5f6e65675f6c656e74785f696e6e65725f6172725f6c656e5f746f6f5f6c6f6e6774785f696e6e6572" - "5f6172725f6c656e5f7074725f6f6f6263616368655f6c655f7074725f6f6f6263616368655f6c655f77726f6e675f" - "6c656e55534430303030303030303030303030303030300041b184c0000b8a1774726163655f6e756d5f6f6f625f73" - "7472686f6d655f6c655f6172725f6c656e5f696e76616c69645f736669656c646c655f6172725f6c656e5f696e7661" - "6c69645f736669656c64616d656e646d656e745f656e61626c65645f746f6f5f6269675f736c696365616d656e646d" - "656e745f656e61626c65645f746f6f5f6c6f6e6774785f696e6e65725f6172725f6c656e5f746f6f5f6269675f736c" - "696365686f6d655f6c655f696e6e65725f6172725f6c656e5f746f6f5f6269675f736c6963656c655f696e6e65725f" - "6172725f6c656e5f746f6f5f6269675f736c6963657365745f646174615f746f6f5f6269675f736c69636574726163" - "655f6f6f625f736c69636574726163655f78666c6f61745f6f6f625f736c69636574726163655f616d745f6f6f625f" - "736c696365666c6f61745f636d705f6f6f625f736c69636531666c6f61745f636d705f6f6f625f736c696365326361" - "6368655f6c655f77726f6e675f73697a655f75696e743235366e66745f666c6167735f77726f6e675f73697a655f75" - "696e743235366e66745f786665725f6665655f77726f6e675f73697a655f75696e7432353630303030303030303030" - "3030303030303030303030303030303030303030303174726163655f616363745f77726f6e675f73697a655f616363" - "6f756e745f696474726163655f6f6f625f737472696e6774726163655f78666c6f61745f6f6f625f737472696e6774" - "726163655f616363745f6f6f625f737472696e6774726163655f616d745f6f6f625f737472696e6774726163655f74" - "6f6f5f6c6f6e6774726163655f6e756d5f746f6f5f6c6f6e6774726163655f78666c6f61745f746f6f5f6c6f6e6774" - "726163655f616363745f746f6f5f6c6f6e6774726163655f616d745f746f6f5f6c6f6e6774726163655f616d745f77" - "726f6e675f6c656e67746874726163655f696e76616c69645f61735f68657874726163655f616363745f636865636b" - "5f646573796e636c6467725f696e646578706172656e745f6c6467725f74696d65706172656e745f6c6467725f6861" - "7368626173655f666565686f6d655f6c655f6669656c646c655f6669656c6474785f696e6e6572686f6d655f6c655f" - "696e6e65726c655f696e6e65727368613531325f68616c666e66745f7572696e66745f6973737565726e66745f7461" - "786f6e6e66745f73657269616c706172656e745f6c6467725f686173685f6e65675f6c656e706172656e745f6c6467" - "725f686173685f6275665f746f6f5f736d616c6c706172656e745f6c6467725f686173685f6c656e5f746f6f5f6c6f" - "6e67636865636b5f69645f6f6f625f6c656e5f753332636865636b5f69645f77726f6e675f6c656e5f753332666c6f" - "61745f66726f6d5f75696e745f6c656e5f6f6f62666c6f61745f66726f6d5f75696e745f77726f6e675f6c656e5f75" - "696e7436346163636f756e74726f6f745f69645f6c656e5f6f6f626163636f756e74726f6f745f69645f77726f6e67" - "5f6c656e74727573746c696e655f69645f6c656e5f6f6f625f63757272656e637974727573746c696e655f69645f77" - "726f6e675f6c656e5f63757272656e6379616d6d5f69645f6c656e5f6f6f625f617373657432616d6d5f69645f6c65" - "6e5f77726f6e675f6c656e5f617373657432616d6d5f69645f6c656e5f77726f6e675f6e6f6e5f7872705f63757272" - "656e63795f6c656e616d6d5f69645f6c656e5f77726f6e675f7872705f63757272656e63795f6c656e616d6d5f6964" - "5f6d707474785f6669656c645f696e76616c69645f736669656c64686f6d655f6c655f6669656c645f696e76616c69" - "645f736669656c646c655f6669656c645f696e76616c69645f736669656c6474785f696e6e65725f746f6f5f626967" - "5f736c696365686f6d655f6c655f696e6e65725f746f6f5f6269675f736c6963656c655f696e6e65725f746f6f5f62" - "69675f736c6963657368613531325f68616c665f746f6f5f6269675f736c696365616d6d5f69645f746f6f5f626967" - "5f736c69636563726564656e7469616c5f69645f746f6f5f6269675f736c6963656d70746f6b656e5f69645f746f6f" - "5f6269675f736c6963655f6d70746964666c6f61745f6164645f6f6f625f736c69636531666c6f61745f6164645f6f" - "6f625f736c69636532666c6f61745f7375625f6f6f625f736c69636531666c6f61745f7375625f6f6f625f736c6963" - "6532666c6f61745f6d756c745f6f6f625f736c69636531666c6f61745f6d756c745f6f6f625f736c69636532666c6f" - "61745f6469765f6f6f625f736c69636531666c6f61745f6469765f6f6f625f736c69636532666c6f61745f726f6f74" - "5f6f6f625f736c696365666c6f61745f706f775f6f6f625f736c696365657363726f775f69645f77726f6e675f7369" - "7a655f75696e7433326d70745f69737375616e63655f69645f77726f6e675f73697a655f75696e7433326e66745f6f" - "666665725f69645f77726f6e675f73697a655f75696e7433326f666665725f69645f77726f6e675f73697a655f7569" - "6e7433326f7261636c655f69645f77726f6e675f73697a655f75696e7433327061796368616e5f69645f77726f6e67" - "5f73697a655f75696e7433327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f73697a655f75" - "696e7433327469636b65745f69645f77726f6e675f73697a655f75696e7433327661756c745f69645f77726f6e675f" - "73697a655f75696e7433326e66745f7572695f77726f6e675f73697a655f75696e743235366e66745f697373756572" - "5f77726f6e675f73697a655f75696e743235366e66745f7461786f6e5f77726f6e675f73697a655f75696e74323536" - "6e66745f73657269616c5f77726f6e675f73697a655f75696e743235366163636f756e74726f6f745f69645f77726f" - "6e675f73697a655f6163636f756e745f6964636865636b5f69645f77726f6e675f73697a655f6163636f756e745f69" - "6463726564656e7469616c5f69645f77726f6e675f73697a655f6163636f756e745f69643163726564656e7469616c" - "5f69645f77726f6e675f73697a655f6163636f756e745f69643264656c65676174655f69645f77726f6e675f73697a" - "655f6163636f756e745f69643164656c65676174655f69645f77726f6e675f73697a655f6163636f756e745f696432" - "6465706f7369745f707265617574685f69645f77726f6e675f73697a655f6163636f756e745f6964316465706f7369" - "745f707265617574685f69645f77726f6e675f73697a655f6163636f756e745f6964326469645f69645f77726f6e67" - "5f73697a655f6163636f756e745f6964657363726f775f69645f77726f6e675f73697a655f6163636f756e745f6964" - "74727573746c696e655f69645f77726f6e675f73697a655f6163636f756e745f69643174727573746c696e655f6964" - "5f77726f6e675f73697a655f6163636f756e745f6964326d70745f69737375616e63655f69645f77726f6e675f7369" - "7a655f6163636f756e745f69646d70746f6b656e5f69645f77726f6e675f73697a655f6163636f756e745f69646e66" - "745f6f666665725f69645f77726f6e675f73697a655f6163636f756e745f69646f666665725f69645f77726f6e675f" - "73697a655f6163636f756e745f69646f7261636c655f69645f77726f6e675f73697a655f6163636f756e745f696470" - "61796368616e5f69645f77726f6e675f73697a655f6163636f756e745f6964317061796368616e5f69645f77726f6e" - "675f73697a655f6163636f756e745f6964327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f" - "73697a655f6163636f756e745f69647369676e6572735f69645f77726f6e675f73697a655f6163636f756e745f6964" - "7469636b65745f69645f77726f6e675f73697a655f6163636f756e745f69647661756c745f69645f77726f6e675f73" - "697a655f6163636f756e745f69646e66745f7572695f77726f6e675f73697a655f6163636f756e745f69646d70746f" - "6b656e5f69645f6d707469645f77726f6e675f6c656e677468004d0970726f64756365727302086c616e6775616765" - "010452757374000c70726f6365737365642d6279010572757374631d312e38372e3020283137303637653961632032" - "3032352d30352d303929002c0f7461726765745f6665617475726573022b0f6d757461626c652d676c6f62616c732b" - "087369676e2d657874"; - -extern std::string const kBadAlignWasmHex = - "0061736d01000000011b046000017f60057f7f7f7f7f017f60067f7f7f7f7f7f017f60000002260203656e760f666c" - "6f61745f66726f6d5f75696e74000103656e7608636865636b5f6964000203050403000000050301000306470b7f00" - "4180080b7f00418088020b7f004180080b7f00418088040b7f00418088040b7f00418088080b7f004180080b7f0041" - "8088080b7f004180800c0b7f0041000b7f0041010b07cc0110066d656d6f72790200115f5f7761736d5f63616c6c5f" - "63746f72730002057465737431000307655f64617461310300057465737432000407655f6461746132030104746573" - "7400050c5f5f64736f5f68616e646c6503020a5f5f646174615f656e6403030b5f5f737461636b5f6c6f7703040c5f" - "5f737461636b5f6869676803050d5f5f676c6f62616c5f6261736503060b5f5f686561705f6261736503070a5f5f68" - "6561705f656e6403080d5f5f6d656d6f72795f6261736503090c5f5f7461626c655f62617365030a0a99020402000b" - "2801017f418108427f370000418108410841a308410c41001000220041a40828020020004100481b0b5f01017f419a" - "88024191a4cca00136010041928802428994ace0d0c1c38710370100418a88024281848ca0d0c0c183083701004181" - "8802417f360000418a8802411441818802410441a3880241201001220041a4880228020020004100481b0b8a010103" - "7f418108427f370000418108410841a308410c410010002100419a88024191a4cca00136010041928802428994ace0" - "d0c1c38710370100418a88024281848ca0d0c0c1830837010041818802417f36000041a4082802002101418a880241" - "1441818802410441a3880241201001220241a4880228020020024100481b2000200120004100481b6a0b007f097072" - "6f647563657273010c70726f6365737365642d62790105636c616e675f31392e312e352d776173692d73646b202868" - "747470733a2f2f6769746875622e636f6d2f6c6c766d2f6c6c766d2d70726f6a656374206162346235613264623538" - "32393538616631656533303861373930636664623432626432343732302900490f7461726765745f66656174757265" - "73042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f7265666572656e63652d74797065732b" - "0a6d756c746976616c7565"; diff --git a/src/test/app/wasm_fixtures/fixtures.h b/src/test/app/wasm_fixtures/fixtures.h deleted file mode 100644 index 4a3461a1fe..0000000000 --- a/src/test/app/wasm_fixtures/fixtures.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -// TODO: consider moving these to separate files (and figure out the build) - -#include - -extern std::string const kLedgerSqnWasmHex; -extern std::string const kAllHostFunctionsWasmHex; -extern std::string const kAllKeyletsWasmHex; -extern std::string const kCodecovTestsWasmHex; - -extern std::string const kBadAlignWasmHex; diff --git a/src/test/app/wasm_fixtures/ledgerSqn.c b/src/test/app/wasm_fixtures/ledgerSqn.c deleted file mode 100644 index 0f4c27af7d..0000000000 --- a/src/test/app/wasm_fixtures/ledgerSqn.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -int32_t ldgr_index(uint8_t *, int32_t); - -int escrow_finish() -{ - uint32_t sqn; - int32_t result = ldgr_index((uint8_t *)&sqn, sizeof(sqn)); - - if (result < 0) - return result; - - return sqn >= 5 ? 5 : 0; -} diff --git a/src/test/basics/RustInterop_test.cpp b/src/test/basics/RustInterop_test.cpp deleted file mode 100644 index f3362027bc..0000000000 --- a/src/test/basics/RustInterop_test.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -#include - -namespace xrpl { - -class RustInterop_test : public beast::unit_test::Suite -{ -public: - void - testHelloWorld() - { - testcase("hello_world"); - auto result = rs::hello_world::hello_world(); - BEAST_EXPECT(result == "hello_world"); - } - - void - run() override - { - testHelloWorld(); - } -}; - -BEAST_DEFINE_TESTSUITE(RustInterop, basics, xrpl); - -} // namespace xrpl