diff --git a/.cspell.config.yaml b/.cspell.config.yaml index fdc379daa5..4e91dee24f 100644 --- a/.cspell.config.yaml +++ b/.cspell.config.yaml @@ -7,7 +7,6 @@ ignorePaths: - cmake/** - LICENSE.md - .clang-tidy - - src/test/app/wasm_fixtures/*.c - nix/check-tools/*.txt # generated, and full of Nix store hashes language: en allowCompoundWords: true # TODO (#6334) diff --git a/.github/scripts/levelization/results/ordering.txt b/.github/scripts/levelization/results/ordering.txt index 5577c363fd..e8ccb8a290 100644 --- a/.github/scripts/levelization/results/ordering.txt +++ b/.github/scripts/levelization/results/ordering.txt @@ -1,6 +1,9 @@ benchmarks.libxrpl > xrpl.basics benchmarks.libxrpl > xrpl.config benchmarks.libxrpl > xrpl.nodestore +benchmarks.libxrpl > xrpl.protocol +benchmarks.libxrpl > xrpl.protocol_autogen +benchmarks.libxrpl > xrpl.tx libxrpl.basics > xrpl.basics libxrpl.conditions > xrpl.basics libxrpl.conditions > xrpl.conditions diff --git a/cmake/XrplAddBenchmark.cmake b/cmake/XrplAddBenchmark.cmake index 921deb0658..a09db01c46 100644 --- a/cmake/XrplAddBenchmark.cmake +++ b/cmake/XrplAddBenchmark.cmake @@ -29,6 +29,14 @@ function(xrpl_add_benchmark name) # XrplCore.cmake. Each file compiles fine on its own. set_target_properties(${target} PROPERTIES UNITY_BUILD OFF) + # Land next to `xrpl_tests` in the build root rather than buried under + # `src/benchmarks/libxrpl/`. A benchmark is something a person runs by hand, + # repeatedly, and comparing two of them should not mean typing two long paths. + set_target_properties( + ${target} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + ) + isolate_headers( ${target} "${CMAKE_SOURCE_DIR}/src" diff --git a/crates/Cargo.lock b/crates/Cargo.lock index ddfd05bc00..dc45bd9a24 100644 --- a/crates/Cargo.lock +++ b/crates/Cargo.lock @@ -476,6 +476,7 @@ version = "0.1.0" dependencies = [ "cxx", "wat", + "xrpl-host-functions", ] [[package]] diff --git a/crates/xrpl-wasm-testkit/Cargo.toml b/crates/xrpl-wasm-testkit/Cargo.toml index 06c1e7c366..21b929bae1 100644 --- a/crates/xrpl-wasm-testkit/Cargo.toml +++ b/crates/xrpl-wasm-testkit/Cargo.toml @@ -9,3 +9,4 @@ crate-type = ["staticlib", "rlib"] [dependencies] cxx.workspace = true wat = "1" +xrpl-host-functions = { path = "../xrpl-host-functions" } diff --git a/crates/xrpl-wasm-testkit/src/lib.rs b/crates/xrpl-wasm-testkit/src/lib.rs index f503294c59..58c109dd61 100644 --- a/crates/xrpl-wasm-testkit/src/lib.rs +++ b/crates/xrpl-wasm-testkit/src/lib.rs @@ -19,6 +19,18 @@ mod ffi { /// Throws `rust::Error` on invalid input, which is what a test wants: a typo in a /// fixture should fail the test that holds it, at the line that holds it. fn compile_wat(wat: &str) -> Result>; + + /// The gas a host function is charged before it runs, by its guest import name. + /// + /// For the C++ gas benchmarks, which measure what a host call actually costs and + /// report it against what the table says it costs. Reading the declaration through + /// here rather than copying the numbers into C++ is the point: 61 transcribed + /// constants would drift from `lib.rs` the first time a price changed, and drift + /// silently, because a benchmark has nothing to fail. + /// + /// Throws `rust::Error` on an unknown name — a typo should fail loudly rather than + /// quietly compare against zero. + fn host_function_gas(wasm_name: &str) -> Result; } } @@ -26,9 +38,28 @@ fn compile_wat(wat: &str) -> Result, wat::Error> { wat::parse_str(wat) } +fn host_function_gas(wasm_name: &str) -> Result { + xrpl_host_functions::HostFunctionSpec::ALL + .iter() + .find(|op| op.wasm_name() == wasm_name) + .map(|op| op.gas()) + .ok_or_else(|| UnknownHostFunction(wasm_name.to_owned())) +} + +#[derive(Debug)] +struct UnknownHostFunction(String); + +impl std::fmt::Display for UnknownHostFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "no host function is imported as `{}`", self.0) + } +} + +impl std::error::Error for UnknownHostFunction {} + #[cfg(test)] mod tests { - use super::compile_wat; + use super::*; #[test] fn a_module_assembles_to_something_beginning_with_the_wasm_magic() { @@ -37,6 +68,33 @@ mod tests { assert_eq!(&wasm[..4], b"\0asm"); } + #[test] + fn a_host_function_reports_the_gas_its_declaration_gives_it() { + // `trace` is the cheapest declaration in the table; the point is not the number but + // that the lookup reaches the same constant the engine charges from. + assert_eq!( + host_function_gas("trace").expect("trace is a host function"), + xrpl_host_functions::HostFunctionSpec::Trace.gas() + ); + } + + #[test] + fn every_host_function_is_reachable_by_its_import_name() { + for op in xrpl_host_functions::HostFunctionSpec::ALL { + assert_eq!( + host_function_gas(op.wasm_name()).expect("declared"), + op.gas(), + "{} must be reachable by name", + op.wasm_name() + ); + } + } + + #[test] + fn an_unknown_name_is_an_error_rather_than_zero_gas() { + host_function_gas("not_a_host_function").expect_err("must not resolve"); + } + #[test] fn a_typo_is_an_error_rather_than_a_module() { let error = compile_wat("(module (func (export").expect_err("must not assemble"); diff --git a/crates/xrpl-wasm-vm/tests/host_calls.rs b/crates/xrpl-wasm-vm/tests/host_calls.rs index f5dd801c84..b6f1bd36d8 100644 --- a/crates/xrpl-wasm-vm/tests/host_calls.rs +++ b/crates/xrpl-wasm-vm/tests/host_calls.rs @@ -1247,3 +1247,142 @@ fn the_outcome_carries_whatever_the_guest_returned() { assert_eq!(outcome.result, value); } } + +/// The remaining binary operators marshal like `float_add`: both operands and the mode reach +/// the host, tagged by operator. +#[test] +fn float_sub_reads_both_operands_and_the_mode() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let wat = module( + &[import::FLOAT_SUB, ONE_PAGE], + "(call $float_sub (i32.const 0) (i32.const 8) (i32.const 8) (i32.const 8) (i32.const 64) (i32.const 8) (i32.const 2))", + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!( + *host.float_binary_ops_asked.borrow(), + vec![("sub", vec![0u8; 8], vec![0u8; 8], 2)] + ); +} + +#[test] +fn float_mult_reads_both_operands_and_the_mode() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let wat = module( + &[import::FLOAT_MULT, ONE_PAGE], + "(call $float_mult (i32.const 0) (i32.const 8) (i32.const 8) (i32.const 8) (i32.const 64) (i32.const 8) (i32.const 2))", + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!( + *host.float_binary_ops_asked.borrow(), + vec![("mult", vec![0u8; 8], vec![0u8; 8], 2)] + ); +} + +#[test] +fn float_div_reads_both_operands_and_the_mode() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let wat = module( + &[import::FLOAT_DIV, ONE_PAGE], + "(call $float_div (i32.const 0) (i32.const 8) (i32.const 8) (i32.const 8) (i32.const 64) (i32.const 8) (i32.const 2))", + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!( + *host.float_binary_ops_asked.borrow(), + vec![("div", vec![0u8; 8], vec![0u8; 8], 2)] + ); +} + +#[test] +fn float_pow_reads_the_float_the_degree_and_the_mode() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let wat = module( + &[import::FLOAT_POW, ONE_PAGE], + "(call $float_pow (i32.const 0) (i32.const 8) (i32.const 3) (i32.const 64) (i32.const 8) (i32.const 1))", + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!( + *host.float_unary_ops_asked.borrow(), + vec![("pow", vec![0u8; 8], 3, 1)] + ); +} + +/// The `ST*`-in operators read one serialized region and a mode, and write the float. +#[test] +fn float_from_stamount_reads_the_amount_and_the_mode() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let wat = module( + &[import::FLOAT_FROM_STAMOUNT, ONE_PAGE], + "(call $float_from_stamount (i32.const 0) (i32.const 8) (i32.const 64) (i32.const 8) (i32.const 2))", + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!( + *host.float_from_stamount_asked.borrow(), + vec![(vec![0u8; 8], 2)] + ); +} + +#[test] +fn float_from_stnumber_reads_the_number_and_the_mode() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let wat = module( + &[import::FLOAT_FROM_STNUMBER, ONE_PAGE], + "(call $float_from_stnumber (i32.const 0) (i32.const 8) (i32.const 64) (i32.const 8) (i32.const 2))", + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!( + *host.float_from_stnumber_asked.borrow(), + vec![(vec![0u8; 8], 2)] + ); +} + +/// `float_to_int` reads a float and a mode, writing the integer. +#[test] +fn float_to_int_reads_the_float_and_the_mode() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let wat = module( + &[import::FLOAT_TO_INT, ONE_PAGE], + "(call $float_to_int (i32.const 0) (i32.const 8) (i32.const 64) (i32.const 8) (i32.const 2))", + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!(*host.float_to_int_asked.borrow(), vec![(vec![0u8; 8], 2)]); +} + +/// `float_from_mant_exp` passes two scalars (an i64 mantissa and an i32 exponent) and a mode. +#[test] +fn float_from_mant_exp_passes_the_mantissa_exponent_and_mode() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let wat = module( + &[import::FLOAT_FROM_MANT_EXP, ONE_PAGE], + "(call $float_from_mant_exp (i64.const 42) (i32.const 3) (i32.const 64) (i32.const 8) (i32.const 1))", + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!(*host.float_from_mant_exp_asked.borrow(), vec![(42, 3, 1)]); +} + +/// A host input read from an unaligned pointer arrives intact: the host reads a byte slice, not +/// an aligned word, so a contract that hands it an odd offset is served the right bytes. (Ports +/// the old `bad_align` fixture, which exercised unaligned reads in the C-ABI wrapper.) +#[test] +fn an_unaligned_input_is_read_intact() { + let host = FakeHost::new().answering_float(support::Answer::filler(8)); + let stores: String = (0..8u8) + .map(|i| { + format!( + "(i32.store8 (i32.const {}) (i32.const {}))", + i + 1, + 0xa0 + i + ) + }) + .collect(); + let wat = module( + &[import::FLOAT_FROM_STAMOUNT, ONE_PAGE], + &format!( + "{stores} (call $float_from_stamount (i32.const 1) (i32.const 8) (i32.const 64) (i32.const 8) (i32.const 0))" + ), + ); + assert_eq!(status(&wat, &host), 8); + assert_eq!( + *host.float_from_stamount_asked.borrow(), + vec![((0xa0u8..0xa8u8).collect::>(), 0)] + ); +} diff --git a/crates/xrpl-wasm-vm/tests/preflight.rs b/crates/xrpl-wasm-vm/tests/preflight.rs index 705252e0e9..46a9bd5450 100644 --- a/crates/xrpl-wasm-vm/tests/preflight.rs +++ b/crates/xrpl-wasm-vm/tests/preflight.rs @@ -593,3 +593,61 @@ fn a_memory64_memory_is_refused_by_screening() { "{refusal}" ); } + +/// The corruption fixtures below are written as hex strings, which is how the old Beast suite +/// carried them — the bytes are deliberately malformed, so there is nothing to assemble them +/// from. +fn hex(s: &str) -> Vec { + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) + .collect() +} + +/// Malformed modules crafted to abuse the parser rather than merely be invalid — a vector +/// length that lies about its size, a section that overruns its payload, a locals-count bomb, +/// and a non-terminating LEB128 — are refused at compile like any other garbage. These guard +/// the parser against resource-exhaustion shapes (ported from the old Beast section-corruption +/// fixtures); the plainer "bad magic / wrong version" shapes are covered by `garbage_does_not_pass`. +#[test] +fn parser_abuse_shapes_are_refused() { + let cases = [ + ("vector length lies", "0061736d010000000105ffffffff0f"), + ("section overruns its payload", "0061736d01000000010a0160"), + ( + "locals-count bomb", + "0061736d01000000010401600000030201000a0f010d01ffffffff0f7f0b", + ), + ( + "non-terminating LEB128", + "0061736d0100000001058080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080", + ), + ]; + for (label, h) in cases { + let refusal = xrpl_wasm_vm::check(&hex(h), ENTRY).expect_err(label); + assert_stage!(refusal, CheckError::Compile(_)); + } +} + +/// The plain structurally-malformed modules from the old section-corruption fixtures — a +/// corrupt magic, a wrong version, a lying section length, sections out of order, junk after +/// the last section, an unknown section id — are all refused at compile. Belt-and-suspenders +/// alongside `garbage_does_not_pass`: guards against a wasmi upgrade loosening the validator. +#[test] +fn structurally_malformed_modules_are_refused() { + let cases = [ + ("corrupt magic number", "0161736d01000000"), + ("wrong version", "0061736d02000000"), + ("lying section length", "0061736d01000000018080808008"), + ("sections out of order", "0061736d010000000a02000b03020000"), + ( + "junk after last section", + "0061736d01000000010a01600000000000000000", + ), + ("unknown section id", "0061736d01000000ff0100"), + ]; + for (label, h) in cases { + let refusal = xrpl_wasm_vm::check(&hex(h), ENTRY).expect_err(label); + assert_stage!(refusal, CheckError::Compile(_)); + } +} diff --git a/crates/xrpl-wasm-vm/tests/vm_limits.rs b/crates/xrpl-wasm-vm/tests/vm_limits.rs index 52a8314a65..bcbfa7218d 100644 --- a/crates/xrpl-wasm-vm/tests/vm_limits.rs +++ b/crates/xrpl-wasm-vm/tests/vm_limits.rs @@ -598,3 +598,114 @@ fn a_memory64_module_is_rejected_at_compile() { "rejected before instantiation, so nothing is charged: {failure}" ); } + +/// A function declaring more parameters than wasm allows (1000) is refused at compile, so a +/// contract cannot smuggle an unbounded signature past screening. +#[test] +fn a_function_with_too_many_params_is_refused() { + let host = FakeHost::new(); + let params = " i32".repeat(1001); + let wat = format!( + "(module {ONE_PAGE} (func (param{params}) (result i32) (i32.const 0)) \ + (func (export \"finish\") (result i32) (i32.const 0)))" + ); + assert_stage!(failure(&wat, &host), RunError::Compile(_)); +} + +/// A function declaring more locals than wasm allows (50 000) is refused at compile. +#[test] +fn a_function_with_too_many_locals_is_refused() { + let host = FakeHost::new(); + let locals = format!("(local{})", " i32".repeat(50_001)); + let wat = module(&[ONE_PAGE], &format!("{locals} (i32.const 0)")); + assert_stage!(failure(&wat, &host), RunError::Compile(_)); +} + +/// Below the compile cap but past the engine's register frame, a locals-heavy function is +/// refused when the frame is built rather than at compile — still refused, just later. +#[test] +fn a_function_past_the_register_frame_is_refused() { + let host = FakeHost::new(); + let locals = format!("(local{})", " i32".repeat(40_000)); + let wat = module(&[ONE_PAGE], &format!("{locals} (i32.const 0)")); + assert_stage!(failure(&wat, &host), RunError::Trap(_)); +} + +/// Unbounded recursion is stopped by the engine's call-stack limit — it traps rather than +/// running the host's native stack off the end (the portable dispatcher makes loops safe; +/// this pins that guest *calls* are bounded too). +#[test] +fn unbounded_recursion_is_stopped_by_the_call_stack_limit() { + let host = FakeHost::new(); + let wat = format!( + "(module {ONE_PAGE} \ + (func $rec (param i32) (result i32) \ + (if (result i32) (i32.eqz (local.get 0)) (then (i32.const 0)) \ + (else (call $rec (i32.sub (local.get 0) (i32.const 1)))))) \ + (func (export \"finish\") (result i32) (call $rec (i32.const 1000000))))" + ); + assert_stage!(failure(&wat, &host), RunError::Trap(_)); +} + +/// A module with many functions currently compiles and runs: wasmi's only cap is its +/// 1,000,000 hard limit, so the ticket's ~24k-function module — a CodeMap-growth DoS, since +/// every validation appends to the engine's append-only CodeMap — is not refused here. +/// Enforcing a tighter bound (a function-count / average-bytes-per-function limit) belongs in +/// a future preflight pass that parses the module before the engine sees it. Ignored until +/// then, so this documents the gap without asserting it is acceptable. +#[test] +#[ignore = "CodeMap-DoS unmitigated; a function-count limit is deferred to preflight parsing"] +fn many_functions_currently_run_unbounded() { + let host = FakeHost::new(); + let funcs: String = (0..24_000) + .map(|i| format!("(func $f{i} (result i32) (i32.const {}))", i % 7)) + .collect(); + let wat = + format!("(module {ONE_PAGE} {funcs} (func (export \"finish\") (result i32) (call $f0)))"); + assert!( + run(&wat, &host).is_ok(), + "a large-function module currently compiles and runs" + ); +} + +/// The trap *kinds* wasmi distinguishes all reach the caller identically — a guest trap +/// charged as the contract's fault — so the `unreachable` representative pins the mapping. +/// These pin the individual kinds too, guarding against a wasmi upgrade reclassifying any of +/// them as something other than a trap. +#[test] +fn a_division_by_zero_traps() { + let host = FakeHost::new(); + let wat = module(&[ONE_PAGE], "(i32.div_s (i32.const 1) (i32.const 0))"); + assert_stage!(failure(&wat, &host), RunError::Trap(_)); +} + +#[test] +fn a_signed_integer_overflow_traps() { + let host = FakeHost::new(); + let wat = module( + &[ONE_PAGE], + "(i32.div_s (i32.const 0x80000000) (i32.const -1))", + ); + assert_stage!(failure(&wat, &host), RunError::Trap(_)); +} + +#[test] +fn an_indirect_call_to_a_null_table_entry_traps() { + let host = FakeHost::new(); + let wat = format!( + "(module {ONE_PAGE} (type $t (func (result i32))) (table 1 funcref) \ + (func (export \"finish\") (result i32) (call_indirect (type $t) (i32.const 0))))" + ); + assert_stage!(failure(&wat, &host), RunError::Trap(_)); +} + +#[test] +fn an_indirect_call_with_a_mismatched_signature_traps() { + let host = FakeHost::new(); + let wat = format!( + "(module {ONE_PAGE} (type $void (func)) (type $i32 (func (result i32))) \ + (table 1 funcref) (elem (i32.const 0) $f) (func $f (type $void)) \ + (func (export \"finish\") (result i32) (call_indirect (type $i32) (i32.const 0))))" + ); + assert_stage!(failure(&wat, &host), RunError::Trap(_)); +} diff --git a/src/benchmarks/libxrpl/CMakeLists.txt b/src/benchmarks/libxrpl/CMakeLists.txt index ac751a0413..ab3e68b87b 100644 --- a/src/benchmarks/libxrpl/CMakeLists.txt +++ b/src/benchmarks/libxrpl/CMakeLists.txt @@ -20,3 +20,20 @@ target_link_libraries( xrpl_add_benchmark(nodestore) target_link_libraries(xrpl.bench.nodestore PRIVATE xrpl.imports.bench) add_dependencies(xrpl.benchmarks xrpl.bench.nodestore) + +# Gas calibration for the wasm host functions. The ledger and real host come from +# `xrpl.testkit.wasm` (built with the tests, but framework-free), so this target links +# no GTest and no GMock. +if(TARGET xrpl.testkit.wasm) + xrpl_add_benchmark(wasm) + target_link_libraries( + xrpl.bench.wasm + PRIVATE xrpl.imports.bench xrpl.testkit.wasm + ) + add_dependencies(xrpl.benchmarks xrpl.bench.wasm) +else() + message( + STATUS + "xrpl.testkit.wasm not built (tests disabled); skipping xrpl.bench.wasm." + ) +endif() diff --git a/src/benchmarks/libxrpl/wasm/BenchFixtures.cpp b/src/benchmarks/libxrpl/wasm/BenchFixtures.cpp new file mode 100644 index 0000000000..3eb9c7e35b --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/BenchFixtures.cpp @@ -0,0 +1,175 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { + +Fixtures::Fixtures() + : alice_{ledger_.fund("benchAlice")} + , bob_{ledger_.fund("benchBob")} + , signerListOwner_{ledger_.fund("benchSigners")} + , escrow_{keylet::account(AccountID{})} + , signedMessage_{signMessage("the quick brown fox jumps over the lazy dog")} + , nftId_{NftIds::makeNftId(alice_.id())} +{ + ledger_.makeSignerList(signerListOwner_, 2, {{alice_, 1}, {bob_, 1}}); + + // The escrow has to be submitted after the accounts exist, which is why it is built here + // rather than in the initializer list: its keylet depends on the owner's sequence number at + // submission time. + auto const ownerSeq = ledger_.ledger.getAccountRoot(alice_.id()).getSequence(); + auto const created = ledger_.ledger.submit( + transactions::EscrowCreateBuilder{alice_.id(), bob_.id(), XRP(100)}.setFinishAfter( + 900'000'000), + alice_); + if (created.ter != tesSUCCESS) + { + fixtureFailed(std::string{"creating the escrow: "} + transToken(created.ter)); + } + ledger_.ledger.close(); + escrow_ = keylet::escrow(alice_.id(), SeqProxy::rawSequence(ownerSeq)); +} + +Account const& +Fixtures::alice() const +{ + return alice_; +} + +Account const& +Fixtures::bob() const +{ + return bob_; +} + +TxAssembler +Fixtures::memoTx() +{ + auto assembler = escrowFinishTx(ledger_.ledger, alice_); + assembler.build = [inner = std::move(assembler.build)](STObject& obj) { + inner(obj); + auto memos = STArray{}; + memos.push_back(makeMemo(WasmLedger::toBytes("hello"))); + memos.push_back(makeMemo(WasmLedger::toBytes("world"))); + obj.setFieldArray(sfMemos, memos); + }; + return assembler; +} + +FieldLocator +Fixtures::memoLocator() +{ + return FieldLocator{{sfMemos.getCode(), 0, sfMemoData.getCode()}}; +} + +WasmHost +Fixtures::host() +{ + auto assembler = memoTx(); + return ledger_.makeHost( + keylet::account(alice_.id()), assembler.type, std::move(assembler.build)); +} + +WasmHost +Fixtures::cachedHost() +{ + auto wasmHost = host(); + if (!wasmHost->cacheLedgerObj(keylet::account(alice_.id()).key, 1).has_value()) + { + fixtureFailed("caching the account root into slot 1"); + } + return wasmHost; +} + +WasmHost +Fixtures::signerListHost() +{ + auto assembler = bareTx(); + return ledger_.makeHost( + keylet::signerList(signerListOwner_.id()), assembler.type, std::move(assembler.build)); +} + +WasmHost +Fixtures::cachedSignerListHost() +{ + auto assembler = bareTx(); + auto wasmHost = + ledger_.makeHost(keylet::account(AccountID{}), assembler.type, std::move(assembler.build)); + if (!wasmHost->cacheLedgerObj(keylet::signerList(signerListOwner_.id()).key, 1).has_value()) + { + fixtureFailed("caching the signer list into slot 1"); + } + return wasmHost; +} + +WasmHost +Fixtures::tracingHost() +{ + return ledger_.makeTracingHost(); +} + +Keylet const& +Fixtures::escrow() const +{ + return escrow_; +} + +WasmHost +Fixtures::escrowHost() +{ + return ledger_.makeHost(escrow_); +} + +Slice +Fixtures::floatX() +{ + return FloatConstants::slice(FloatConstants::kPi); +} + +Slice +Fixtures::floatY() +{ + return FloatConstants::slice(FloatConstants::kTwo); +} + +SignedMessage const& +Fixtures::signedMessage() const +{ + return signedMessage_; +} + +uint256 const& +Fixtures::nftId() const +{ + return nftId_; +} + +Fixtures& +Fixtures::instance() +{ + static Fixtures kValue; + return kValue; +} + +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/BenchFixtures.h b/src/benchmarks/libxrpl/wasm/BenchFixtures.h new file mode 100644 index 0000000000..8693a13dfd --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/BenchFixtures.h @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +#include + +namespace xrpl::test::bench { + +// The ledger and canned inputs every `*.bench.cpp` measures against. +class Fixtures +{ +public: + // The one set of fixtures every benchmark shares, built on first use. + static Fixtures& + instance(); + + // A sequence number for the keylets that take one. Arbitrary — a keylet hashes whatever it + // is given, so the value cannot change the cost. + static constexpr std::uint32_t kSeq = 42; + + // Rounding mode 0 throughout the float family: modes select a tie-breaking rule, not a + // different algorithm, so they do not move the cost, and pinning one keeps the fourteen + // comparable. + static constexpr std::int32_t kRoundingMode = 0; + + // Two funded accounts, enough for every keylet shape and every object below. + [[nodiscard]] Account const& + alice() const; + [[nodiscard]] Account const& + bob() const; + + // The default host: its transaction carries a two-element memo array (something for the + // nested getters to walk to and the array-length getters to count) and its current object is + // Alice's account root. + [[nodiscard]] WasmHost + host(); + + // The same, with Alice's account root pinned to slot 1, for the `le_*` getters that read + // through a cache slot rather than the current object. + [[nodiscard]] WasmHost + cachedHost(); + + // An account root has no arrays, so the array-length getters that read a *ledger object* + // need a different one. A signer list has `sfSignerEntries`; without it those calls would + // answer `FieldNotFound` and the benchmark would time the rejection instead of the work. + [[nodiscard]] WasmHost + signerListHost(); + [[nodiscard]] WasmHost + cachedSignerListHost(); + + // A host whose `trace` output is captured rather than dropped, so the log-enabled path can + // be measured against the log-disabled one that `host()` gives. + [[nodiscard]] WasmHost + tracingHost(); + + // A real escrow, created through the real transactor — the current object for + // `home_le_field`, the one getter whose cost depends on the object it reads rather than on + // its arguments. + [[nodiscard]] Keylet const& + escrow() const; + [[nodiscard]] WasmHost + escrowHost(); + + // `sfMemos[0].sfMemoData` — a two-step locator path, the shape the nested getters are priced + // for. + [[nodiscard]] static FieldLocator + memoLocator(); + + // Canonical float operands. Zeroed bytes decode as a non-canonical float and would be + // refused before any arithmetic ran, so the whole family shares these two known-good values. + [[nodiscard]] static Slice + floatX(); + [[nodiscard]] static Slice + floatY(); + + // A signed message for `check_sig`. Signing is far more expensive than the verification + // being measured, so it happens once here rather than inside a timed loop. + [[nodiscard]] SignedMessage const& + signedMessage() const; + + // A well-formed NFToken id with the fixture's known taxon, flags, fee and sequence baked in, + // so the id-extractor getters have real fields to pull out rather than zeros. + [[nodiscard]] uint256 const& + nftId() const; + +private: + // Order matters, and that is the reason this is a constructor rather than a pile of lazy + // statics: the accounts have to be funded before the signer list and the escrow can be built + // on them. + Fixtures(); + + // The transaction the default host runs, carrying the memo array. + [[nodiscard]] TxAssembler + memoTx(); + + WasmLedger ledger_; + Account alice_; + Account bob_; + Account signerListOwner_; + Keylet escrow_; + SignedMessage signedMessage_; + uint256 nftId_; +}; + +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/Crossing.cpp b/src/benchmarks/libxrpl/wasm/Crossing.cpp new file mode 100644 index 0000000000..d764d051b7 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/Crossing.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +// The harness checking itself. +// +// This file holds no host function — it belongs to the wasm directory rather than +// `host_functions/` because it measures the two reference points every per-function number is read +// against, and neither is a host call. +// +// `GuestInstruction` runs a contract whose "host call" is a couple of guest instructions. Its +// `implied_gas` and `charged_gas` are then two independent measurements of the same quantity — one +// from wall time via `secondsPerGas`, one from the engine's own fuel meter — and they should agree +// closely. When they diverge, `secondsPerGas` has measured something other than a guest +// instruction and no other number in the run is trustworthy. Read this first. +// +// The crossing floor is the other reference point, and it lives in `host_functions/LedgerSqn`: +// `ldgr_index` takes no input and answers from a header already in hand, so its impl is as close +// to nothing as a host function gets, and whatever its `ThroughVm` case costs above its `Impl` +// case is the price of leaving the guest — paid by every one of the 61 functions before any of +// them does any work. +// +// So the reading order across the suite is: this file, then `LedgerSqn`'s pair for the floor, then +// a function's own `Impl` number. Those three should account for its `ThroughVm` number; where +// they do not, the gap is size-dependent copying, which the swept cases (`Sha512Half`, +// `UpdateData`) expose. + +void +guestInstruction(benchmark::State& state) +{ + static constexpr std::string_view kBody = "(i32.add (local.get $r) (i32.const 1))"; + // Empty import name: this case prices no host function, so there is nothing to look a + // declaration up for and it reports no `suggested_gas`. + benchmarkThroughVm(state, "", "", "", kBody, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(guestInstruction)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/README.md b/src/benchmarks/libxrpl/wasm/README.md new file mode 100644 index 0000000000..e50afdec01 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/README.md @@ -0,0 +1,181 @@ +# WASM host functions — gas calibration + +These are **not tests**: nothing asserts, and a number moving is not a build failure. They answer +the question the tests cannot — whether each `#[gas = N]` in +`crates/xrpl-host-functions/src/lib.rs` matches what the function actually costs. + +```bash +cmake --build build --target xrpl.bench.wasm +./build/xrpl.bench.wasm # everything (~2 min) +./build/xrpl.bench.wasm --benchmark_filter=sha512Half +./build/xrpl.bench.wasm --benchmark_repetitions=25 --benchmark_report_aggregates_only=true +``` + +**Build Release.** Debug inflates the crossing far more than the impls: `Impl`-to-`Impl` ratios +survive it, `suggested_gas` does not. + +## Reading the output + +| Counter | Meaning | +| ------------------- | ---------------------------------------------------------------------------------- | +| `suggested_gas` | **the answer** — what this function should be priced at | +| `host_function_gas` | what `lib.rs` says today, read through the `wasm_testkit` bridge so it can't drift | +| `price_ratio` | `host_function_gas / suggested_gas`. **1.0 is correct; below 1 is underpriced** | +| `rel_error` | relative uncertainty of `suggested_gas`. **Quote this one** — ~1.2% when quiet | +| `unreliable` | `1` means do not act on this row | +| `implied_gas` | the raw measurement, before the crossing is added back | +| `charged_gas` | what the engine actually billed; confirms the right call was measured | +| `ns_per_call` | raw wall time, for debugging a suspicious ratio | + +Sort by `price_ratio`. **Below 1 is the direction that matters** — an underpriced call is one a +contract can buy too cheaply, a denial-of-service vector rather than a rounding error: + +```bash +./build/xrpl.bench.wasm --benchmark_format=json | + jq -r '.benchmarks[] | select(.price_ratio) | [.price_ratio, .name] | @tsv' | sort -n +``` + +`unreliable=1` when `rel_error` exceeds 25%, or when `suggested_gas` falls below the crossing floor +— a call whose own cost is small next to the crossing is read off the difference of two nearly +equal numbers. + +### With `--benchmark_repetitions` + +Adds `_mean` / `_median` / `_stddev` / `_cv` rows. One trap worth knowing: + +**`cv` on `suggested_gas` for an `Impl` case is not an error bar.** The crossing floor is measured +once per process, so repetitions never resample it — and it is most of a cheap `Impl` case's value. +Over 25 repetitions on an idle machine, `Impl` `cv` reads **1.3%** against `ThroughVm`'s 2.3%, while +`rel_error` is 1.2% for both. The lowest number in the output is the least trustworthy one. + +Use repetitions to confirm the machine is quiet and to get a median; quote `rel_error`. Under load +the `Impl` cases inflate first (3.0% against 1.8% at load ~10), which makes the gap between the two +families a usable load detector. + +## How `suggested_gas` is measured + +Gas is wasmi fuel — `set_fuel(gas)` meters guest instructions and host charges from one pool — so +one gas is about one guest instruction and the question becomes a ratio. Every step is a +subtraction, so fixed costs cancel: + +``` +secondsPerGas = (time_busy − time_idle) / (fuel_busy − fuel_idle) # pure-wasm loop, N vs 0 +implied_gas = secondsPerCall / secondsPerGas +crossing_floor = (ldgr_index ThroughVm − ldgr_index Impl) / secondsPerGas + +suggested_gas = implied_gas # ThroughVm — the guest already paid the crossing +suggested_gas = implied_gas + crossing_floor # Impl — a guest cannot call without paying it +price_ratio = host_function_gas / suggested_gas + +rel_error = sqrt( ( sqrt((implied·caseErr)² + (floor·floorErr)²) / suggested )² + perGasErr² ) +``` + +`secondsPerCall` is itself a subtraction: a `ThroughVm` case runs a contract making N host calls +against a **byte-identical** one making none, so compilation, instantiation and the guest's own loop +cancel. An `Impl` case times `kCallsPerRun` direct calls and divides. + +`secondsPerGas` is measured **once** and shared by every case, deliberately — two routes to the same +price must divide by the same constant, and per-case calibration was tried and swung 6x between +runs. Its uncertainty is propagated arithmetically instead. See the comments in `WasmBench.cpp` for +why the three terms in `rel_error` do not all combine in quadrature. + +**`guestInstruction` is the self-test — read it first.** It runs the calibration's own loop body, so +its `implied_gas` (wall time) and `charged_gas` (the fuel meter) are two independent measurements of +one quantity. Quiet Release machine: **≈13.7 against 13.007, ~5% high.** A persistent gap much +beyond that means every other number in the run shares it. It has already caught an estimator +mismatch worth +40%, and the memory leak below. + +**`suggested_gas` for an `Impl`-only case is a lower bound** — the crossing floor is measured on a +call with no input, so a function that moves bytes pays more; `Sha512Half` and `UpdateData` sweep +that per-byte term. `ThroughVm` cases are deliberately one per crossing _shape_, not one per +function. + +## VM overhead (`Vm.cpp`) + +Everything above prices what a contract _asks for_. `Vm.cpp` prices getting it running at all. Of +the seven stages `runEscrowWasm` performs — compile, store, linker, instantiate, entry-point lookup, +call, fuel read — **only the call is metered**; the rest is wall time no transaction pays for. + +These cases report `ns_per_op` and `gas_equivalent` (that time over the same `secondsPerGas`, so an +unpriced stage reads on the same axis as a priced one), plus `module_bytes` and `gas_per_byte` on +size sweeps. + +| case | measures | +| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `preflightMinimal` | compile plus the import/export walk. The narrowest view of compilation reachable from C++: no host, no instance | +| `preflightRejects` | the same on a module refused at the import walk. Against `preflightMinimal`, what refusing costs versus accepting | +| `runMinimal` | a whole run of a do-nothing contract — every stage. Minus `preflightMinimal`, the stages that are not compilation | +| `compileScaling/N` | compilation against module size: `N` unreachable filler functions, preflight only | +| `runScaling/N` | the same modules through a whole run. Paired with `compileScaling` per size, separates size-dependent stages from fixed ones | +| `instantiateScaling/pages` | declared memory at constant module size, so what moves is the host allocating and zeroing pages | + +Two of those pairings are the point of the file. `runMinimal − preflightMinimal` gives the fixed +cost of everything that is not compilation; `runScaling` against `compileScaling` shows compilation +appearing a second time, because the transactor validates and executes with no module cache between +them. The size sweeps matter more than the floor: a fixed cost is only a griefing concern if it is +large, but a slope against attacker-chosen module size is one at any height. + +Two caveats when reading a sweep. `gas_per_byte` is an **average** carrying the case's fixed cost, +not a marginal rate — it overestimates, and falls toward the true slope as the module grows, so read +the convergence rather than any single row. And the `/4096` points get few iterations and go noisy +first; compare `rel_error` across the sweep before quoting the largest one. + +The sweep stops at 4096 functions for want of a real cap to stop at — no maximum contract size is +enforced anywhere yet, the transactor not being wired. + +The linker rebuild and the fuel-metering overhead are **not** separable from here — C++ sees only +`runEscrowWasm` and `preflightEscrowWasm`. Both need benchmarks inside `xrpl-wasm-vm`, where +`compile` and `wasm_engine` are `pub(crate)`. + +### Compiling leaks — pin your iteration counts + +`wasm_engine()` is a process-global `LazyLock`, and what `Module::new` adds to it is never +released. Repeatedly preflighting one **60-byte** module: + +| `--benchmark_repetitions` | peak RSS | +| ------------------------- | -------- | +| 1 | 0.41 GB | +| 5 | 1.46 GB | +| 15 | 4.20 GB | + +Linear, at roughly **800 bytes per compile**. Within the suite this is why every `Vm.cpp` case pins +`->Iterations(...)`: automatic sizing ran `preflightMinimal` ~348k times per repetition, reaching +7.9 GB at 25 repetitions, after which every later case in the binary failed to compile — 720 errored +rows, all blaming cases that were innocent. + +**Outside the suite it is worth a look.** A validator compiles twice per programmable-escrow +transaction against that same static engine. Whether that is unbounded growth in production depends +on wasmi internals not checked here — this is the C++-visible symptom, not a diagnosis. wasmi is +pinned at `2.0.0-beta.10`, a beta, so try a version bump first. + +## Gotchas, each of which has already cost someone an afternoon + +- **The wasm ABI is not the trait's argument order.** `float_add(x, y, mode, out)` in Rust is + `(x_ptr, x_len, y_ptr, y_len, out_ptr, out_len, mode)` on the wire — scalars move _after_ the + output region. Check `register.rs`, not `lib.rs`, when writing WAT. +- **A soft host error still "succeeds".** The run completes and gas is charged _before_ the body, so + a wrong-argument case reports a plausible, confidently wrong number. The harness requires the + contract's result to be `>= 0`; the tell is a `ThroughVm` case coming out _faster_ than its `Impl`. +- **A host serves exactly one run** (`checkSelf` in `WasmVM.cpp`), so a benchmark builds a fresh host + per run and cannot pre-cache a slot. +- **`MAX_FIELD_BYTES` is 1024** — nothing crosses the boundary above 1 KiB, so size sweeps stop there. +- **Do not compare timings across builds at the cheap end.** Two builds whose timed regions were + byte-identical measured 2.18 ns and 2.52 ns for the same case — ~15% apart, from code layout alone. + Use `price_ratio` within one run, and reason from the code when judging whether a change costs + anything. +- **Every case pins `->Iterations(...)`, for two different reasons.** Host-function cases must + because with `UseManualTime` automatic sizing reads only the tiny reported residue and would ask + for millions of iterations; `Vm.cpp` cases must because compiling leaks. + +## Layout + +One `.cpp` per host function under `host_functions/`, mirroring +`src/tests/libxrpl/tx/wasm/host_functions/`, so adding a host function is a two-file checklist +rather than a judgement call. `Crossing.cpp` holds the harness's own reference points, `Vm.cpp` the +per-run overhead around them, `WasmBench.*` the measurement machinery, `BenchFixtures.*` the shared +ledger (one ledger, funded once, for the whole binary). + +The ledger and real host come from `xrpl.testkit.wasm` — a framework-free library built alongside +the tests — so this target links **no GTest and no GMock**. See +`src/tests/libxrpl/tx/wasm/README.md` for how that library is split, and why its setup steps throw +rather than using `EXPECT_`. diff --git a/src/benchmarks/libxrpl/wasm/Vm.cpp b/src/benchmarks/libxrpl/wasm/Vm.cpp new file mode 100644 index 0000000000..dd5ec2e420 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/Vm.cpp @@ -0,0 +1,149 @@ +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { +namespace { + +// What a run costs *around* the contract, rather than what its host calls cost. Only the guest's +// own execution is metered, so every stage measured here is wall time no transaction pays for. +// ../README.md has what each case measures and how to read `gas_equivalent`. +// +// **Every case must pin `->Iterations(...)`.** Compiling a module allocates against the +// process-global engine and is never reclaimed — roughly 800 bytes per compile — so Google +// Benchmark's automatic sizing, which targets a wall-clock budget rather than a compile count, +// reaches gigabytes resident and the whole binary stops being able to compile anything. + +// The smallest module the engine accepts. Everything a run does to it is overhead by construction. +std::string +minimalWat() +{ + return R"wat((module + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (i32.const 1))) +)wat"; +} + +// `count` unreachable functions on top of the minimal module: bigger without doing more. +// +// Each body is seeded with its own index so no two are identical and none folds to a constant the +// translator can drop — either would break the link between function count and byte count. +// Unreachable is fine: validation and translation visit every function a module declares, and that +// visit is exactly the cost being swept. +std::string +fillerWat(size_t count) +{ + auto out = std::string{"(module\n (memory (export \"memory\") 1)\n"}; + for (auto i = 0uz; i < count; ++i) + { + out += std::format( + " (func $f{0} (param i32) (result i32)\n" + " (i32.add (i32.mul (local.get 0) (i32.const {0})) (i32.const {0})))\n", + i); + } + out += " (func (export \"escrow_finish\") (result i32)\n (i32.const 1)))\n"; + return out; +} + +// The minimal module asking for `pages` of initial memory. `MAX_MEMORY_PAGES` is 128 (8 MiB), and a +// contract declares this for free — the host allocates and zeroes it before the first instruction. +std::string +pagesWat(size_t pages) +{ + return std::format( + "(module\n" + " (memory (export \"memory\") {})\n" + " (func (export \"escrow_finish\") (result i32)\n" + " (i32.const 1)))\n", + pages); +} + +// Compiles cleanly and is then refused: `env::malloc` is not a namespace the engine serves, so +// `check_imports` stops at it. +std::string +rejectedWat() +{ + return R"wat((module + (import "env" "malloc" (func $malloc (param i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (i32.const 1))) +)wat"; +} + +void +preflightMinimal(benchmark::State& state) +{ + static auto const kWasm = assembleWat(minimalWat()); + benchmarkPreflight(state, kWasm); +} +BENCHMARK(preflightMinimal)->UseManualTime()->Iterations(kBenchIterations); + +void +preflightRejects(benchmark::State& state) +{ + static auto const kWasm = assembleWat(rejectedWat()); + benchmarkPreflight(state, kWasm, /*expectAccepted*/ false); +} +BENCHMARK(preflightRejects)->UseManualTime()->Iterations(kBenchIterations); + +void +runMinimal(benchmark::State& state) +{ + static auto const kWasm = assembleWat(minimalWat()); + benchmarkRun(state, kWasm, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(runMinimal)->UseManualTime()->Iterations(kBenchIterations); + +void +compileScaling(benchmark::State& state) +{ + auto const wasm = assembleWat(fillerWat(static_cast(state.range(0)))); + benchmarkPreflight(state, wasm, /*expectAccepted*/ true, /*sizeSweep*/ true); +} +BENCHMARK(compileScaling) + ->UseManualTime() + ->Iterations(kBenchIterations) + ->Arg(1) + ->Arg(8) + ->Arg(64) + ->Arg(512) + ->Arg(4096); + +void +runScaling(benchmark::State& state) +{ + auto const wasm = assembleWat(fillerWat(static_cast(state.range(0)))); + benchmarkRun(state, wasm, [] { return Fixtures::instance().host(); }, /*sizeSweep*/ true); +} +BENCHMARK(runScaling) + ->UseManualTime() + ->Iterations(kBenchIterations) + ->Arg(1) + ->Arg(8) + ->Arg(64) + ->Arg(512) + ->Arg(4096); + +void +instantiateScaling(benchmark::State& state) +{ + auto const wasm = assembleWat(pagesWat(static_cast(state.range(0)))); + benchmarkRun(state, wasm, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(instantiateScaling) + ->UseManualTime() + ->Iterations(kBenchIterations) + ->Arg(1) + ->Arg(8) + ->Arg(32) + ->Arg(128); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/WasmBench.cpp b/src/benchmarks/libxrpl/wasm/WasmBench.cpp new file mode 100644 index 0000000000..e5975f2403 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/WasmBench.cpp @@ -0,0 +1,397 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xrpl::test::bench { + +int +callsWithinTransferBudget(std::int64_t bytesWrittenPerCall) +{ + // Writes nothing back to the guest, so the budget does not apply. + if (bytesWrittenPerCall <= 0) + { + return kCallsPerRun; + } + + auto const affordable = kTransferLimitBytes / bytesWrittenPerCall; + if (affordable < 1) + { + fixtureFailed("a single call would exceed the run's transfer budget"); + } + return static_cast(std::min(affordable, kCallsPerRun)); +} + +std::string +dataSegment(int offset, std::span bytes) +{ + return std::format(" (data (i32.const {}) \"{}\")\n", offset, watEscaped(bytes)); +} + +std::string +dataSegment(int offset, Bytes const& bytes) +{ + return dataSegment(offset, std::span{bytes.data(), bytes.size()}); +} + +std::string +makeLoopWat(std::string_view imports, std::string_view data, std::string_view body, int count) +{ + static constexpr auto kTemplate = R"wat((module +{} + (memory (export "memory") 1) +{} + (func (export "escrow_finish") (result i32) + (local $i i32) + (local $r i32) + (local.set $i (i32.const {})) + (block $done + (loop $again + (br_if $done (i32.eqz (local.get $i))) + (local.set $r {}) + (local.set $i (i32.sub (local.get $i) (i32.const 1))) + (br $again))) + (local.get $r))) +)wat"; + + return std::format(kTemplate, imports, data, count, body); +} + +Timing +timeRun(HostFunctions& host, Bytes const& wasm) +{ + auto const start = std::chrono::steady_clock::now(); + auto outcome = runEscrowWasm(wasm, host, kBenchGas); + auto const elapsed = std::chrono::steady_clock::now() - start; + + benchmark::DoNotOptimize(outcome); + return { + .seconds = std::chrono::duration(elapsed).count(), + .gas = outcome.has_value() ? outcome->cost : std::int64_t{0}}; +} + +StageTimer::StageTimer(benchmark::State& state, std::int64_t moduleBytes) + : state_{state}, moduleBytes_{moduleBytes} +{ +} + +void +StageTimer::add(double seconds) +{ + state_.SetIterationTime(seconds); + total_ += seconds; + sumSquares_ += seconds * seconds; + ++rounds_; +} + +void +StageTimer::report() +{ + if (rounds_ == 0) + { + return; + } + + auto const count = static_cast(rounds_); + auto const mean = total_ / count; + auto const variance = std::max(0.0, (sumSquares_ / count) - (mean * mean)); + auto const spread = mean > 0.0 ? std::sqrt(variance) / mean : 0.0; + + auto const& calibration = Calibration::instance(); + auto const perGas = calibration.secondsPerGas(); + auto const equivalent = perGas > 0.0 ? mean / perGas : 0.0; + + state_.counters["ns_per_op"] = mean * 1e9; + // What this stage would cost if it were charged at the rate the guest inside it is charged at. + // It is not charged, which is the point: this puts an unpriced stage in the host-function + // table's units. + state_.counters["gas_equivalent"] = equivalent; + + if (moduleBytes_ > 0) + { + state_.counters["module_bytes"] = static_cast(moduleBytes_); + // An average over the whole operation, not the marginal rate: it carries the case's fixed + // cost, so it overestimates and falls toward the true slope as the sweep grows. + state_.counters["gas_per_byte"] = equivalent / static_cast(moduleBytes_); + } + + // `gas_equivalent` divides by `secondsPerGas`, so the divisor's uncertainty is in every number + // here too. + auto const caseStdErr = spread / std::sqrt(count); + auto const perGasErr = calibration.secondsPerGasRelStdErr(); + auto const totalErr = std::sqrt((caseStdErr * caseStdErr) + (perGasErr * perGasErr)); + state_.counters["rel_error"] = totalErr; + state_.counters["unreliable"] = totalErr > kMaxRelativeSpread ? 1 : 0; +} + +void +benchmarkPreflight(benchmark::State& state, Bytes const& wasm, bool expectAccepted, bool sizeSweep) +{ + (void)Calibration::instance(); + + // Discarded: the reject case refuses on every iteration, and a real sink would put string + // formatting and I/O inside the measurement. + auto const journal = beast::Journal{beast::Journal::getNullSink()}; + + if (isTesSuccess(preflightEscrowWasm(wasm, journal)) != expectAccepted) + { + state.SkipWithError( + expectAccepted + ? "the module was refused; the case would be measuring the reject path" + : "the module was accepted; the case would be measuring the accept path"); + return; + } + + StageTimer timer{state, sizeSweep ? static_cast(wasm.size()) : 0}; + for (auto _ : state) + { + auto const start = std::chrono::steady_clock::now(); + auto verdict = preflightEscrowWasm(wasm, journal); + auto const elapsed = std::chrono::steady_clock::now() - start; + + benchmark::DoNotOptimize(verdict); + timer.add(std::chrono::duration(elapsed).count()); + } + timer.report(); +} + +namespace { + +// Seconds of wall time one unit of gas buys on this machine. +// +// The estimator must be the *same* one the cases use — a mean, with the same clamp at zero. Since +// `implied_gas = secondsPerCall / secondsPerGas`, any difference between how divisor and dividend +// are estimated lands in every reported number: calibrating with a best-of while measuring with a +// mean once biased the whole report +40%. +// +// `guestInstruction` in Crossing.cpp is the check that this holds — it runs this exact loop body. +double +measureSecondsPerGas(double& relativeStandardError) +{ + // A couple of guest instructions, no memory traffic, nothing the engine can fold away. + static constexpr auto kBody = std::string_view{"(i32.add (local.get $r) (i32.const 1))"}; + auto const busy = assembleWat(makeLoopWat("", "", kBody, kCallsPerRun)); + auto const idle = assembleWat(makeLoopWat("", "", kBody, 0)); + + auto fixture = WasmLedger{}; + + // Warm up, so the first-run penalty does not land on one side of the subtraction. + for (auto i = 0U; i < 8; ++i) + { + timeRun(*fixture.makeHost(), busy); + timeRun(*fixture.makeHost(), idle); + } + + auto total = 0.0; + auto sumSquares = 0.0; + // Fuel is exact and deterministic, so any pair gives the same delta. + auto gasDelta = std::int64_t{1}; + for (auto i = 0; i < kCalibrationPairs; ++i) + { + auto hotHost = fixture.makeHost(); + auto const hot = timeRun(*hotHost, busy); + auto coldHost = fixture.makeHost(); + auto const cold = timeRun(*coldHost, idle); + + auto const delta = std::max(0.0, hot.seconds - cold.seconds); + total += delta; + sumSquares += delta * delta; + gasDelta = std::max(std::int64_t{1}, hot.gas - cold.gas); + } + + auto const mean = total / kCalibrationPairs; + auto const variance = std::max(0.0, (sumSquares / kCalibrationPairs) - (mean * mean)); + relativeStandardError = mean > 0.0 ? std::sqrt(variance / kCalibrationPairs) / mean : 0.0; + + return mean / static_cast(gasDelta); +} + +// The crossing, in gas: `ldgr_index` through the VM minus `ldgr_index` called directly. +// +// Both halves are means, for the reason above: the VM half has to match `benchmarkThroughVm`'s +// estimator and the impl half `benchmarkImpl`'s. `secondsPerGas` is passed in rather than +// re-measured so it comes from the same snapshot. +double +measureCrossingFloorGas(double secondsPerGas, double& relativeStandardError) +{ + static constexpr std::string_view kImport = + R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) +)"; + static constexpr std::string_view kBody = "(call $ldgr_index (i32.const 0) (i32.const 4))"; + + auto const loaded = assembleWat(makeLoopWat(kImport, "", kBody, kCallsPerRun)); + auto const baseline = assembleWat(makeLoopWat(kImport, "", kBody, 0)); + + auto fixture = WasmLedger{}; + + auto vmTotal = 0.0; + auto vmSquares = 0.0; + auto guestOverheadGas = 0.0; + for (auto i = 0; i < kBenchIterations; ++i) + { + auto hotHost = fixture.makeHost(); + auto const hot = timeRun(*hotHost, loaded); + auto coldHost = fixture.makeHost(); + auto const cold = timeRun(*coldHost, baseline); + + auto const perCall = std::max(0.0, hot.seconds - cold.seconds) / kCallsPerRun; + vmTotal += perCall; + vmSquares += perCall * perCall; + // Exact, from the fuel meter: what the guest burned per call beyond the call itself. + guestOverheadGas = + (static_cast(hot.gas - cold.gas) / kCallsPerRun) - declaredGas("ldgr_index"); + } + auto const vmSeconds = vmTotal / kBenchIterations; + + // The impl side is the same call without the VM. Subtracting it leaves the crossing. + auto implTotal = 0.0; + auto implSquares = 0.0; + auto host = fixture.makeHost(); + for (auto i = 0; i < kBenchIterations; ++i) + { + auto const start = std::chrono::steady_clock::now(); + for (auto c = 0U; c < kCallsPerRun; ++c) + { + auto result = host->getLedgerSqn(); + benchmark::DoNotOptimize(result); + } + auto const elapsed = std::chrono::steady_clock::now() - start; + + auto const perCall = std::chrono::duration(elapsed).count() / kCallsPerRun; + implTotal += perCall; + implSquares += perCall * perCall; + } + auto const implSeconds = implTotal / kBenchIterations; + + if (secondsPerGas <= 0.0) + { + return 0.0; + } + // Take the guest's loop bookkeeping off here too: `report` removes it from every `ThroughVm` + // number, so leaving it in would make the two routes to one price disagree by that amount. + auto const crossing = std::max(0.0, vmSeconds - implSeconds) / secondsPerGas; + auto const floor = std::max(0.0, crossing - std::max(0.0, guestOverheadGas)); + + // Relative to the *difference*, not to either half: both contribute their error, and the + // denominator is what survives the subtraction. Not divided by `secondsPerGas` — that error is + // common-mode with the rest of `suggested_gas` and is applied once, to the sum, in `report`. + auto const vmVariance = std::max(0.0, (vmSquares / kBenchIterations) - (vmSeconds * vmSeconds)); + auto const implVariance = + std::max(0.0, (implSquares / kBenchIterations) - (implSeconds * implSeconds)); + auto const vmStdErr = std::sqrt(vmVariance / kBenchIterations); + auto const implStdErr = std::sqrt(implVariance / kBenchIterations); + + auto const crossingSeconds = vmSeconds - implSeconds; + auto const crossingStdErr = std::sqrt((vmStdErr * vmStdErr) + (implStdErr * implStdErr)); + relativeStandardError = crossingSeconds > 0.0 ? crossingStdErr / crossingSeconds : 0.0; + + return floor; +} + +} // namespace + +Calibration const& +Calibration::instance() +{ + static Calibration const kValue; + return kValue; +} + +Calibration::Calibration() + : secondsPerGas_{measureSecondsPerGas(secondsPerGasRelStdErr_)} + , crossingFloorGas_{measureCrossingFloorGas(secondsPerGas_, crossingFloorRelStdErr_)} +{ +} + +double +declaredGas(std::string_view wasmName) +{ + return static_cast( + rs::wasm_testkit::host_function_gas(rust::Str{wasmName.data(), wasmName.size()})); +} + +void +report( + benchmark::State& state, + double secondsPerCall, + double chargedGas, + double guestOverheadGas, + double relativeSpread, + std::int64_t rounds, + std::string_view wasmName, + bool throughVm) +{ + auto const& calibration = Calibration::instance(); + auto const perGas = calibration.secondsPerGas(); + auto const measured = perGas > 0.0 ? secondsPerCall / perGas : 0.0; + + // The timed number covers the host call *and* whatever the guest ran around it. + // `guestOverheadGas` is exact, so taking it off removes a bias rather than trading estimates. + auto const implied = std::max(0.0, measured - guestOverheadGas); + auto const suggested = throughVm ? implied : implied + calibration.crossingFloorGas(); + + state.counters["implied_gas"] = implied; + state.counters["ns_per_call"] = secondsPerCall * 1e9; + state.counters["charged_gas"] = chargedGas; + + if (wasmName.empty()) + { + return; + } + + auto const declared = declaredGas(wasmName); + state.counters["host_function_gas"] = declared; + state.counters["suggested_gas"] = suggested; + // Below 1 is the direction that matters: an underpriced call is one a contract buys too + // cheaply. + state.counters["price_ratio"] = suggested > 0.0 ? declared / suggested : 0.0; + + // Uncertainty **of `suggested_gas`**, not of `implied_gas` — different numbers once the floor + // is added. `implied` and the floor are independent timings, so their absolute errors add in + // quadrature over the sum; but both divide by `secondsPerGas`, so that error is common-mode and + // applies once to the total. Adding it per-term would count it twice. + // + // For `ThroughVm` the floor term is zero and `suggested == implied`, so this reduces exactly to + // the plain `sqrt(caseErr² + perGasErr²)`. Only `Impl` cases move — and for a cheap one the + // floor is most of `suggested_gas`, so an error bar describing `implied` alone described + // little. + auto const caseStdErr = + rounds > 0 ? relativeSpread / std::sqrt(static_cast(rounds)) : relativeSpread; + + auto const impliedErr = implied * caseStdErr; + auto const floorErr = + throughVm ? 0.0 : calibration.crossingFloorGas() * calibration.crossingFloorRelStdErr(); + auto const independentErr = suggested > 0.0 + ? std::sqrt((impliedErr * impliedErr) + (floorErr * floorErr)) / suggested + : caseStdErr; + + auto const perGasErr = calibration.secondsPerGasRelStdErr(); + auto const totalErr = std::sqrt((independentErr * independentErr) + (perGasErr * perGasErr)); + state.counters["rel_error"] = totalErr; + + // A call whose own cost is small next to the crossing is read off the difference of two nearly + // equal numbers, so its `suggested_gas` is scatter rather than signal. + auto const floor = calibration.crossingFloorGas(); + state.counters["unreliable"] = + (totalErr > kMaxRelativeSpread || (floor > 0.0 && suggested < floor)) ? 1 : 0; +} + +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/WasmBench.h b/src/benchmarks/libxrpl/wasm/WasmBench.h new file mode 100644 index 0000000000..98f0921be7 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/WasmBench.h @@ -0,0 +1,369 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// The gas-calibration harness. What the numbers mean and how to read a report are in ../README.md. + +namespace xrpl::test::bench { + +// Enough that a benchmark loop never ends early; running out would measure something shorter. +inline constexpr std::int64_t kBenchGas = 2'000'000'000; + +// Host calls per run: enough that the per-call cost dominates the baseline subtraction's residue. +inline constexpr std::int32_t kCallsPerRun = 1000; + +// Timed iterations per case. Pinned because automatic sizing cannot work here: a case reports a +// residue of nanoseconds while the iteration producing it ran two contracts and cost milliseconds, +// so sizing would ask for millions. +inline constexpr std::int32_t kBenchIterations = 50; + +// Pairs the one-off calibration averages. Higher than `kBenchIterations` because `secondsPerGas` +// divides every reported number, and a bare wasm loop is cheap to repeat. +inline constexpr std::int32_t kCalibrationPairs = 400; + +// Above this relative uncertainty, `suggested_gas` is reported as unreliable. +inline constexpr double kMaxRelativeSpread = 0.25; + +// `TRANSFER_LIMIT_BYTES` in crates/xrpl-wasm-vm/src/vm.rs: what a run may write into guest memory +// before `charge_transfer` starts refusing calls. +inline constexpr std::int64_t kTransferLimitBytes = 1 << 20; + +// How many calls a run can afford, given the bytes each has the host **write into guest memory**. +// Output direction only — what the guest passes in is borrowed, and costs nothing against the +// budget. Never raises the count to meet a floor; a case that cannot afford one call fails loudly. +int +callsWithinTransferBudget(std::int64_t bytesWrittenPerCall); + +// One run of a contract: how long it took, and what the engine charged it. +struct Timing +{ + double seconds{}; + std::int64_t gas{}; +}; + +// A `(data ...)` segment placing `bytes` at `offset` in guest memory, so the timed loop measures +// the host call rather than the guest arranging its arguments. `watEscaped` in WasmRun.h says why +// zeroed memory will not do. +std::string +dataSegment(int offset, std::span bytes); + +std::string +dataSegment(int offset, Bytes const& bytes); + +// A contract that runs `body` `count` times and returns the last result. +std::string +makeLoopWat(std::string_view imports, std::string_view data, std::string_view body, int count); + +// Run pre-assembled `wasm` once through the real VM, reporting wall time and gas. +Timing +timeRun(HostFunctions& host, Bytes const& wasm); + +// What this machine costs, measured once and shared by every case: two cases pricing one function +// two ways (`Impl` + crossing floor, versus `ThroughVm`) must divide by the *same* `secondsPerGas` +// or they disagree for reasons unrelated to the function. +class Calibration +{ +public: + static Calibration const& + instance(); + + // Seconds of wall time one unit of gas buys here. + [[nodiscard]] double + secondsPerGas() const + { + return secondsPerGas_; + } + + // The gas a host call costs before it does anything: region decode, bounds checks, the cxx hop. + [[nodiscard]] double + crossingFloorGas() const + { + return crossingFloorGas_; + } + + // Propagated into every case's `rel_error`, which is what lets one snapshot stay shared: + // `--benchmark_repetitions` resamples per-case timings but never this divisor. + [[nodiscard]] double + secondsPerGasRelStdErr() const + { + return secondsPerGasRelStdErr_; + } + + // An additive term in every `Impl` case's `suggested_gas`, and most of the cheap ones. + [[nodiscard]] double + crossingFloorRelStdErr() const + { + return crossingFloorRelStdErr_; + } + +private: + Calibration(); + + double secondsPerGasRelStdErr_{}; + double crossingFloorRelStdErr_{}; + double secondsPerGas_{}; + double crossingFloorGas_{}; +}; + +// What the gas table declares for a host function, by guest import name, read through the +// `wasm_testkit` bridge so it cannot drift. +double +declaredGas(std::string_view wasmName); + +// Attach the calibration counters to a finished case. +// +// `guestOverheadGas` is fuel the guest burned around the call — loop bookkeeping and the +// `i32.const`s pushing arguments. From the fuel meter, so it is exact. Zero for `Impl` cases. +void +report( + benchmark::State& state, + double secondsPerCall, + double chargedGas, + double guestOverheadGas, + double relativeSpread, + std::int64_t rounds, + std::string_view wasmName, + bool throughVm); + +// Accumulates one whole-operation case and turns it into counters. +// +// The two harnesses below subtract setup away, amortizing over `kCallsPerRun` calls against a +// baseline. Here that is inverted: setup is the subject, timed whole, nothing amortized. +class StageTimer +{ +public: + // Pass zero for `moduleBytes` unless the case belongs to a sweep that *varies* module size — + // the per-byte counter it enables is an average over the whole operation, meaningless where the + // module is constant. + StageTimer(benchmark::State& state, std::int64_t moduleBytes); + + void + add(double seconds); + + // Attach the counters. Call once, after the loop. + void + report(); + +private: + benchmark::State& state_; + std::int64_t moduleBytes_{}; + double total_{}; + double sumSquares_{}; + std::int64_t rounds_{}; +}; + +// Measure `preflightEscrowWasm`: compile, then the walk over the module's imports and exports. +// +// `expectAccepted` is what the module *should* do. A refused module stops at the first fault and is +// far cheaper, so a case that silently flipped verdict would report a confident number for an +// operation it never performed. +void +benchmarkPreflight( + benchmark::State& state, + Bytes const& wasm, + bool expectAccepted = true, + bool sizeSweep = false); + +// Measure a whole `runEscrowWasm` — every stage, unamortized. +template +void +benchmarkRun(benchmark::State& state, Bytes const& wasm, SetUp&& setUp, bool sizeSweep = false) +{ + // Force the calibration and the engine's lazy construction before the clock starts, so the + // first case does not absorb them into its own first iteration. + [[maybe_unused]] auto const& calibration = Calibration::instance(); + + auto probe = setUp(); + if (auto const check = runEscrowWasm(wasm, *probe, kBenchGas); !check.has_value()) + { + state.SkipWithError("the benchmarked contract did not run to completion"); + return; + } + + auto timer = StageTimer{state, sizeSweep ? static_cast(wasm.size()) : 0}; + for (auto _ : state) + { + auto host = setUp(); + timer.add(timeRun(*host, wasm).seconds); + } + timer.report(); +} + +// Measure a host function through the whole stack — guest, VM, marshalling, real impl, real ledger +// — with everything but the host calls subtracted away. +template +void +benchmarkThroughVm( + benchmark::State& state, + std::string_view wasmName, + std::string_view imports, + std::string_view data, + std::string_view body, + SetUp&& setUp, + int calls = kCallsPerRun) +{ + auto const loaded = assembleWat(makeLoopWat(imports, data, body, calls)); + auto const baseline = assembleWat(makeLoopWat(imports, data, body, 0)); + + // A host serves exactly one run — `runEscrowWasm` asserts it was handed a clean one + // (`checkSelf` in WasmVM.cpp). Hence `setUp` being a factory rather than a host. + auto probe = setUp(); + + // A soft host error still completes the run, so require both that it completed and that the + // last host call returned a non-negative result, which every body leaves in `$r`. + auto const check = runEscrowWasm(loaded, *probe, kBenchGas); + if (!check.has_value()) + { + state.SkipWithError("the benchmarked contract did not run to completion"); + return; + } + if (check->result < 0) + { + state.SkipWithError( + "the benchmarked host call returned error code " + std::to_string(check->result) + + "; the case would be measuring the rejection path, not the work"); + return; + } + + auto totalSeconds = 0.0; + auto sumSquares = 0.0; + auto totalGas = 0.0; + auto rounds = std::int64_t{0}; + for (auto _ : state) + { + auto hotHost = setUp(); + auto const hot = timeRun(*hotHost, loaded); + auto coldHost = setUp(); + auto const cold = timeRun(*coldHost, baseline); + + // Clamped: on a noisy machine a pair can invert, and a negative iteration time would make + // Google Benchmark's statistics meaningless. + auto const perCall = std::max(0.0, hot.seconds - cold.seconds) / calls; + state.SetIterationTime(perCall); + + totalSeconds += perCall; + sumSquares += perCall * perCall; + totalGas += static_cast(hot.gas - cold.gas) / calls; + ++rounds; + } + + if (rounds > 0) + { + auto const meanSeconds = totalSeconds / rounds; + auto const variance = std::max(0.0, (sumSquares / rounds) - (meanSeconds * meanSeconds)); + auto const spread = meanSeconds > 0.0 ? std::sqrt(variance) / meanSeconds : 0.0; + + // Zero for the empty-name case — `guestInstruction`, which prices no host function. There + // is no host call to separate scaffolding *from*, and subtracting the full charge would + // leave `implied_gas = measured - charged`, ~0 by construction: it would turn the harness's + // one self-test into a tautology that cannot fail. + auto const chargedPerCall = totalGas / rounds; + auto const overhead = wasmName.empty() ? 0.0 : chargedPerCall - declaredGas(wasmName); + + report( + state, + meanSeconds, + chargedPerCall, + std::max(0.0, overhead), + spread, + rounds, + wasmName, + true); + } +} + +// Measure a host function's impl alone — no guest, no VM, no marshalling. Against the `ThroughVm` +// case for the same function, the difference is what crossing the boundary costs. +template +void +benchmarkImpl(benchmark::State& state, std::string_view wasmName, SetUp&& setUp, Call&& call) +{ + auto host = setUp(); + + // A call that errors returns early and is far cheaper than one that works, so a subtly wrong + // argument yields a confident and always *too low* price. Probed either side of the loop rather + // than inside it, where the branch would land in the measurement: *before* catches wrong + // arguments, *after* catches a call that stopped working once the loop exhausted something. + // + // The `requires` skips host functions that answer nothing (`trace`) or answer a bare value. + auto const checkSucceeds = [&](char const* when) { + if constexpr (requires { call(*host).has_value(); }) + { + if (auto const probe = call(*host); !probe.has_value()) + { + state.SkipWithError( + std::string{"the benchmarked host call returned error code "} + + std::to_string(static_cast(probe.error())) + " " + when + + " the timed loop; the case would be measuring the rejection path"); + return false; + } + } + return true; + }; + + if (!checkSucceeds("before")) + { + return; + } + + auto totalSeconds = 0.0; + auto sumSquares = 0.0; + auto rounds = std::int64_t{0}; + for (auto _ : state) + { + auto const start = std::chrono::steady_clock::now(); + for (int i = 0; i < kCallsPerRun; ++i) + { + // `trace` answers nothing, so `ClobberMemory` stands in for `DoNotOptimize`. + if constexpr (std::is_void_v) + { + call(*host); + benchmark::ClobberMemory(); + } + else + { + auto result = call(*host); + benchmark::DoNotOptimize(result); + } + } + auto const elapsed = std::chrono::steady_clock::now() - start; + + auto const perCall = std::chrono::duration(elapsed).count() / kCallsPerRun; + state.SetIterationTime(perCall); + + totalSeconds += perCall; + sumSquares += perCall * perCall; + ++rounds; + } + + if (!checkSucceeds("after")) + { + return; + } + + if (rounds > 0) + { + auto const meanSeconds = totalSeconds / rounds; + auto const variance = std::max(0.0, (sumSquares / rounds) - (meanSeconds * meanSeconds)); + auto const spread = meanSeconds > 0.0 ? std::sqrt(variance) / meanSeconds : 0.0; + + // Nothing charged and no guest scaffolding; `report` adds the crossing back in. + report(state, meanSeconds, 0.0, 0.0, spread, rounds, wasmName, false); + } +} + +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/AccountKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/AccountKeylet.cpp new file mode 100644 index 0000000000..5bd2c7c2e8 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/AccountKeylet.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +accountKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"accountroot_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.accountKeylet(Fixtures::instance().alice().id()); }); +} +BENCHMARK(accountKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/AmmKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/AmmKeylet.cpp new file mode 100644 index 0000000000..4cefc1c553 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/AmmKeylet.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +ammKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"amm_id"}; + + auto const usd = Asset{Issue{toCurrency("USD"), Fixtures::instance().alice().id()}}; + auto const xrp = Asset{xrpIssue()}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [&usd, &xrp](auto& host) { return host.ammKeylet(usd, xrp); }); +} +BENCHMARK(ammKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/BaseFee.cpp b/src/benchmarks/libxrpl/wasm/host_functions/BaseFee.cpp new file mode 100644 index 0000000000..b304beeb65 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/BaseFee.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +baseFeeImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"base_fee"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getBaseFee(); }); +} +BENCHMARK(baseFeeImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/CacheLedgerObj.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CacheLedgerObj.cpp new file mode 100644 index 0000000000..b027396d1e --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/CacheLedgerObj.cpp @@ -0,0 +1,28 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +cacheLedgerObjImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"cache_le"}; + + auto const key = keylet::account(Fixtures::instance().alice().id()).key; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [&key](auto& host) { return host.cacheLedgerObj(key, 1); }); +} +BENCHMARK(cacheLedgerObjImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/CheckKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CheckKeylet.cpp new file mode 100644 index 0000000000..24af99a6ac --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/CheckKeylet.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +checkKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"check_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.checkKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(checkKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/CheckSignature.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CheckSignature.cpp new file mode 100644 index 0000000000..af7e333bc7 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/CheckSignature.cpp @@ -0,0 +1,63 @@ +#include + +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "check_sig"; + +constexpr std::string_view kImport = + R"( (import "host_lib" "check_sig" (func $check_sig (param i32 i32 i32 i32 i32 i32) (result i32))) +)"; + +constexpr std::int32_t kMessageOffset = 0; +constexpr std::int32_t kSignatureOffset = 256; +constexpr std::int32_t kPubkeyOffset = 512; + +void +checkSignatureThroughVm(benchmark::State& state) +{ + auto const& m = Fixtures::instance().signedMessage(); + static auto const kData = dataSegment(kMessageOffset, m.message) + + dataSegment(kSignatureOffset, m.signature) + dataSegment(kPubkeyOffset, m.publicKey); + static auto const kBody = std::format( + "(call $check_sig (i32.const {}) (i32.const {}) (i32.const {}) (i32.const {}) " + "(i32.const {}) (i32.const {}))", + kMessageOffset, + m.message.size(), + kSignatureOffset, + m.signature.size(), + kPubkeyOffset, + m.publicKey.size()); + + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(checkSignatureThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +checkSignatureImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + auto const& m = Fixtures::instance().signedMessage(); + return host.checkSignature( + Slice{m.message.data(), m.message.size()}, + Slice{m.signature.data(), m.signature.size()}, + Slice{m.publicKey.data(), m.publicKey.size()}); + }); +} +BENCHMARK(checkSignatureImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/CredentialKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CredentialKeylet.cpp new file mode 100644 index 0000000000..219cc9051c --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/CredentialKeylet.cpp @@ -0,0 +1,32 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +credentialKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"credential_id"}; + static constexpr auto kType = std::string_view{"termsandconditions"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.credentialKeylet( + Fixtures::instance().alice().id(), + Fixtures::instance().bob().id(), + Slice{kType.data(), kType.size()}); + }); +} +BENCHMARK(credentialKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjArrayLen.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjArrayLen.cpp new file mode 100644 index 0000000000..4678749e84 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjArrayLen.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +currentLedgerObjArrayLenImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"home_le_arr_len"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().signerListHost(); }, + [](auto& host) { return host.getCurrentLedgerObjArrayLen(sfSignerEntries); }); +} +BENCHMARK(currentLedgerObjArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjField.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjField.cpp new file mode 100644 index 0000000000..5a441ffa42 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjField.cpp @@ -0,0 +1,41 @@ +#include + +#include +#include +#include + +#include +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "home_le_field"; +constexpr std::string_view kImport = + R"( (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) +)"; + +void +currentLedgerObjFieldThroughVm(benchmark::State& state) +{ + static auto const kBody = std::format( + "(call $home_le_field (i32.const {}) (i32.const 0) (i32.const 32))", sfAccount.getCode()); + + benchmarkThroughVm( + state, kWasmName, kImport, "", kBody, [] { return Fixtures::instance().escrowHost(); }); +} +BENCHMARK(currentLedgerObjFieldThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +currentLedgerObjFieldImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().escrowHost(); }, + [](auto& host) { return host.getCurrentLedgerObjField(sfAccount); }); +} +BENCHMARK(currentLedgerObjFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp new file mode 100644 index 0000000000..e2c5d0ab73 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp @@ -0,0 +1,30 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +currentLedgerObjNestedArrayLenImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"home_le_inner_arr_len"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().signerListHost(); }, + [](auto& host) { + return host.getCurrentLedgerObjNestedArrayLen( + FieldLocator{{sfSignerEntries.getCode()}}); + }); +} +BENCHMARK(currentLedgerObjNestedArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedField.cpp b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedField.cpp new file mode 100644 index 0000000000..fd0a7f96ed --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/CurrentLedgerObjNestedField.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +currentLedgerObjNestedFieldImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"home_le_inner"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.getCurrentLedgerObjNestedField(FieldLocator{{sfAccount.getCode()}}); + }); +} +BENCHMARK(currentLedgerObjNestedFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/DelegateKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/DelegateKeylet.cpp new file mode 100644 index 0000000000..6a66db420a --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/DelegateKeylet.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +delegateKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"delegate_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.delegateKeylet( + Fixtures::instance().alice().id(), Fixtures::instance().bob().id()); + }); +} +BENCHMARK(delegateKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/DepositPreauthKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/DepositPreauthKeylet.cpp new file mode 100644 index 0000000000..2931669c34 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/DepositPreauthKeylet.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +depositPreauthKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"deposit_preauth_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.depositPreauthKeylet( + Fixtures::instance().alice().id(), Fixtures::instance().bob().id()); + }); +} +BENCHMARK(depositPreauthKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/DidKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/DidKeylet.cpp new file mode 100644 index 0000000000..6402bf425a --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/DidKeylet.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +didKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"did_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.didKeylet(Fixtures::instance().alice().id()); }); +} +BENCHMARK(didKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/EscrowKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/EscrowKeylet.cpp new file mode 100644 index 0000000000..369388fb19 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/EscrowKeylet.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include +#include +#include + +#include +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "escrow_id"; + +constexpr std::string_view kImport = + R"( (import "host_lib" "escrow_id" (func $escrow_id (param i32 i32 i32 i32 i32 i32) (result i32))) +)"; +constexpr std::string_view kBody = + "(call $escrow_id (i32.const 0) (i32.const 20) (i32.const 32) (i32.const 4) " + "(i32.const 64) (i32.const 32))"; + +void +escrowKeyletThroughVm(benchmark::State& state) +{ + static auto const kData = [] { + auto seq = Bytes(4); + for (auto i = 0U; i < 4; ++i) + { + seq[i] = static_cast((Fixtures::kSeq >> (8 * i)) & 0xFF); + } + return dataSegment(0, WasmLedger::toBytes(Fixtures::instance().alice().id())) + + dataSegment(32, seq); + }(); + + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(escrowKeyletThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +escrowKeyletImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.escrowKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(escrowKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatAdd.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatAdd.cpp new file mode 100644 index 0000000000..e5fb2360f3 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatAdd.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "float_add"; + +constexpr std::string_view kImport = + R"( (import "host_lib" "float_add" (func $float_add (param i32 i32 i32 i32 i32 i32 i32) (result i32))) +)"; + +constexpr std::string_view kBody = + "(call $float_add (i32.const 0) (i32.const 12) (i32.const 16) (i32.const 12) " + "(i32.const 64) (i32.const 12) (i32.const 0))"; + +void +floatAddThroughVm(benchmark::State& state) +{ + static auto const kData = + dataSegment(0, FloatConstants::kPi) + dataSegment(16, FloatConstants::kTwo); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(floatAddThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +floatAddImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatAdd(Fixtures::floatX(), Fixtures::floatY(), Fixtures::kRoundingMode); + }); +} +BENCHMARK(floatAddImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatCompare.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatCompare.cpp new file mode 100644 index 0000000000..ea6c68c44f --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatCompare.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatCompareImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_cmp"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatCompare(Fixtures::floatX(), Fixtures::floatY()); }); +} +BENCHMARK(floatCompareImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatDivide.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatDivide.cpp new file mode 100644 index 0000000000..bdc802d4bc --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatDivide.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatDivideImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_div"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatDivide( + Fixtures::floatX(), Fixtures::floatY(), Fixtures::kRoundingMode); + }); +} +BENCHMARK(floatDivideImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatFromInt.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromInt.cpp new file mode 100644 index 0000000000..5edc05d000 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromInt.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatFromIntImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_from_int"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatFromInt(3141592653589793, Fixtures::kRoundingMode); }); +} +BENCHMARK(floatFromIntImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatFromMantExp.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromMantExp.cpp new file mode 100644 index 0000000000..6f60b16136 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromMantExp.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatFromMantExpImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_from_mant_exp"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatFromMantExp(3141592653589793, -15, Fixtures::kRoundingMode); + }); +} +BENCHMARK(floatFromMantExpImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStAmount.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStAmount.cpp new file mode 100644 index 0000000000..4cca4f48af --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStAmount.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatFromStAmountImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_from_stamount"}; + + auto const amount = + STAmount{Issue{toCurrency("USD"), Fixtures::instance().alice().id()}, 1234567, -3}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [&amount](auto& host) { return host.floatFromSTAmount(amount, Fixtures::kRoundingMode); }); +} +BENCHMARK(floatFromStAmountImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStNumber.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStNumber.cpp new file mode 100644 index 0000000000..b5081550c9 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromStNumber.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatFromStNumberImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_from_stnumber"}; + + auto const number = STNumber{sfNumber, Number(3141592653589793, -15)}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [&number](auto& host) { return host.floatFromSTNumber(number, Fixtures::kRoundingMode); }); +} +BENCHMARK(floatFromStNumberImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatFromUint.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromUint.cpp new file mode 100644 index 0000000000..ffe04d409f --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatFromUint.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatFromUintImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_from_uint"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatFromUint(3141592653589793u, Fixtures::kRoundingMode); }); +} +BENCHMARK(floatFromUintImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatMultiply.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatMultiply.cpp new file mode 100644 index 0000000000..a2bcbbd06a --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatMultiply.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatMultiplyImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_mult"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatMultiply( + Fixtures::floatX(), Fixtures::floatY(), Fixtures::kRoundingMode); + }); +} +BENCHMARK(floatMultiplyImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatPower.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatPower.cpp new file mode 100644 index 0000000000..81b5134d2e --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatPower.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "float_pow"; + +constexpr std::string_view kImport = + R"( (import "host_lib" "float_pow" (func $float_pow (param i32 i32 i32 i32 i32 i32) (result i32))) +)"; + +constexpr std::string_view kBody = + "(call $float_pow (i32.const 0) (i32.const 12) (i32.const 7) " + "(i32.const 64) (i32.const 12) (i32.const 0))"; + +void +floatPowerThroughVm(benchmark::State& state) +{ + static auto const kData = dataSegment(0, FloatConstants::kPi); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(floatPowerThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +floatPowerImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatPower(Fixtures::floatX(), 7, Fixtures::kRoundingMode); }); +} +BENCHMARK(floatPowerImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatSubtract.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatSubtract.cpp new file mode 100644 index 0000000000..644aada775 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatSubtract.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatSubtractImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_sub"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.floatSubtract( + Fixtures::floatX(), Fixtures::floatY(), Fixtures::kRoundingMode); + }); +} +BENCHMARK(floatSubtractImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatToInt.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatToInt.cpp new file mode 100644 index 0000000000..e8e3179b36 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatToInt.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +floatToIntImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"float_to_int"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatToInt(Fixtures::floatX(), Fixtures::kRoundingMode); }); +} +BENCHMARK(floatToIntImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/FloatToMantExp.cpp b/src/benchmarks/libxrpl/wasm/host_functions/FloatToMantExp.cpp new file mode 100644 index 0000000000..50522b5e5c --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/FloatToMantExp.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "float_to_mant_exp"; + +constexpr std::string_view kImport = + R"( (import "host_lib" "float_to_mant_exp" (func $split (param i32 i32 i32 i32 i32 i32) (result i32))) +)"; +constexpr std::string_view kBody = + "(call $split (i32.const 0) (i32.const 12) (i32.const 64) (i32.const 8) " + "(i32.const 128) (i32.const 4))"; + +void +floatToMantExpThroughVm(benchmark::State& state) +{ + static auto const kData = dataSegment(0, FloatConstants::kPi); + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(floatToMantExpThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +floatToMantExpImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.floatToMantExp(Fixtures::floatX()); }); +} +BENCHMARK(floatToMantExpImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/GetNFT.cpp b/src/benchmarks/libxrpl/wasm/host_functions/GetNFT.cpp new file mode 100644 index 0000000000..e28addfed0 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/GetNFT.cpp @@ -0,0 +1,34 @@ + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +getNFTImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"nft_uri"}; + + // A really minted token, so the lookup walks a real page rather than failing fast — a + // not-found answer would measure the rejection instead of the work. + static constexpr auto kUri = std::string_view{"ipfs://benchmark"}; + // Its own ledger rather than the shared `Fixtures`: minting mutates state, and the shared + // one is deliberately read-only after construction. + static auto nft = WasmLedger{}; + static auto const kOwner = nft.fund("benchNftOwner"); + static auto const kMinted = mintNft(nft, kOwner, kUri); + + benchmarkImpl( + state, + kWasmName, + [] { return nft.makeHost(); }, + [](auto& host) { return host.getNFT(kOwner.id(), kMinted); }); +} +BENCHMARK(getNFTImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/IsAmendmentEnabled.cpp b/src/benchmarks/libxrpl/wasm/host_functions/IsAmendmentEnabled.cpp new file mode 100644 index 0000000000..3fc49c706c --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/IsAmendmentEnabled.cpp @@ -0,0 +1,54 @@ +#include + +#include +#include +#include + +#include +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "amendment_enabled"; + +std::string const& +benchAmendment() +{ + static auto const kValue = std::string{"TokenEscrow"}; + return kValue; +} + +void +isAmendmentEnabledByIdImpl(benchmark::State& state) +{ + auto const feature = getRegisteredFeature(benchAmendment()); + if (!feature.has_value()) + { + state.SkipWithError("the benchmarked amendment is not registered"); + return; + } + auto const id = *feature; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [&id](auto& host) { return host.isAmendmentEnabled(id); }); +} +BENCHMARK(isAmendmentEnabledByIdImpl)->UseManualTime()->Iterations(kBenchIterations); + +void +isAmendmentEnabledByNameImpl(benchmark::State& state) +{ + // The gap over the id form is precisely what the shared price of 100 asserts does not exist. + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.isAmendmentEnabled(std::string_view{benchAmendment()}); }); +} +BENCHMARK(isAmendmentEnabledByNameImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjArrayLen.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjArrayLen.cpp new file mode 100644 index 0000000000..89b14997da --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjArrayLen.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +ledgerObjArrayLenImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"le_arr_len"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().cachedSignerListHost(); }, + [](auto& host) { return host.getLedgerObjArrayLen(1, sfSignerEntries); }); +} +BENCHMARK(ledgerObjArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjField.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjField.cpp new file mode 100644 index 0000000000..2f707b6cb8 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjField.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +ledgerObjFieldImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"le_field"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().cachedHost(); }, + [](auto& host) { return host.getLedgerObjField(1, sfAccount); }); +} +BENCHMARK(ledgerObjFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedArrayLen.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedArrayLen.cpp new file mode 100644 index 0000000000..b51460e664 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedArrayLen.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +ledgerObjNestedArrayLenImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"le_inner_arr_len"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().cachedSignerListHost(); }, + [](auto& host) { + return host.getLedgerObjNestedArrayLen(1, FieldLocator{{sfSignerEntries.getCode()}}); + }); +} +BENCHMARK(ledgerObjNestedArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedField.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedField.cpp new file mode 100644 index 0000000000..757b3118c5 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerObjNestedField.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +ledgerObjNestedFieldImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"le_inner"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().cachedHost(); }, + [](auto& host) { + return host.getLedgerObjNestedField(1, FieldLocator{{sfAccount.getCode()}}); + }); +} +BENCHMARK(ledgerObjNestedFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/LedgerSqn.cpp b/src/benchmarks/libxrpl/wasm/host_functions/LedgerSqn.cpp new file mode 100644 index 0000000000..130cea3cd2 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/LedgerSqn.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "ldgr_index"; + +constexpr std::string_view kImport = + R"( (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) +)"; + +void +ledgerSqnThroughVm(benchmark::State& state) +{ + benchmarkThroughVm( + state, kWasmName, kImport, "", "(call $ldgr_index (i32.const 0) (i32.const 4))", [] { + return Fixtures::instance().host(); + }); +} +BENCHMARK(ledgerSqnThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +ledgerSqnImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getLedgerSqn(); }); +} +BENCHMARK(ledgerSqnImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/MptokenIssuanceKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/MptokenIssuanceKeylet.cpp new file mode 100644 index 0000000000..bda4c979be --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/MptokenIssuanceKeylet.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +mptokenIssuanceKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"mpt_issuance_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.mptokenIssuanceKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(mptokenIssuanceKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/MptokenKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/MptokenKeylet.cpp new file mode 100644 index 0000000000..b1e289181d --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/MptokenKeylet.cpp @@ -0,0 +1,31 @@ + +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +mptokenKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"mptoken_id"}; + + auto const mptid = makeMptID(1, Fixtures::instance().alice().id()); + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [&mptid](auto& host) { + return host.mptokenKeylet(mptid, Fixtures::instance().bob().id()); + }); +} +BENCHMARK(mptokenKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/NFTFlags.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTFlags.cpp new file mode 100644 index 0000000000..270f8337fa --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTFlags.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +nftFlagsImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"nft_flags"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTFlags(Fixtures::instance().nftId()); }); +} +BENCHMARK(nftFlagsImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/NFTIssuer.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTIssuer.cpp new file mode 100644 index 0000000000..bcb960e6ee --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTIssuer.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +nftIssuerImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"nft_issuer"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTIssuer(Fixtures::instance().nftId()); }); +} +BENCHMARK(nftIssuerImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/NFTSequence.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTSequence.cpp new file mode 100644 index 0000000000..f30a8d2348 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTSequence.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +nftSequenceImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"nft_serial"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTSequence(Fixtures::instance().nftId()); }); +} +BENCHMARK(nftSequenceImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/NFTTaxon.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTTaxon.cpp new file mode 100644 index 0000000000..8a4bc91790 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTTaxon.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +nftTaxonImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"nft_taxon"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTTaxon(Fixtures::instance().nftId()); }); +} +BENCHMARK(nftTaxonImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/NFTTransferFee.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NFTTransferFee.cpp new file mode 100644 index 0000000000..c574ccab9d --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/NFTTransferFee.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +nftTransferFeeImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"nft_xfer_fee"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getNFTTransferFee(Fixtures::instance().nftId()); }); +} +BENCHMARK(nftTransferFeeImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/NftokenOfferKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/NftokenOfferKeylet.cpp new file mode 100644 index 0000000000..46a3b074a8 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/NftokenOfferKeylet.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +nftokenOfferKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"nft_offer_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.nftokenOfferKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(nftokenOfferKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/OfferKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/OfferKeylet.cpp new file mode 100644 index 0000000000..7cd61c2b69 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/OfferKeylet.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +offerKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"offer_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.offerKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(offerKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/OracleKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/OracleKeylet.cpp new file mode 100644 index 0000000000..8a7679322c --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/OracleKeylet.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +oracleKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"oracle_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.oracleKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(oracleKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerHash.cpp b/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerHash.cpp new file mode 100644 index 0000000000..8f3210d101 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerHash.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +parentLedgerHashImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"parent_ldgr_hash"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getParentLedgerHash(); }); +} +BENCHMARK(parentLedgerHashImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerTime.cpp b/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerTime.cpp new file mode 100644 index 0000000000..fa800c7520 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/ParentLedgerTime.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +parentLedgerTimeImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"parent_ldgr_time"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getParentLedgerTime(); }); +} +BENCHMARK(parentLedgerTimeImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/PaychannelKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/PaychannelKeylet.cpp new file mode 100644 index 0000000000..0892fdfbde --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/PaychannelKeylet.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +paychannelKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"paychan_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.paychannelKeylet( + Fixtures::instance().alice().id(), Fixtures::instance().bob().id(), Fixtures::kSeq); + }); +} +BENCHMARK(paychannelKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/PermissionedDomainedKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/PermissionedDomainedKeylet.cpp new file mode 100644 index 0000000000..d97d35afba --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/PermissionedDomainedKeylet.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +permissionedDomainKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"permissioned_domain_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.permissionedDomainKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(permissionedDomainKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/Sha512Half.cpp b/src/benchmarks/libxrpl/wasm/host_functions/Sha512Half.cpp new file mode 100644 index 0000000000..0894956d8e --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/Sha512Half.cpp @@ -0,0 +1,69 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "sha512_half"; + +constexpr std::string_view kImport = + R"( (import "host_lib" "sha512_half" (func $sha512_half (param i32 i32 i32 i32) (result i32))) +)"; + +void +sha512HalfThroughVm(benchmark::State& state) +{ + // Zeroed guest memory is a perfectly good hash input: `sha512_half` validates nothing about + // its bytes, so there is no data segment to seed. + auto const body = std::format( + "(call $sha512_half (i32.const 0) (i32.const {}) (i32.const 8192) (i32.const 32))", + state.range(0)); + + // A hash is 32 bytes back to the guest whatever the input length, and the transfer budget + // counts only what the host writes — so the input sweep does not shrink the call count. + benchmarkThroughVm( + state, + kWasmName, + kImport, + "", + body, + [] { return Fixtures::instance().host(); }, + callsWithinTransferBudget(32)); + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK(sha512HalfThroughVm) + ->RangeMultiplier(8) + ->Range(8, xrpl::kMaxWasmDataLength) + ->UseManualTime() + ->Iterations(kBenchIterations); + +void +sha512HalfImpl(benchmark::State& state) +{ + auto const data = Bytes(static_cast(state.range(0)), 0x42); + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [&data](auto& host) { + return host.computeSha512HalfHash(Slice{data.data(), data.size()}); + }); + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK(sha512HalfImpl) + ->RangeMultiplier(8) + ->Range(8, xrpl::kMaxWasmDataLength) + ->UseManualTime() + ->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/SignerListKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/SignerListKeylet.cpp new file mode 100644 index 0000000000..0764bd140c --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/SignerListKeylet.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +signerListKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"signers_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.signerListKeylet(Fixtures::instance().alice().id()); }); +} +BENCHMARK(signerListKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/TicketKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TicketKeylet.cpp new file mode 100644 index 0000000000..78791a7d2c --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/TicketKeylet.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +ticketKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"ticket_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.ticketKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(ticketKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/Trace.cpp b/src/benchmarks/libxrpl/wasm/host_functions/Trace.cpp new file mode 100644 index 0000000000..c0eec7a2d6 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/Trace.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "trace"; +constexpr std::string_view kMessage = "benchmark trace message"; +constexpr std::string_view kData = "0123456789abcdef"; + +// The path a validator actually runs: journal pointed at a null sink. +void +traceDisabledImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.trace(kMessage, kData); }); +} +BENCHMARK(traceDisabledImpl)->UseManualTime()->Iterations(kBenchIterations); + +// The same call against a host whose sink records what it is given. The gap over the case above +// is the cost the flat 30 does not cover. +void +traceEnabledImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().tracingHost(); }, + [](auto& host) { return host.trace(kMessage, kData); }); +} +BENCHMARK(traceEnabledImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/TrustLineKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TrustLineKeylet.cpp new file mode 100644 index 0000000000..ffb09dc65c --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/TrustLineKeylet.cpp @@ -0,0 +1,31 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +trustLineKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"trustline_id"}; + + auto const currency = toCurrency("USD"); + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [¤cy](auto& host) { + return host.trustLineKeylet( + Fixtures::instance().alice().id(), Fixtures::instance().bob().id(), currency); + }); +} +BENCHMARK(trustLineKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/TxArrayLen.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TxArrayLen.cpp new file mode 100644 index 0000000000..a4b1b94811 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/TxArrayLen.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +txArrayLenImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"tx_arr_len"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getTxArrayLen(sfMemos); }); +} +BENCHMARK(txArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/TxField.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TxField.cpp new file mode 100644 index 0000000000..afe0dcaf8d --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/TxField.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +txFieldImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"tx_field"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getTxField(sfAccount); }); +} +BENCHMARK(txFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/TxNestedArrayLen.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TxNestedArrayLen.cpp new file mode 100644 index 0000000000..de7b4d4a4a --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/TxNestedArrayLen.cpp @@ -0,0 +1,27 @@ +#include +#include + +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +txNestedArrayLenImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"tx_inner_arr_len"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getTxNestedArrayLen(FieldLocator{{sfMemos.getCode()}}); }); +} +BENCHMARK(txNestedArrayLenImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/TxNestedField.cpp b/src/benchmarks/libxrpl/wasm/host_functions/TxNestedField.cpp new file mode 100644 index 0000000000..3707a55ee7 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/TxNestedField.cpp @@ -0,0 +1,55 @@ +#include +#include + +#include +#include +#include + +#include +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "tx_inner"; +constexpr std::string_view kImport = + R"( (import "host_lib" "tx_inner" (func $tx_inner (param i32 i32 i32 i32) (result i32))) +)"; +constexpr std::string_view kBody = + "(call $tx_inner (i32.const 0) (i32.const 12) (i32.const 64) (i32.const 64))"; + +void +txNestedFieldThroughVm(benchmark::State& state) +{ + // The locator bytes are seeded rather than stored by the guest, so the loop measures the host + // call and not three `i32.store`s. + static auto const kData = dataSegment(0, [] { + auto bytes = Bytes{}; + for (auto const step : {sfMemos.getCode(), 0, sfMemoData.getCode()}) + { + for (auto i = 0U; i < 4; ++i) + { + bytes.push_back(static_cast((step >> (8 * i)) & 0xFF)); + } + } + return bytes; + }()); + + benchmarkThroughVm( + state, kWasmName, kImport, kData, kBody, [] { return Fixtures::instance().host(); }); +} +BENCHMARK(txNestedFieldThroughVm)->UseManualTime()->Iterations(kBenchIterations); + +void +txNestedFieldImpl(benchmark::State& state) +{ + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { return host.getTxNestedField(Fixtures::memoLocator()); }); +} +BENCHMARK(txNestedFieldImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/UpdateData.cpp b/src/benchmarks/libxrpl/wasm/host_functions/UpdateData.cpp new file mode 100644 index 0000000000..0cc8a19249 --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/UpdateData.cpp @@ -0,0 +1,62 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test::bench { +namespace { + +constexpr std::string_view kWasmName = "set_data"; +constexpr std::string_view kImport = + R"( (import "host_lib" "set_data" (func $set_data (param i32 i32) (result i32))) +)"; + +void +updateDataThroughVm(benchmark::State& state) +{ + auto const body = std::format("(call $set_data (i32.const 0) (i32.const {}))", state.range(0)); + + benchmarkThroughVm( + state, + kWasmName, + kImport, + "", + body, + [] { return Fixtures::instance().host(); }, + // `set_data` answers a scalar and writes nothing into guest memory, so the + // transfer budget does not constrain it however large the input gets. + callsWithinTransferBudget(0)); + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK(updateDataThroughVm) + ->RangeMultiplier(4) + ->Range(8, kMaxWasmDataLength) + ->UseManualTime() + ->Iterations(kBenchIterations); + +void +updateDataImpl(benchmark::State& state) +{ + auto const data = Bytes(static_cast(state.range(0)), 0x42); + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [&data](auto& host) { return host.updateData(Slice{data.data(), data.size()}); }); + state.SetBytesProcessed(state.iterations() * state.range(0)); +} +BENCHMARK(updateDataImpl) + ->RangeMultiplier(4) + ->Range(8, kMaxWasmDataLength) + ->UseManualTime() + ->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/benchmarks/libxrpl/wasm/host_functions/VaultKeylet.cpp b/src/benchmarks/libxrpl/wasm/host_functions/VaultKeylet.cpp new file mode 100644 index 0000000000..32b7feabac --- /dev/null +++ b/src/benchmarks/libxrpl/wasm/host_functions/VaultKeylet.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +namespace xrpl::test::bench { +namespace { + +void +vaultKeyletImpl(benchmark::State& state) +{ + static constexpr auto kWasmName = std::string_view{"vault_id"}; + + benchmarkImpl( + state, + kWasmName, + [] { return Fixtures::instance().host(); }, + [](auto& host) { + return host.vaultKeylet(Fixtures::instance().alice().id(), Fixtures::kSeq); + }); +} +BENCHMARK(vaultKeyletImpl)->UseManualTime()->Iterations(kBenchIterations); + +} // namespace +} // namespace xrpl::test::bench diff --git a/src/test/app/TestHostFunctions.h b/src/test/app/TestHostFunctions.h deleted file mode 100644 index a38e284f40..0000000000 --- a/src/test/app/TestHostFunctions.h +++ /dev/null @@ -1,488 +0,0 @@ -#pragma once - -#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()}; - } - - // FieldNotFound is a guest-returnable code (the contract handles a negative result); - // Unimplemented now maps to a fatal Fault::Internal (tecINTERNAL) that stops the run. - return std::unexpected(HostFunctionError::FieldNotFound); - } - - [[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, SeqProxy::rawSequence(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, SeqProxy::rawSequence(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 - } - - void - trace(std::string_view const& msg, std::string_view const& data) const override - { - log(msg, [&data] { return data; }); - } - - [[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 - 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 15b3c8f32c..0000000000 --- a/src/test/app/Wasm_test.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include -#ifdef _DEBUG -// #define DEBUG_OUTPUT 1 -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -namespace xrpl::test { - -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 - 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, env.journal, 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, env.journal, escrowFunctionName); - BEAST_EXPECT(!isTesSuccess(re)); - } - } - - 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, 50'207); - } - - { - // max() gas - TestHostFunctions hfs(env); - auto re = runEscrowWasm( - allHFWasm, hfs, std::numeric_limits::max(), escrowFunctionName); - checkResult(re, 1, 50'207); - } - - { // 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, 28'901); - } - - { // 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, 28'901); - } - } - - void - testCodecovWasm() - { - testcase("Codecov wasm test"); - - using namespace test::jtx; - - Env env{*this}; - - auto const codecovWasm = hexToBytes(kCodecovTestsWasmHex); - TestHostFunctions hfs(env); - - auto const allowance = 124'173; - auto re = runEscrowWasm(codecovWasm, hfs, allowance, escrowFunctionName); - - checkResult(re, 1, allowance); - } - - 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 - { - testBadWasm(); - testEscrowWasmDN(); - testCodecovWasm(); - 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 5240e9b0f0..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/Cargo.lock +++ /dev/null @@ -1,180 +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-common-stdlib", - "xrpl-escrow-stdlib", -] - -[[package]] -name = "block-buffer" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" -dependencies = [ - "hybrid-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 = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", -] - -[[package]] -name = "hybrid-array" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" -dependencies = [ - "typenum", -] - -[[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.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" -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 = "xrpl-common-stdlib" -version = "0.8.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "xrpl-macros", -] - -[[package]] -name = "xrpl-escrow-stdlib" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "xrpl-common-stdlib", -] - -[[package]] -name = "xrpl-macros" -version = "0.1.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git?branch=error-and-trace#b008b097237ce0d1a2dffc72ba39dd9fc50020a9" -dependencies = [ - "bs58", - "proc-macro2", - "quote", - "sha2", - "syn", -] 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 71ad3ba9c6..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/Cargo.toml +++ /dev/null @@ -1,22 +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-common-stdlib", branch = "error-and-trace" } -xrpl-escrow = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-escrow-stdlib", branch = "error-and-trace" } - -[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 586e950e39..0000000000 --- a/src/test/app/wasm_fixtures/all_host_functions/src/lib.rs +++ /dev/null @@ -1,760 +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_escrow::current_tx::escrow_finish::EscrowFinish; -use xrpl_std::current_tx::traits::TransactionCommonFields; -use xrpl_std::host; -use xrpl_std::host::trace::TraceDataType; -use xrpl_std::host::trace::{trace, trace_acct_buf, trace_hex, trace_num}; -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_hex("Parent ledger hash:", &hash_buffer); - - 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_acct_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_hex("Transaction Fee (serialized XRP amount):", &fee_buffer); - - // 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_hex("Transaction Sequence:", &seq_buffer); - - // 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_hex("Nested field:", &nested_buffer[..nested_result as usize]); - } - - // 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_hex( - "Current object balance (serialized XRP amount):", - &balance_buffer, - ); - } else { - let _ = trace_num( - "Current object balance length (non-XRP amount):", - balance_result as i64, - ); - let _ = trace_hex( - "Current object balance:", - &balance_buffer[..balance_result as usize], - ); - } - - // 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_acct_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_hex( - "Current nested field:", - ¤t_nested_buffer[..current_nested_result as usize], - ); - } - - // 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_hex( - "Cached object balance (serialized XRP amount):", - &cached_balance_buffer, - ); - } else { - let _ = trace_num( - "Cached object balance length (non-XRP amount):", - cached_balance_result as i64, - ); - let _ = trace_hex( - "Cached object balance:", - &cached_balance_buffer[..cached_balance_result as usize], - ); - } - - // 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_hex( - "Cached nested field:", - &cached_nested_buffer[..cached_nested_result as usize], - ); - } - - // 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_hex("Account keylet:", &accountroot_id_buffer); - - // 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_hex( - "Credential keylet:", - &credential_keylet_buffer[..credential_keylet_result as usize], - ); - } - - // 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_hex("Escrow keylet:", &escrow_keylet_buffer); - - // 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_hex("Oracle keylet:", &oracle_keylet_buffer); - - 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_hex("Input data:", test_data); - let _ = trace_hex("SHA512 half hash:", &hash_output); - - // 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_hex("NFT data:", &nft_buffer[..nft_result as usize]); - } - - // Test 6.3: trace() - Debug logging with data - let trace_message = b"Test trace message"; - let trace_data_payload = b"payload"; - unsafe { - host::trace( - trace_message.as_ptr(), - trace_message.len(), - TraceDataType::AsHex as i32, - trace_data_payload.as_ptr(), - trace_data_payload.len(), - ) - }; - - // Test 6.4: trace_num() - Debug logging with number - let test_number = 42i64; - trace_num("Test number trace", test_number); - - 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_hex("Successfully updated ledger entry with:", update_payload); - 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 6e82e804a7..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/Cargo.lock +++ /dev/null @@ -1,180 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "block-buffer" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" -dependencies = [ - "hybrid-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-common-stdlib", - "xrpl-escrow-stdlib", -] - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", -] - -[[package]] -name = "hybrid-array" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" -dependencies = [ - "typenum", -] - -[[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.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" -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 = "xrpl-common-stdlib" -version = "0.9.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#e88dc32a48fac9d0eb6e7239c8a38693221657f6" -dependencies = [ - "xrpl-macros", -] - -[[package]] -name = "xrpl-escrow-stdlib" -version = "0.9.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#e88dc32a48fac9d0eb6e7239c8a38693221657f6" -dependencies = [ - "xrpl-common-stdlib", -] - -[[package]] -name = "xrpl-macros" -version = "0.9.0" -source = "git+https://github.com/ripple/xrpl-wasm-stdlib.git#e88dc32a48fac9d0eb6e7239c8a38693221657f6" -dependencies = [ - "bs58", - "proc-macro2", - "quote", - "sha2", - "syn", -] 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 7a81244620..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/Cargo.toml +++ /dev/null @@ -1,19 +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-common-stdlib" } -xrpl-escrow = { git = "https://github.com/ripple/xrpl-wasm-stdlib.git", package = "xrpl-escrow-stdlib" } 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 7b42f747a8..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/src/host_bindings_loose.rs +++ /dev/null @@ -1,56 +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; - - // Same wasm functype as the real binding, so this is not a second import of - // host_lib.trace. Loose i32 pointers exercise the out-of-bounds path. - #[link_name = "trace"] - pub fn trace_loose( - msg_read_ptr: i32, - msg_read_len: i32, - data_type: i32, - data_read_ptr: i32, - data_read_len: 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 ef8f7b10de..0000000000 --- a/src/test/app/wasm_fixtures/codecov_tests/src/lib.rs +++ /dev/null @@ -1,1728 +0,0 @@ -#![cfg_attr(target_arch = "wasm32", no_std)] - -#[cfg(not(target_arch = "wasm32"))] -extern crate std; - -use core::panic; -use xrpl_escrow::current_tx::escrow_finish::{get_current_escrow_finish, EscrowFinish}; -use xrpl_std::current_tx::traits::TransactionCommonFields; -use xrpl_std::fields::locator::Locator; -use xrpl_std::host; -use xrpl_std::host::error_codes; -use xrpl_std::host::trace::TraceDataType; -use xrpl_std::host::trace::{trace, trace_num as trace_number}; -use xrpl_std::ledger_entry_ids; -use xrpl_std::sfield; -use xrpl_std::types::blob::DEFAULT_BLOB_SIZE; -use xrpl_std::types::contract_data::XRPL_CONTRACT_DATA_SIZE; -use xrpl_std::types::issue::Issue; -use xrpl_std::types::issue::XrpIssue; -use xrpl_std::types::mpt_id::MptId; - -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 = ledger_entry_ids::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"; - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Account as i32, - account.0.as_ptr(), - account.0.len(), - ) - }; - let amount = &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F]; // 95 drops of XRP - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Amount as i32, - amount.as_ptr(), - amount.len(), - ) - }; - let amount = &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; // 0 drops of XRP - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Amount as i32, - amount.as_ptr(), - amount.len(), - ) - }; - - // ######################################## - // 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", - ) - }); - - // Out-of-bounds message pointer; nothing to assert on now that trace is void. - let num_bytes = 42i64.to_le_bytes(); - unsafe { - host_bindings_loose::trace_loose( - locator.as_ptr() as i32 + 1_000_000_000, - locator.len() as i32, - TraceDataType::Int64 as i32, - num_bytes.as_ptr() as i32, - num_bytes.len() as i32, - ) - }; - - // ######################################## - // 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", - ) - }); - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::AsText as i32, - locator.as_ptr().wrapping_add(1_000_000_000), - locator.len(), - ) - }; - let float: [u8; 8] = [0xD4, 0x83, 0x8D, 0x7E, 0xA4, 0xC6, 0x80, 0x00]; - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Xfloat as i32, - float.as_ptr().wrapping_add(1_000_000_000), - float.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Amount as i32, - locator.as_ptr().wrapping_add(1_000_000_000), - locator.len(), - ) - }; - 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_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", - ) - }); - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Account as i32, - locator.as_ptr(), - locator.len(), - ) - }; - - // invalid Currency was already tested above - // invalid string - - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - TraceDataType::AsText as i32, - uint256.as_ptr(), - uint256.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - TraceDataType::Xfloat as i32, - float.as_ptr(), - float.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - TraceDataType::Account as i32, - account.0.as_ptr(), - account.0.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr().wrapping_add(1_000_000_000), - message.len(), - TraceDataType::Amount as i32, - amount.as_ptr(), - amount.len(), - ) - }; - - // trace too large - - unsafe { - host::trace( - locator.as_ptr(), - locator.len(), - TraceDataType::AsText as i32, - locator.as_ptr(), - long_len, - ) - }; - let too_long_num = 1i64.to_le_bytes(); - unsafe { - host::trace( - locator.as_ptr(), - long_len, - TraceDataType::Int64 as i32, - too_long_num.as_ptr(), - too_long_num.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr(), - long_len, - TraceDataType::Xfloat as i32, - float.as_ptr(), - float.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr(), - long_len, - TraceDataType::Account as i32, - account.0.as_ptr(), - account.0.len(), - ) - }; - unsafe { - host::trace( - message.as_ptr(), - long_len, - TraceDataType::Amount as i32, - amount.as_ptr(), - amount.len(), - ) - }; - - // trace amount errors - - unsafe { - host::trace( - message.as_ptr(), - message.len(), - TraceDataType::Amount as i32, - locator.as_ptr(), - locator.len(), - ) - }; - - // 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", - ) - }); - // Unknown data_type: the host logs "invalid arguments" and returns. - unsafe { - host::trace( - message.as_ptr(), - message.len(), - 99, - locator.as_ptr(), - locator.len(), - ) - }; - - // ensure that the Slice index desync issue is fixed - let empty: &[u8] = b""; - unsafe { - host::trace( - empty.as_ptr(), - empty.len(), - TraceDataType::Account as i32, - account.0.as_ptr(), - account.0.len(), - ) - }; - - 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 9c200b7d1b..0000000000 --- a/src/test/app/wasm_fixtures/fixtures.cpp +++ /dev/null @@ -1,648 +0,0 @@ -#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 = - "0061736d0100000001550c60027f7f017f60037f7f7f017f60047f7f7f7f017f60017f017f60067f7f7f7f7f7f017f" - "60037f7f7f0060057f7f7f7f7f0060087f7f7f7f7f7f7f7f017f60057f7f7f7f7f017f60017f0060027f7f00600001" - "7f02b1041808686f73745f6c69620874785f6669656c64000108686f73745f6c6962057472616365000608686f7374" - "5f6c69620a6c6467725f696e646578000008686f73745f6c696210706172656e745f6c6467725f74696d6500000868" - "6f73745f6c696210706172656e745f6c6467725f68617368000008686f73745f6c69620874785f696e6e6572000208" - "686f73745f6c69620a74785f6172725f6c656e000308686f73745f6c69621074785f696e6e65725f6172725f6c656e" - "000008686f73745f6c69620d686f6d655f6c655f6669656c64000108686f73745f6c69620d686f6d655f6c655f696e" - "6e6572000208686f73745f6c69620f686f6d655f6c655f6172725f6c656e000308686f73745f6c696215686f6d655f" - "6c655f696e6e65725f6172725f6c656e000008686f73745f6c69620863616368655f6c65000108686f73745f6c6962" - "0d63726564656e7469616c5f6964000708686f73745f6c696209657363726f775f6964000408686f73745f6c696209" - "6f7261636c655f6964000408686f73745f6c69620b7368613531325f68616c66000208686f73745f6c6962076e6674" - "5f757269000408686f73745f6c6962087365745f64617461000008686f73745f6c69620a6c655f6172725f6c656e00" - "0008686f73745f6c69620e6163636f756e74726f6f745f6964000208686f73745f6c6962106c655f696e6e65725f61" - "72725f6c656e000108686f73745f6c6962086c655f6669656c64000208686f73745f6c6962086c655f696e6e657200" - "08030b0a090a05050b000101030005030100110619037f01418080c0000b7f0041c698c0000b7f0041d098c0000b07" - "3504066d656d6f727902000d657363726f775f66696e697368001c0a5f5f646174615f656e6403010b5f5f68656170" - "5f6261736503020acf210a9d0101027f230041206b2201240020014200370310200142003703082001410036021820" - "00027f024041818020200141086a41141000220241004e0440200241144b0d01200241144704402000418180808078" - "36020441010c030b20002001280218360011200020012903103700092000200129030837000141000c020b20002002" - "36020441010c010b2000417336020441010b3a0000200141206a24000b5a01017f230041106b2202240020012d0000" - "41014604402002200134020437030841df97c000410b4101200241086a41081001000b200020012800113600102000" - "200129000937000820002001290001370000200241106a24000b1900200241214f0440000b20002002360204200020" - "013602000b1900200241094f0440000b20002002360204200020013602000bdd1e01077f230041c0036b2200240041" - "ea97c000411b4107410141001001418598c0004119410741014100100141b583c000412b4107410141001001200041" - "003602500240024002400240024002400240200041d0006a41041002220141004a044020002000280250220141ff81" - "fc0771410878200141187841ff81fc077172ad3703c00141e083c00041174101200041c0016a220241081001200041" - "003602800120004180016a41041003220141004c0d012000200028028001220141ff81fc0771410878200141187841" - "ff81fc077172ad3703c00141f783c00041134101200241081001200042003703d801200042003703d0012000420037" - "03c801200042003703c0012002412010042201412047044020002001ac3703a00141bd84c000412b4101200041a001" - "6a4108100141997f21030c080b418a84c00041134106200041c0016a220441201001419d84c0004120410741014100" - "100141aa85c000412e4107410141001001200041003602b001200042003703a801200042003703a001418180202000" - "41a0016a22024114100022014114470d0241d885c00041144104200241141001200042003703384188801820004138" - "6a22024108100022014108470d03200042083703c00141ec85c00041174101200441081001418386c0004128410620" - "02410810012000410036027841848008200041f8006a22024104100022014104470d0441ab86c00041154106200241" - "04100120004100360051200041013a005020004100360054200042003703d801200042003703d001200042003703c8" - "01200042003703c0010240200041d0006a4108200441201005220141004e044020002001ad3703800141c086c00041" - "14410120004180016a41081001200041306a20042001101a41d486c000410d41062000280230200028023410010c01" - "0b20002001ac3703800141e186c0004129410120004180016a410810010b20004183803c1006ac37038001418a87c0" - "004115410120004180016a22024108100120004189803c1006ac37038001419f87c000411341012002410810010240" - "200041d0006a41081007220141004e044020002001ad3703800141b287c000411441012002410810010c010b200020" - "01ac3703800141c687c000412d410120004180016a410810010b41f387c0004123410741014100100141e792c00041" - "3341074101410010012000420037033841828018200041386a220141081008220241004c0d05200241084604402000" - "42083703c001419a93c000412b4101200041c0016a4108100141c593c000412f41062001410810010c070b20002002" - "ad3703c00141f493c000412f4101200041c0016a41081001200041286a200041386a2002101b41a394c00041174106" - "2000280228200028022c10010c060b20002001ac3703c001418d85c000411d4101200041c0016a41081001419b7f21" - "030c060b20002001ac3703c00141e884c00041254101200041c0016a41081001419a7f21030c050b20002001ac3703" - "c001418289c000412a4101200041c0016a4108100141b77e21030c040b20002001ac3703c00141c188c00041c10041" - "01200041c0016a4108100141b67e21030c030b20002001ac3703c001419688c000412b4101200041c0016a41081001" - "41b57e21030c020b20002002ac3703c00141ba94c00041c5004101200041c0016a410810010b200041003602b00120" - "0042003703a801200042003703a001024041818020200041a0016a220241141008220141004a044041ff94c000411e" - "41042002411410010c010b20002001ac3703c001419d95c00041334101200041c0016a410810010b20004100360051" - "200041013a005020004100360054200042003703d801200042003703d001200042003703c801200042003703c00102" - "40200041d0006a4108200041c0016a220141201009220241004e044020002002ad3703800141d095c000411c410120" - "004180016a41081001200041206a20012002101a41ec95c000411541062000280220200028022410010c010b200020" - "02ac37038001418196c0004139410120004180016a410810010b20004183803c100aac3703800141ba96c000412441" - "0120004180016a2201410810010240200041d0006a4108100b220241004e044020002002ad3703800141de96c00041" - "1c41012001410810010c010b20002002ac3703800141fa96c000413d410120004180016a410810010b41b797c00041" - "28410741014100100141ac89c000412f4107410141001001200041c0016a2204101820004180016a22012004101920" - "0042003703b801200042003703b001200042003703a801200042003703a001024002400240024002402001200041a0" - "016a2202101d22014120460440200241204100100c220541004a044020002005ad3703c00141db89c0004123410120" - "0441081001200042003703782005200041f8006a22014108101e220241004c0d0220024108460440200042083703c0" - "0141fe89c000412a410120044108100141a88ac000412e41062001410810010c060b20002002ad3703c00141d68ac0" - "00412e4101200041c0016a41081001200041186a200041f8006a2002101b41848bc000411641062000280218200028" - "021c10010c050b20002005ac3703c00141bc8dc000413c4101200041c0016a220141081001200042003703d8012000" - "42003703d001200042003703c801200042003703c001410120014120101e22014100480d020c030b20002001ac3703" - "c001419090c000412e4101200041c0016a4108100141ef7c21030c050b20002002ac3703c001419a8bc000412b4101" - "200041c0016a410810010c020b20002001ac37035041f88dc00041c1004101200041d0006a410810010b2000410036" - "0039200041013a00382000410036003c4101200041386a200041c0016a101f2201410048044020002001ac37035041" - "b98ec00041354101200041d0006a410810010b410110202201410048044020002001ac37035041ee8ec00041324101" - "200041d0006a410810010b4101200041386a10212201410048044020002001ac37035041a08fc00041394101200041" - "d0006a410810010b41d98fc000413741074101410010010c010b20004100360039200041013a00382000410036003c" - "200042003703d801200042003703d001200042003703c801200042003703c00102402005200041386a200041c0016a" - "2201101f220241004e044020002002ad37035041c58bc000411b4101200041d0006a41081001200041106a20012002" - "101a41e08bc000411441062000280210200028021410010c010b20002002ac37035041f48bc00041314101200041d0" - "006a410810010b200020051020ac37035041a58cc00041234101200041d0006a22014108100102402005200041386a" - "1021220241004e044020002002ad37035041c88cc000411b41012001410810010c010b20002002ac37035041e38cc0" - "0041354101200041d0006a410810010b41988dc000412441074101410010010b41be90c000412f4107410141001001" - "200041c0016a22011018200041386a2204200110192000420037036820004200370360200042003703582000420037" - "0350024002402004200041d0006a2202101d2201412046044041ed90c000410f410620024120100120004200370398" - "012000420037039001200042003703880120004200370380010240200441142004411441fc90c00041092000418001" - "6a22014120100d220241004a0440200041086a20012002101a418491c000411241062000280208200028020c10010c" - "010b20002002ac3703c001419691c000413c4101200041c0016a410810010b200042003703b801200042003703b001" - "200042003703a801200042003703a00120004180808cc07e360270200041386a22044114200041f0006a4104200041" - "a0016a22024120100e22014120470d0141d291c000410e4106200241201001200042003703d801200042003703d001" - "200042003703c801200042003703c001200041808080d00236027420044114200041f4006a4104200041c0016a4120" - "100f2201412047044020002001ac370378419292c000411c4101200041f8006a4108100141887c21030c040b41e091" - "c000410e4106200041c0016a22044120100141ee91c00041244107410141001001418080c000412541074101410010" - "0120004200370398012000420037039001200042003703880120004200370380010240024041a580c0004117200041" - "80016a2202412010102201412046044041bc80c000410b410641a580c0004117100141c780c0004111410620024120" - "100120041018200041d0006a220620041019200042003703b801200042003703b001200042003703a8012000420037" - "03a00102404100200422036b410371220220036a220520034d0d0020020440200221010340200341003a0000200341" - "016a2103200141016b22010d000b0b200241016b4107490d000340200341003a0000200341076a41003a0000200341" - "066a41003a0000200341056a41003a0000200341046a41003a0000200341036a41003a0000200341026a41003a0000" - "200341016a41003a0000200341086a22032005470d000b0b200541800220026b2201417c716a220320054b04400340" - "20054100360200200541046a22052003490d000b0b024020032001410371220120036a22024f0d0020012205044003" - "40200341003a0000200341016a2103200541016b22050d000b0b200141016b4107490d000340200341003a00002003" - "41076a41003a0000200341066a41003a0000200341056a41003a0000200341046a41003a0000200341036a41003a00" - "00200341026a41003a0000200341016a41003a0000200341086a22032002470d000b0b20064114200041a0016a4120" - "20044180021011220141004c0d0120002001ad37033841d880c00041104101200041386a4108100120014181024f0d" - "0541e880c000410941062004200110010c020b20002001ac3703c00141e381c00041224101200041c0016a41081001" - "41a77b21030c050b20002001ac37033841f180c000412e4101200041386a410810010b419f81c0004112410641b181" - "c000410710012000422a3703384101210341b881c00041114101200041386a4108100141c981c000411a4107410141" - "001001418582c0004129410741014100100141ae82c000412810122201412847044020002001ac3703c001419b83c0" - "00411a4101200041c0016a4108100141c37a21030c040b41d682c0004127410641ae82c0004128100141fd82c00041" - "1e4107410141001001419e98c000412841074101410010010c030b20002001ac3703c00141ca92c000411d41012000" - "41c0016a41081001418b7c21030c020b20002001ac3703c00141ae92c000411c4101200041c0016a4108100141897c" - "21030c010b000b200041c0036a240020030b0c00200041142001412010140b0e002000418280182001200210160b0e" - "002000200141082002412010170b0a0020004183803c10130b0a0020002001410810150b0bd0180100418080c0000b" - "c6182d2d2d2043617465676f727920363a205574696c6974792046756e6374696f6e73202d2d2d48656c6c6f2c2058" - "52504c205741534d20776f726c6421496e70757420646174613a5348413531322068616c6620686173683a4e465420" - "64617461206c656e6774683a4e465420646174613a494e464f3a206765745f6e6674206661696c6564202865787065" - "63746564202d206e6f2073756368204e4654293a54657374207472616365206d6573736167657061796c6f61645465" - "7374206e756d626572207472616365535543434553533a205574696c6974792066756e6374696f6e734552524f523a" - "20636f6d707574655f7368613531325f68616c66206661696c65643a2d2d2d2043617465676f727920373a20446174" - "61205570646174652046756e6374696f6e73202d2d2d55706461746564206c656467657220656e7472792064617461" - "2066726f6d205741534d20746573745375636365737366756c6c792075706461746564206c656467657220656e7472" - "7920776974683a535543434553533a2044617461207570646174652066756e6374696f6e734552524f523a20757064" - "6174655f64617461206661696c65643a2d2d2d2043617465676f727920313a204c6564676572204865616465722046" - "756e6374696f6e73202d2d2d4c65646765722073657175656e6365206e756d6265723a506172656e74206c65646765" - "722074696d653a506172656e74206c656467657220686173683a535543434553533a204c6564676572206865616465" - "722066756e6374696f6e734552524f523a206765745f706172656e745f6c65646765725f686173682077726f6e6720" - "6c656e6774683a4552524f523a206765745f706172656e745f6c65646765725f74696d65206661696c65643a455252" - "4f523a206765745f6c65646765725f73716e206661696c65643a2d2d2d2043617465676f727920323a205472616e73" - "616374696f6e20446174612046756e6374696f6e73202d2d2d5472616e73616374696f6e204163636f756e743a5472" - "616e73616374696f6e20466565206c656e6774683a5472616e73616374696f6e20466565202873657269616c697a65" - "642058525020616d6f756e74293a5472616e73616374696f6e2053657175656e63653a4e6573746564206669656c64" - "206c656e6774683a4e6573746564206669656c643a494e464f3a206765745f74785f6e65737465645f6669656c6420" - "6e6f74206170706c696361626c653a5369676e657273206172726179206c656e6774683a4d656d6f73206172726179" - "206c656e6774683a4e6573746564206172726179206c656e6774683a494e464f3a206765745f74785f6e6573746564" - "5f61727261795f6c656e206e6f74206170706c696361626c653a535543434553533a205472616e73616374696f6e20" - "646174612066756e6374696f6e734552524f523a206765745f74785f6669656c642853657175656e6365292077726f" - "6e67206c656e6774683a4552524f523a206765745f74785f6669656c6428466565292077726f6e67206c656e677468" - "20286578706563746564203820627974657320666f7220585250293a4552524f523a206765745f74785f6669656c64" - "284163636f756e74292077726f6e67206c656e6774683a2d2d2d2043617465676f727920343a20416e79204c656467" - "6572204f626a6563742046756e6374696f6e73202d2d2d5375636365737366756c6c7920636163686564206f626a65" - "637420696e20736c6f743a436163686564206f626a6563742062616c616e6365206c656e677468202858525020616d" - "6f756e74293a436163686564206f626a6563742062616c616e6365202873657269616c697a65642058525020616d6f" - "756e74293a436163686564206f626a6563742062616c616e6365206c656e67746820286e6f6e2d58525020616d6f75" - "6e74293a436163686564206f626a6563742062616c616e63653a494e464f3a206765745f6c65646765725f6f626a5f" - "6669656c642842616c616e636529206661696c65643a436163686564206e6573746564206669656c64206c656e6774" - "683a436163686564206e6573746564206669656c643a494e464f3a206765745f6c65646765725f6f626a5f6e657374" - "65645f6669656c64206e6f74206170706c696361626c653a436163686564206f626a656374205369676e6572732061" - "72726179206c656e6774683a436163686564206e6573746564206172726179206c656e6774683a494e464f3a206765" - "745f6c65646765725f6f626a5f6e65737465645f61727261795f6c656e206e6f74206170706c696361626c653a5355" - "43434553533a20416e79206c6564676572206f626a6563742066756e6374696f6e73494e464f3a2063616368655f6c" - "65646765725f6f626a206661696c65642028657870656374656420776974682074657374206669787475726573293a" - "494e464f3a206765745f6c65646765725f6f626a5f6669656c64206661696c65642061732065787065637465642028" - "6e6f20636163686564206f626a656374293a494e464f3a206765745f6c65646765725f6f626a5f6e65737465645f66" - "69656c64206661696c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f626a5f6172" - "7261795f6c656e206661696c65642061732065787065637465643a494e464f3a206765745f6c65646765725f6f626a" - "5f6e65737465645f61727261795f6c656e206661696c65642061732065787065637465643a535543434553533a2041" - "6e79206c6564676572206f626a6563742066756e6374696f6e732028696e7465726661636520746573746564294552" - "524f523a206163636f756e74726f6f745f6964206661696c656420666f722063616368696e6720746573743a2d2d2d" - "2043617465676f727920353a204b65796c65742047656e65726174696f6e2046756e6374696f6e73202d2d2d416363" - "6f756e74206b65796c65743a546573745479706543726564656e7469616c206b65796c65743a494e464f3a20637265" - "64656e7469616c5f6b65796c6574206661696c656420286578706563746564202d20696e7465726661636520697373" - "7565293a457363726f77206b65796c65743a4f7261636c65206b65796c65743a535543434553533a204b65796c6574" - "2067656e65726174696f6e2066756e6374696f6e734552524f523a206f7261636c655f6b65796c6574206661696c65" - "643a4552524f523a20657363726f775f6b65796c6574206661696c65643a4552524f523a206163636f756e74726f6f" - "745f6964206661696c65643a2d2d2d2043617465676f727920333a2043757272656e74204c6564676572204f626a65" - "63742046756e6374696f6e73202d2d2d43757272656e74206f626a6563742062616c616e6365206c656e6774682028" - "58525020616d6f756e74293a43757272656e74206f626a6563742062616c616e6365202873657269616c697a656420" - "58525020616d6f756e74293a43757272656e74206f626a6563742062616c616e6365206c656e67746820286e6f6e2d" - "58525020616d6f756e74293a43757272656e74206f626a6563742062616c616e63653a494e464f3a206765745f6375" - "7272656e745f6c65646765725f6f626a5f6669656c642842616c616e636529206661696c656420286d617920626520" - "6578706563746564293a43757272656e74206c6564676572206f626a656374206163636f756e743a494e464f3a2067" - "65745f63757272656e745f6c65646765725f6f626a5f6669656c64284163636f756e7429206661696c65643a437572" - "72656e74206e6573746564206669656c64206c656e6774683a43757272656e74206e6573746564206669656c643a49" - "4e464f3a206765745f63757272656e745f6c65646765725f6f626a5f6e65737465645f6669656c64206e6f74206170" - "706c696361626c653a43757272656e74206f626a656374205369676e657273206172726179206c656e6774683a4375" - "7272656e74206e6573746564206172726179206c656e6774683a494e464f3a206765745f63757272656e745f6c6564" - "6765725f6f626a5f6e65737465645f61727261795f6c656e206e6f74206170706c696361626c653a53554343455353" - "3a2043757272656e74206c6564676572206f626a6563742066756e6374696f6e736572726f725f636f64653d3d3d3d" - "20484f53542046554e4354494f4e532054455354203d3d3d54657374696e6720323620686f73742066756e6374696f" - "6e73535543434553533a20416c6c20686f73742066756e6374696f6e2074657374732070617373656421004d097072" - "6f64756365727302086c616e6775616765010452757374000c70726f6365737365642d6279010572757374631d312e" - "39352e30202835393830373631366520323032362d30342d313429002c0f7461726765745f6665617475726573022b" - "0f6d757461626c652d676c6f62616c732b087369676e2d657874"; - -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 = - "0061736d01000000015c0c60067f7f7f7f7f7f017f60027f7f017f60047f7f7f7f017f60037f7f7f017f60077f7f7f" - "7f7f7f7f017f60087f7f7f7f7f7f7f7f017f60057f7f7f7f7f017f60017f017f60057f7f7f7f7f0060047f7f7f7f00" - "60017f006000017f02d8093608686f73745f6c6962057472616365000808686f73745f6c69620a6c6467725f696e64" - "6578000108686f73745f6c696210706172656e745f6c6467725f74696d65000108686f73745f6c696210706172656e" - "745f6c6467725f68617368000108686f73745f6c696208626173655f666565000108686f73745f6c696211616d656e" - "646d656e745f656e61626c6564000108686f73745f6c69620874785f6669656c64000308686f73745f6c69620e6163" - "636f756e74726f6f745f6964000208686f73745f6c69620863616368655f6c65000308686f73745f6c69620d686f6d" - "655f6c655f6669656c64000308686f73745f6c6962086c655f6669656c64000208686f73745f6c69620874785f696e" - "6e6572000208686f73745f6c69620d686f6d655f6c655f696e6e6572000208686f73745f6c6962086c655f696e6e65" - "72000608686f73745f6c69620a74785f6172725f6c656e000708686f73745f6c69620f686f6d655f6c655f6172725f" - "6c656e000708686f73745f6c69620a6c655f6172725f6c656e000108686f73745f6c69621074785f696e6e65725f61" - "72725f6c656e000108686f73745f6c696215686f6d655f6c655f696e6e65725f6172725f6c656e000108686f73745f" - "6c6962106c655f696e6e65725f6172725f6c656e000308686f73745f6c6962087365745f64617461000108686f7374" - "5f6c69620b7368613531325f68616c66000208686f73745f6c696209636865636b5f736967000008686f73745f6c69" - "62076e66745f757269000008686f73745f6c69620a6e66745f697373756572000208686f73745f6c6962096e66745f" - "7461786f6e000208686f73745f6c6962096e66745f666c616773000108686f73745f6c69620c6e66745f786665725f" - "666565000108686f73745f6c69620a6e66745f73657269616c000208686f73745f6c696208636865636b5f69640000" - "08686f73745f6c69620f666c6f61745f66726f6d5f75696e74000608686f73745f6c69620c74727573746c696e655f" - "6964000508686f73745f6c696206616d6d5f6964000008686f73745f6c69620d63726564656e7469616c5f69640005" - "08686f73745f6c69620a6d70746f6b656e5f6964000008686f73745f6c696209666c6f61745f636d70000208686f73" - "745f6c696209666c6f61745f616464000408686f73745f6c696209666c6f61745f737562000408686f73745f6c6962" - "0a666c6f61745f6d756c74000408686f73745f6c696209666c6f61745f646976000408686f73745f6c696209666c6f" - "61745f706f77000008686f73745f6c696209657363726f775f6964000008686f73745f6c69620f6d70745f69737375" - "616e63655f6964000008686f73745f6c69620c6e66745f6f666665725f6964000008686f73745f6c6962086f666665" - "725f6964000008686f73745f6c6962096f7261636c655f6964000008686f73745f6c69620a7061796368616e5f6964" - "000508686f73745f6c6962167065726d697373696f6e65645f646f6d61696e5f6964000008686f73745f6c69620974" - "69636b65745f6964000008686f73745f6c6962087661756c745f6964000008686f73745f6c69620b64656c65676174" - "655f6964000008686f73745f6c6962126465706f7369745f707265617574685f6964000008686f73745f6c69620664" - "69645f6964000208686f73745f6c69620a7369676e6572735f69640002030403090a0b05030100110619037f014180" - "80c0000b7f0041c698c0000b7f0041d098c0000b073504066d656d6f727902000d657363726f775f66696e69736800" - "380a5f5f646174615f656e6403010b5f5f686561705f6261736503020aa22e037201017f230041106b220424000240" - "02402000200147044020022003410741014100100020004100480d0120042000ad3703080c020b20042000ac370308" - "200220034101200441086a41081000200441106a24000f0b20042000ac3703080b418080c000410b4101200441086a" - "41081000000b2801017f230041106b2201240020012000ac37030841aa91c000410b4101200141086a41081000000b" - "832d02087f017e230041a0026b2200240041b591c0004123410741014100100020004100360260200041e0006a2201" - "41041001410441888ec000410a103620004100360260200141041002410441a683c000411010362000420037037820" - "0042003703702000420037036820004200370360200141201003412041a185c0004110103620004100360260200141" - "041004410441d888c000410810362000428182848890a0c080013703202000428182848890a0c08001370318200042" - "8182848890a0c080013703102000428182848890a0c0800137030841d891c000410e1005410141e691c00041111036" - "200041086a41201005410141e691c00041111036200041003602702000420037036820004200370360024002404181" - "802020014114100622014100480d00200141144b0440417321010c010b20014114460d0141808080807821010b2001" - "1037000b2000200029006c3700fd01200020002900673703f801200020002d00623a002e200020002f01603b012c20" - "00200028006336002f200020002903f801370033200020002900fd0137003820004200370378200042003703702000" - "42003703682000420037036002402000412c6a4114200041e0006a4120100722014120470440200141004e0d012001" - "1037000b200020002d00623a0042200020002f01603b01402000200029006f22083703800220002000280063360043" - "200020002900673700472000200837004f20002000290077370057200020002d007f3a005f200041406b4120410010" - "08410141f791c0004108103620004100360270200042003703682000420037036041818020200041e0006a22024114" - "1009411441a68fc000410d103620004100360270200042003703682000420037036041014181802020024114100a41" - "1441bf8cc0004108103602404100200041e4006a22046b410371220320046a220120044d0d00200304402003210503" - "40200441003a0000200441016a2104200541016b22050d000b0b200341016b4107490d000340200441003a00002004" - "41076a41003a0000200441066a41003a0000200441056a41003a0000200441046a41003a0000200441036a41003a00" - "00200441026a41003a0000200441016a41003a0000200441086a22042001470d000b0b2001413c20036b2203417c71" - "6a220420014b0440034020014100360200200141046a22012004490d000b0b024020042003410371220320046a2205" - "4f0d002003220104400340200441003a0000200441016a2104200141016b22010d000b0b200341016b4107490d0003" - "40200441003a0000200441076a41003a0000200441066a41003a0000200441056a41003a0000200441046a41003a00" - "00200441036a41003a0000200441026a41003a0000200441016a41003a0000200441086a22042005470d000b0b2000" - "41043602a00120004181802036026020004100360288022000420037038002200042003703f80120024104200041f8" - "016a22014114100b4114418388c0004108103620004100360288022000420037038002200042003703f80120022000" - "2802a00120014114100c411441e085c000410d103620004100360288022000420037038002200042003703f8014101" - "200220002802a00120014114100d4114418b86c000410810364189803c100e412041ff91c000410a10364189803c10" - "0f4120418992c000410f103641014189803c10104120419892c000410a1036200220002802a0011011412041a292c0" - "0041101036200220002802a0011012412041b292c000411510364101200220002802a0011013412041c792c0004110" - "10362000412c6a220341141014411441d792c000410810362000420037039002200042003703880220004200370380" - "02200042003703f801200220002802a001200141201015412041db82c000410b103641df92c000410c41eb92c00041" - "0b41f692c000410e10164101418493c00041091036200020002903203703c001200020002903183703b80120002000" - "2903103703b001200020002903083703a801200041003b0188022000420037038002200042003703f8012003411420" - "0041a8016a220541202001411210174112418c84c00041071036200041003602880220004200370380022000420037" - "03f801200541202001411410184114419386c000410a1036200041003602f80120054120200141041019410441c48a" - "c0004109103620054120101a4108418d93c0004109103620054120101b410a419693c000410c1036200041003602f8" - "012005412020014104101c410441818fc000410a103641a293c000410d410420034114100041a293c000410d410541" - "af93c0004108100041a293c000410d410541b793c00041081000417f41041003417141bf93c0004118103620004100" - "3602f8012001417f1003417141e686c00041181036200041003a00fa01200041003b01f801200141031003417d41f8" - "80c000411e1036200041003602f8012001418094ebdc0310034173419790c000411d10364102100e416f41d793c000" - "41191036417f20002802a0011011417141f093c000411810362002417f10114171418894c000411810362002418108" - "1011417441a094c00041191036200041e094ebdc036a220420002802a0011011417341b994c0004118103620004200" - "3703900220004200370388022000420037038002200042003703f801200341142004410820014120101d417341e283" - "c00041141036200042003703900220004200370388022000420037038002200042003703f801200341142003411420" - "014120101d417141eb84c00041161036200042003703900220004200370388022000420037038002200042003703f8" - "0120044108200141204100101e417341ea8ec000411710362000420037039002200042003703880220004200370380" - "02200042003703f801200220002802a001200141204100101e4171418185c00041201036200420002802a001410110" - "08417341d194c00041101036200220002802a00141011008417141e194c00041121036200042003703900220004200" - "370388022000420037038002200042003703f801200420002802a0012001412010074173418b8bc000411610362000" - "42003703900220004200370388022000420037038002200042003703f801200220002802a001200141201007417141" - "b683c00041181036200042003703900220004200370388022000420037038002200042003703f80120034114200341" - "14200420002802a00120014120101f417341c78cc000411d1036200042003703900220004200370388022000420037" - "038002200042003703f8012003411420034114200220002802a00120014120101f417141e489c000411f1036200042" - "003703900220004200370388022000420037038002200042003703f80141b298c0004114200420002802a001200141" - "201020417341a688c00041151036200042003703900220004200370388022000420037038002200042003703f80141" - "b298c0004114200220002802a001200141201020417141c787c000411b103620004200370390022000420037038802" - "2000420037038002200042003703f80141b298c000411441f394c0004114200141201020417141bb85c00041251036" - "200042003703900220004200370388022000420037038002200042003703f801418795c000412841b298c000411420" - "0141201020417141c98bc000412110362000200028013c3602dc01200020002901343702d4012000200029012c3702" - "cc01200041808080083602c801200041003b01f801200041c8016a2207411841b298c0004114200141021020417141" - "b185c000410a10362000422a3703e001200420002802a0014101200041e0016a41081000200041003b01f801410220" - "0141021006416f41af80c00041171036200041003b01f8014102200141021009416f419787c000411c103620004100" - "3b01f8014101410220014102100a416f41e682c000411710364102100e416f41d793c000411910364102100f416f41" - "af95c000411e1036410141021010416f41cd95c0004119103641d891c0004181081005417441e695c000411f103641" - "d891c00041c10010054174418596c000411a1036200041003b01f801200241810820014102100b417441f683c00041" - "161036200041003b01f801200241810820014102100c4174418b88c000411b1036200041003b01f801410120024181" - "0820014102100d4174419384c00041161036200241810810114174419f96c000411e103620024181081012417441bd" - "96c00041231036410120024181081013417441e096c000411e103620024181081014417441fe96c0004116103641a2" - "93c00041810841eb92c000410b41f692c000410e10164174418493c0004109103641a293c000410d41eb92c0004181" - "0841f692c000410e10164174418493c0004109103641a293c000410d41eb92c000410b41f692c00041810810164174" - "418493c00041091036200041003b01f8012002418108200141021015417441fe86c00041191036200041003b01f801" - "41b298c00041810841b298c0004114200141021020417441b58bc00041141036200041003b01f80120034114200341" - "142002418108200141021021417441c082c000411b1036200041003b01f80120074181082003411420014102102241" - "7441da80c000411e103641a293c000410d4107200420002802a0011000200042d487b6f4c7d4b1c0003700ec0141a2" - "93c000410d4103200041ec95ebdc036a22054108100041a293c000410d4105200420002802a0011000200541082000" - "41ec016a2204410810234173419497c0004114103620044108200541081023417341a897c00041141036200041003b" - "01f80120054108200441082001410241001024417341ac82c00041141036200041003b01f801200441082005410820" - "01410241001024417341ce83c00041141036200041003b01f80120054108200441082001410241001025417341a18b" - "c00041141036200041003b01f80120044108200541082001410241001025417341c680c00041141036200041003b01" - "f80120054108200441082001410241001026417341cd8ac00041151036200041003b01f80120044108200541082001" - "410241001026417341c781c00041151036200041003b01f80120054108200441082001410241001027417341b387c0" - "0041141036200041003b01f801200441082005410820014102410010274173419d86c00041141036200041003b01f8" - "0120054108410320014102410010284173419681c00041131036200042003703900220004200370388022000420037" - "038002200042003703f8012003411420034114200141201029417141ea8bc000411b10362000420037039002200042" - "00370388022000420037038002200042003703f801200341142003411420014120102a417141e287c0004121103620" - "0042003703900220004200370388022000420037038002200042003703f801200341142003411420014120102b4171" - "41a981c000411e1036200042003703900220004200370388022000420037038002200042003703f801200341142003" - "411420014120102c417141b48ec000411a103620004200370390022000420037038802200042003703800220004200" - "3703f801200341142003411420014120102d4171418b8fc000411b1036200042003703900220004200370388022000" - "420037038002200042003703f80120034114200341142003411420014120102e417141ce8ec000411c103620004200" - "3703900220004200370388022000420037038002200042003703f801200341142003411420014120102f417141e08d" - "c00041281036200042003703900220004200370388022000420037038002200042003703f801200341142003411420" - "0141201030417141b186c000411b1036200042003703900220004200370388022000420037038002200042003703f8" - "012003411420034114200141201031417141b490c000411a1036200220002802a00141001008417141bc97c000411b" - "1036200041003b01f80120034114200220002802a001200141021017417141cc86c000411a1036200041003b01f801" - "200220002802a001200141021018417141858cc000411d1036200041003b01f801200220002802a001200141021019" - "417141ce90c000411c1036200220002802a001101a417141d797c000411c1036200220002802a001101b417141f397" - "c000411f1036200041003602f801200220002802a00120014104101c417141a28cc000411d1036200041003b01f801" - "200220002802a0012001410210074171418b80c00041241036200041808080083602f401200041003b01f801200220" - "002802a001200041f4016a2205410420014102101d4171419f8dc000411e1036200041003b01f801200220002802a0" - "0122062003411420022006200141021021417141d28fc00041241036200041003b01f80120034114200220002802a0" - "01220620022006200141021021417141dc81c00041241036200041003b01f801200220002802a00120034114200141" - "021032417141838ac00041221036200041003b01f80120034114200220002802a001200141021032417141a984c000" - "41221036200041003b01f801200220002802a00120034114200141021033417141fd82c00041291036200041003b01" - "f80120034114200220002802a001200141021033417141e28ac00041291036200041003b01f801200220002802a001" - "2001410210344171418089c000411c1036200041003b01f801200220002802a00120054104200141021029417141b3" - "8fc000411f1036200041003b01f801200220002802a0012003411441f394c000411420014102101f417141c189c000" - "41231036200041003b01f80120034114200220002802a00141f394c000411420014102101f417141bd8dc000412310" - "36200041003b01f801200220002802a0012005410420014102102a4171419c89c00041251036200041003b01f80120" - "074118200220002802a001200141021022417141cb84c00041201036200041003b01f801200220002802a001200541" - "0420014102102b417141928ec00041221036200041003b01f801200220002802a0012005410420014102102c417141" - "ed85c000411e1036200041003b01f801200220002802a0012005410420014102102d417141a58ac000411f10362000" - "41003b01f801200220002802a001200341142005410420014102102e417141f68fc00041211036200041003b01f801" - "20034114200220002802a0012005410420014102102e417141ea90c00041211036200041003b01f801200220002802" - "a0012005410420014102102f4171418082c000412c1036200041003b01f801200220002802a0012001410210354171" - "41e088c00041201036200041003b01f801200220002802a001200541042001410210304171418b91c000411f103620" - "0041003b01f801200220002802a00120054104200141021031417141818dc000411e1036200041003b01f801200220" - "002802a001419298c0004120200141021017417141e48cc000411d103641a293c000410d4104200220002802a00110" - "0041a2a7abdd03410d4107419298c0004120100041a2a7abdd03410d410320044108100041a2a7abdd03410d410420" - "034114100041a2a7abdd03410d410541b793c00041081000200220002802a001410720024181081000200042013703" - "f8012002418108410120014108100041a293c000418108410320044108100041a293c0004181084104200341141000" - "41a293c000418108410541b793c0004108100041a293c000410d4105200220002802a0011000200041003b019e0220" - "0220002802a001200341142000419e026a41021022417141bb88c000411d103641a293c000410d41e3002002200028" - "02a0011000410141004104200341141000200041a0026a240041010f0b000b0b9d180200418080c0000b8715544553" - "54204641494c45446163636f756e74726f6f745f69645f77726f6e675f73697a655f6163636f756e745f696474785f" - "6669656c645f696e76616c69645f736669656c64666c6f61745f7375625f6f6f625f736c696365326d70746f6b656e" - "5f69645f746f6f5f6269675f736c6963655f6d70746964706172656e745f6c6467725f686173685f6275665f746f6f" - "5f736d616c6c666c6f61745f706f775f6f6f625f736c6963656e66745f6f666665725f69645f77726f6e675f73697a" - "655f75696e743332666c6f61745f6d756c745f6f6f625f736c6963653263726564656e7469616c5f69645f77726f6e" - "675f73697a655f6163636f756e745f6964327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f" - "73697a655f6163636f756e745f6964666c6f61745f6164645f6f6f625f736c6963653163726564656e7469616c5f69" - "645f746f6f5f6269675f736c6963657368613531325f68616c666c655f6669656c645f696e76616c69645f73666965" - "6c646465706f7369745f707265617574685f69645f77726f6e675f73697a655f6163636f756e745f69643170617265" - "6e745f6c6467725f74696d656163636f756e74726f6f745f69645f77726f6e675f6c656e666c6f61745f6164645f6f" - "6f625f736c69636532636865636b5f69645f6f6f625f6c656e5f75333274785f696e6e65725f746f6f5f6269675f73" - "6c6963656e66745f7572696c655f696e6e65725f746f6f5f6269675f736c69636564656c65676174655f69645f7772" - "6f6e675f73697a655f6163636f756e745f6964326d70746f6b656e5f69645f77726f6e675f73697a655f6163636f75" - "6e745f6964636865636b5f69645f77726f6e675f6c656e5f753332666c6f61745f66726f6d5f75696e745f77726f6e" - "675f6c656e5f75696e743634706172656e745f6c6467725f68617368616d6d5f69645f6d7074616d6d5f69645f6c65" - "6e5f77726f6e675f6e6f6e5f7872705f63757272656e63795f6c656e686f6d655f6c655f696e6e65726f666665725f" - "69645f77726f6e675f73697a655f6163636f756e745f69646c655f696e6e65726e66745f697373756572666c6f6174" - "5f6469765f6f6f625f736c696365327469636b65745f69645f77726f6e675f73697a655f75696e7433326e66745f75" - "72695f77726f6e675f73697a655f75696e74323536706172656e745f6c6467725f686173685f6e65675f6c656e7368" - "613531325f68616c665f746f6f5f6269675f736c696365686f6d655f6c655f6669656c645f696e76616c69645f7366" - "69656c64666c6f61745f6469765f6f6f625f736c69636531616d6d5f69645f6c656e5f77726f6e675f6c656e5f6173" - "736574326d70745f69737375616e63655f69645f77726f6e675f73697a655f75696e74333274785f696e6e6572686f" - "6d655f6c655f696e6e65725f746f6f5f6269675f736c696365616d6d5f69645f6c656e5f6f6f625f6173736574326d" - "70746f6b656e5f69645f6d707469645f77726f6e675f6c656e677468626173655f6665657369676e6572735f69645f" - "77726f6e675f73697a655f6163636f756e745f69646469645f69645f77726f6e675f73697a655f6163636f756e745f" - "69646d70745f69737375616e63655f69645f77726f6e675f73697a655f6163636f756e745f696474727573746c696e" - "655f69645f77726f6e675f73697a655f6163636f756e745f69643174727573746c696e655f69645f77726f6e675f6c" - "656e5f63757272656e637964656c65676174655f69645f77726f6e675f73697a655f6163636f756e745f6964316f72" - "61636c655f69645f77726f6e675f73697a655f6163636f756e745f69646e66745f7461786f6e666c6f61745f6d756c" - "745f6f6f625f736c696365316465706f7369745f707265617574685f69645f77726f6e675f73697a655f6163636f75" - "6e745f6964326163636f756e74726f6f745f69645f6c656e5f6f6f62666c6f61745f7375625f6f6f625f736c696365" - "31616d6d5f69645f746f6f5f6269675f736c696365616d6d5f69645f6c656e5f77726f6e675f7872705f6375727265" - "6e63795f6c656e657363726f775f69645f77726f6e675f73697a655f75696e7433326e66745f6973737565725f7772" - "6f6e675f73697a655f75696e743235366e66745f73657269616c5f77726f6e675f73697a655f75696e743235366c65" - "5f6669656c6474727573746c696e655f69645f6c656e5f6f6f625f63757272656e63796e66745f7572695f77726f6e" - "675f73697a655f6163636f756e745f69647661756c745f69645f77726f6e675f73697a655f6163636f756e745f6964" - "636865636b5f69645f77726f6e675f73697a655f6163636f756e745f696474727573746c696e655f69645f77726f6e" - "675f73697a655f6163636f756e745f6964327065726d697373696f6e65645f646f6d61696e5f69645f77726f6e675f" - "73697a655f75696e7433326c6467725f696e6465786e66745f6f666665725f69645f77726f6e675f73697a655f6163" - "636f756e745f69646f666665725f69645f77726f6e675f73697a655f75696e7433327061796368616e5f69645f7772" - "6f6e675f73697a655f75696e743332666c6f61745f66726f6d5f75696e745f6c656e5f6f6f626e66745f7365726961" - "6c6f7261636c655f69645f77726f6e675f73697a655f75696e743332686f6d655f6c655f6669656c64657363726f77" - "5f69645f77726f6e675f73697a655f6163636f756e745f696463726564656e7469616c5f69645f77726f6e675f7369" - "7a655f6163636f756e745f6964317061796368616e5f69645f77726f6e675f73697a655f6163636f756e745f696431" - "706172656e745f6c6467725f686173685f6c656e5f746f6f5f6c6f6e677661756c745f69645f77726f6e675f73697a" - "655f75696e7433326e66745f7461786f6e5f77726f6e675f73697a655f75696e743235367061796368616e5f69645f" - "77726f6e675f73697a655f6163636f756e745f6964327469636b65745f69645f77726f6e675f73697a655f6163636f" - "756e745f69646572726f725f636f64653d2424242424205354415254494e47205741534d20455845435554494f4e20" - "2424242424746573745f616d656e646d656e74616d656e646d656e745f656e61626c656463616368655f6c6574785f" - "6172725f6c656e686f6d655f6c655f6172725f6c656e6c655f6172725f6c656e74785f696e6e65725f6172725f6c65" - "6e686f6d655f6c655f696e6e65725f6172725f6c656e6c655f696e6e65725f6172725f6c656e7365745f6461746174" - "657374206d65737361676574657374207075626b657974657374207369676e6174757265636865636b5f7369676e66" - "745f666c6167736e66745f786665725f66656574657374696e67207472616365400000000000005f40000000000000" - "00706172656e745f6c6467725f686173685f6e65675f70747274785f6172725f6c656e5f696e76616c69645f736669" - "656c6474785f696e6e65725f6172725f6c656e5f6e65675f70747274785f696e6e65725f6172725f6c656e5f6e6567" - "5f6c656e74785f696e6e65725f6172725f6c656e5f746f6f5f6c6f6e6774785f696e6e65725f6172725f6c656e5f70" - "74725f6f6f6263616368655f6c655f7074725f6f6f6263616368655f6c655f77726f6e675f6c656e55534430303030" - "303030303030303030303030300041af95c0000b8303686f6d655f6c655f6172725f6c656e5f696e76616c69645f73" - "6669656c646c655f6172725f6c656e5f696e76616c69645f736669656c64616d656e646d656e745f656e61626c6564" - "5f746f6f5f6269675f736c696365616d656e646d656e745f656e61626c65645f746f6f5f6c6f6e6774785f696e6e65" - "725f6172725f6c656e5f746f6f5f6269675f736c696365686f6d655f6c655f696e6e65725f6172725f6c656e5f746f" - "6f5f6269675f736c6963656c655f696e6e65725f6172725f6c656e5f746f6f5f6269675f736c6963657365745f6461" - "74615f746f6f5f6269675f736c696365666c6f61745f636d705f6f6f625f736c69636531666c6f61745f636d705f6f" - "6f625f736c6963653263616368655f6c655f77726f6e675f73697a655f75696e743235366e66745f666c6167735f77" - "726f6e675f73697a655f75696e743235366e66745f786665725f6665655f77726f6e675f73697a655f75696e743235" - "363030303030303030303030303030303030303030303030303030303030303031004d0970726f6475636572730208" - "6c616e6775616765010452757374000c70726f6365737365642d6279010572757374631d312e39352e302028353938" - "30373631366520323032362d30342d313429002c0f7461726765745f6665617475726573022b0f6d757461626c652d" - "676c6f62616c732b087369676e2d657874"; - -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 ecb25b73da..0000000000 --- a/src/test/app/wasm_fixtures/fixtures.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#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/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index 44f7b4bdc4..f8c53e02bd 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -5,15 +5,24 @@ include(verify_headers) # Test requirements. find_package(GTest REQUIRED) -# Single combined gtest binary built from the shared test helpers and all test -# modules below. -add_executable( - xrpl_tests - main.cpp +add_library( + xrpl.testkit.wasm + STATIC helpers/Account.cpp helpers/TestSink.cpp helpers/TxTest.cpp + tx/wasm/fixtures/NftSetup.cpp + tx/wasm/fixtures/WasmLedger.cpp + tx/wasm/fixtures/WasmRun.cpp ) +target_include_directories(xrpl.testkit.wasm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries( + xrpl.testkit.wasm + PUBLIC xrpl.libxrpl xrpl_wasm_testkit_cxxbridge +) +add_dependencies(xrpl.testkit.wasm xrpl_crates) + +add_executable(xrpl_tests main.cpp) patch_nix_binary(xrpl_tests) set_target_properties( xrpl_tests @@ -21,10 +30,10 @@ set_target_properties( ) # Lets test sources include the shared helpers as . target_include_directories(xrpl_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(xrpl_tests PRIVATE GTest::gtest GTest::gmock xrpl.libxrpl) - -target_link_libraries(xrpl_tests PRIVATE xrpl_wasm_testkit_cxxbridge) -add_dependencies(xrpl_tests xrpl_crates) +target_link_libraries( + xrpl_tests + PRIVATE GTest::gtest GTest::gmock xrpl.libxrpl xrpl.testkit.wasm +) # One source subdirectory per module. Network unit tests are currently not # supported on Windows. @@ -55,6 +64,13 @@ foreach(module IN LISTS test_modules) "${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp" ) + # The framework-free half of tx/wasm/fixtures/ is compiled into xrpl.testkit.wasm, + # which this binary links; the rest of that folder belongs here. + list( + FILTER sources + EXCLUDE + REGEX "/fixtures/(NftSetup|WasmLedger|WasmRun)\\.cpp$" + ) target_sources(xrpl_tests PRIVATE ${sources}) # Expose the module's private headers under their canonical include path. diff --git a/src/tests/libxrpl/tx/wasm/NFTFixture.h b/src/tests/libxrpl/tx/wasm/NFTFixture.h deleted file mode 100644 index 559787ada4..0000000000 --- a/src/tests/libxrpl/tx/wasm/NFTFixture.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include -#include -#include - -namespace xrpl::test { - -struct NFTTest : RealHostFixture -{ - static constexpr std::uint16_t kFlags = nft::kFlagTransferable | nft::kFlagBurnable; - static constexpr std::uint16_t kFee = 314; - static constexpr std::uint32_t kTaxon = 12345; - static constexpr std::uint32_t kSequence = 7; - - static uint256 - makeNftId(AccountID const& issuer); - - // Mint a real NFToken owned by `issuer` (taxon 0) and return its id, read back from the - // owner's NFTokenPage. TxTest applies to the open ledger, which produces no metadata, so - // the id is recovered from ledger state rather than from the mint's metadata. - uint256 - mintNFT(Account const& issuer, std::optional uri = std::nullopt); -}; - -} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/Preflight.cpp b/src/tests/libxrpl/tx/wasm/Preflight.cpp index 2309fafd46..095ef4ced8 100644 --- a/src/tests/libxrpl/tx/wasm/Preflight.cpp +++ b/src/tests/libxrpl/tx/wasm/Preflight.cpp @@ -6,8 +6,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -29,7 +29,7 @@ constexpr std::string_view kRunnableWat = R"wat( } // namespace // `preflightEscrowWasm` takes no host, so this fixture holds none - which is the point of -// the signature, and what deriving from `WasmTest` would hide. Only a journal, to read the +// the signature, and what deriving from `MockVmTest` would hide. Only a journal, to read the // refusal out of. struct PreflightTest : testing::Test { diff --git a/src/tests/libxrpl/tx/wasm/README.md b/src/tests/libxrpl/tx/wasm/README.md new file mode 100644 index 0000000000..ed1621c8aa --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/README.md @@ -0,0 +1,90 @@ +# WASM host-function tests — layering + +These tests are deliberately **layered**: each layer isolates one thing, so a failure points at +one place instead of "somewhere in the stack." If a folder looks thin, the breadth it seems to be +missing lives in a sibling layer. + +## The layers + +| Layer | Location | host | VM | ledger | Answers | +| ------------------------------------- | --------------------------------------------------- | ---- | --- | ------ | ----------------------------------------------------------------------------------- | +| Engine / gas / limits / ABI | `crates/xrpl-wasm-vm`, `crates/xrpl-host-functions` | mock | ✓ | ✗ | gas, transfer budget, memory/field limits, preflight, VM limits, generated ABI | +| `host_context/` (`HostContextTest`) | `.../host_context` | mock | ✗ | ✗ | the `HostContext` marshalling shim alone (byte order, buffer sizing, `SField` xlat) | +| `host_calls/` (`HostCallTest`) | `.../host_calls` | mock | ✓ | ✗ | per-function **wire contract** — what the host was asked, what came back | +| `host_functions/` (`RealHostFixture`) | `.../host_functions` | real | ✗ | real | each function's **actual answer** vs. a real `TxTest` ledger | +| `e2e/` (`RealVmTest`) | `.../e2e` | real | ✓ | real | **full-stack integration** — VM + `HostContext` + real impl + real ledger | + +Run the C++ side with: + +```bash +./build/xrpl_tests --gtest_filter='*Impl.*:*Call.*:*E2e.*:WasmVMTest.*:WasmVMDeathTest.*:PreflightTest.*' +``` + +(707 tests, 136 suites.) The engine-level coverage is Rust: `cd crates && cargo test`. + +## `fixtures/` — split by whether it needs a test framework + +| | | +| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **No GTest** — the `xrpl.testkit.wasm` library | `WasmLedger` (real genesis ledger + the real host over it), `WasmRun` (WAT assembler), `NftSetup`, `FloatConstants` | +| **GTest** → `xrpl_tests` | `RealHostFixture` (`: testing::Test, WasmLedger` + `expectValue`/`expectError`/`expectKeyletMatches`), `FloatFixture`, `NFTFixture`, `MockHostFunctions`, `WasmFixture`, `RealVmTest`, `HostContextFixture` | + +A benchmark wants a ledger and a host, not GTest's lifecycle. Both binaries link the library; +`xrpl.bench.wasm` links no GTest and no GMock at all. + +Setup steps in `WasmLedger` and `NftSetup` **throw** (`fixtureFailed`) rather than using `EXPECT_`. +Not stylistic: an `EXPECT_` outside a running test is recorded and discarded, so a benchmark whose +escrow was never created would still run its host call, take the not-found path, and report a +cheap, plausible, completely wrong price. **If you add a setup step that can fail, throw.** + +## Gas calibration + +The benchmarks that price these host functions live in `src/benchmarks/libxrpl/wasm/`, mirroring +this tree one file per function, and have their own README. They link `xrpl.testkit.wasm` (above) +for the ledger and host, and no test framework. + +## What `e2e/` covers — the rule + +**`e2e/` covers every marshalling shape and cross-call convention exactly once. It does not cover +every function.** That is a completeness claim on the axis e2e uniquely tests, not a sample. + +`host_calls` pins what the bridge _asks_ with a _canned_ answer; `host_functions` pins what the +real impl _answers_. The type system guarantees they agree on signatures. Nothing guarantees they +agree on **conventions** — units, endianness, buffer layout — because in neither test does a real +guest write bytes a real host reads. That is exactly the `seq`-as-little-endian-region bug: every +internal test passed, and it was caught by cross-checking the guest SDK. + +Convention mismatch is a property of a call's **shape**, not of the function. All 19 keylets share +one shape, so a 19th keylet e2e proves nothing the 1st did. The inventory is meant to be exhaustive: + +| Shape / convention | Covered by | Why it is its own row | +| ----------------------------------------- | -------------------------- | -------------------------------------------------------- | +| no-input scalar getter | `LedgerSqnE2e` | header read; the minimal call | +| field code in, bytes out (ledger object) | `CurrentLedgerObjFieldE2e` | `SField` translation over a real object | +| field code in, bytes out (transaction) | `TxFieldE2e` | a different source than a ledger object | +| region in, bytes out + `u32` region | `CacheLedgerObjE2e` | the 4-byte little-endian region convention | +| slot in, bytes out — **cross-call state** | `CacheLedgerObjE2e` | the slot table is the only host state outliving one call | +| locator (path of i32 steps) | `TxNestedFieldE2e` | a wire format the guest writes and the host walks | +| **two** output regions | `FloatToMantExpE2e` | two bounds checks, two writes, an ordering between them | +| write / mutation | `SetDataE2e` | the one thing a contract changes | +| **error** path from a real impl | `HostErrorE2e` | a soft code from a real failure, not a staged one | +| realistic multi-call contract | `HostFunctionTourE2e` | the old `all_host_functions` tour shape, as one test | + +Adding a function needs no new e2e case unless it introduces a shape not in that table. Per-function +breadth lives in `host_functions/` and `host_calls/`, one case each. + +## Out of scope + +**The guest SDK** (`xrpl-std` / `xrpl-escrow`, external `xrpl-wasm-stdlib` repo) is not exercised +here — that is the SDK repo's own suite. These tests hand-write the ABI in WAT (raw imports, +literal field codes, hand-built byte layouts), deliberately bypassing all SDK code. Agreement is +verified _transitively_: the SDK repo tests the SDK against the ABI spec, this repo tests the host +against the same spec. That would not catch a drift where both diverge on an ambiguous point; +closing it needs a **cross-repo integration test** (compiled guests against a real host) in CI +where the Rust→wasm toolchain exists. + +**Transactor-level (L5) tests** are deferred: the redesign does not yet wire `runEscrowWasm` into +the `EscrowFinish` transactor, so there is no caller under `src/xrpld`. When it is wired, these +need a home as C++ transactor tests over a real `Env` — `set_data` persistence (including on +`tecBYTECODE_REJECTED`), `sfGasUsed` / `sfVMReturnCode` in transaction metadata, and owner-reserve +accounting for a bytecode-bearing escrow. The layers here deliberately stop at the VM boundary. diff --git a/src/tests/libxrpl/tx/wasm/WasmVM.cpp b/src/tests/libxrpl/tx/wasm/WasmVM.cpp index f4c771872a..59d1c9a2f2 100644 --- a/src/tests/libxrpl/tx/wasm/WasmVM.cpp +++ b/src/tests/libxrpl/tx/wasm/WasmVM.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include #include @@ -52,7 +53,7 @@ constexpr std::string_view kNoMemoryWat = R"wat( } // namespace -class WasmVMTest : public WasmTest +class WasmVMTest : public MockVmTest { }; diff --git a/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp new file mode 100644 index 0000000000..80635fee76 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/CacheLedgerObj.cpp @@ -0,0 +1,63 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test { + +// The keylet -> cache -> read round trip: the only place a contract's host calls depend on +// each other. Every other e2e case here is one call in isolation. This one is three, and each +// consumes what the last produced: `accountroot_id` computes a key into guest memory, `cache_le` +// hands those same bytes back to the host and answers with a slot number, and `le_field` +// uses that slot to read the object. The slot table is the one piece of host state that +// outlives a single call, so this is the only test at any layer that can catch the two ends +// of that state disagreeing — `host_calls` mocks the host, so its slot numbers are whatever +// the mock was told to return, and `host_functions` calls the impl directly, so its slots +// never cross the guest boundary at all. +struct CacheLedgerObjE2e : RealVmTest +{ +}; + +TEST_F(CacheLedgerObjE2e, ContractComputesAKeyCachesTheObjectAndReadsItsField) +{ + auto const owner = fund("owner"); + auto const wat = std::format( + R"wat( +(module + (import "host_lib" "accountroot_id" (func $accountroot_id (param i32 i32 i32 i32) (result i32))) + (import "host_lib" "cache_le" (func $cache_le (param i32 i32 i32) (result i32))) + (import "host_lib" "le_field" (func $le_field (param i32 i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (data (i32.const 0) "{}") + (func (export "escrow_finish") (result i32) + (local $slot i32) + (local $r i32) + ;; The account's AccountRoot keylet, computed by the host into offset 64. + (local.set $r (call $accountroot_id (i32.const 0) (i32.const 20) (i32.const 64) (i32.const 32))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + ;; Those same 32 bytes handed straight back: cache the object they name. + (local.set $slot (call $cache_le (i32.const 64) (i32.const 32) (i32.const 0))) + (if (i32.lt_s (local.get $slot) (i32.const 0)) (then (return (local.get $slot)))) + ;; And read a field of it through the slot the host just assigned. + (call $le_field (local.get $slot) (i32.const {}) (i32.const 128) (i32.const 32)))) +)wat", + watEscaped(RealHostFixture::toBytes(owner.id())), + sfAccount.getCode()); + + auto const outcome = run(wat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + // 20 bytes: the `sfAccount` the contract read back is the account it started from, so + // the key it computed found the right object. + EXPECT_EQ( + outcome->result, static_cast(RealHostFixture::toBytes(owner.id()).size())); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp new file mode 100644 index 0000000000..839aaedd1d --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/CurrentLedgerObjField.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test { + +// A contract reads a field of its current ledger object (a real escrow) end to end: the real +// VM runs the guest, `HostContext` marshals the field code into an `SField`, the real impl +// reads the real ledger, and the byte count comes back to the guest. `host_calls/` proves the +// marshalling with a mock and `host_functions/` proves the impl's answer without a VM; this +// proves the two agree over a real ledger. +struct CurrentLedgerObjFieldE2e : RealVmTest +{ + // Create a real escrow owned by `owner` and return its keylet — the object the contract + // runs against. + Keylet + makeEscrow(Account const& owner, Account const& dest) + { + ledger.createAccount(owner, XRP(1000)); + ledger.createAccount(dest, XRP(1000)); + auto const ownerSeq = ledger.getAccountRoot(owner.id()).getSequence(); + auto const r = ledger.submit( + transactions::EscrowCreateBuilder{owner.id(), dest.id(), XRP(100)}.setFinishAfter( + 900'000'000), + owner); + EXPECT_EQ(r.ter, tesSUCCESS) << transToken(r.ter); + ledger.close(); + return keylet::escrow(owner.id(), SeqProxy::rawSequence(ownerSeq)); + } +}; + +TEST_F(CurrentLedgerObjFieldE2e, ContractReadsAFieldOfItsRealEscrow) +{ + auto const owner = Account{"owner"}; + auto const escrow = makeEscrow(owner, Account{"dest"}); + + // Ask the current object for `sfAccount` and return the byte count the host wrote — 20 for + // an account id — proving the read reached the real ledger and came back through the VM. + auto const wat = std::format( + R"wat( +(module + (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (call $home_le_field (i32.const {}) (i32.const 0) (i32.const 32)))) +)wat", + sfAccount.getCode()); + + auto const outcome = run(wat, escrow); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, static_cast(toBytes(owner.id()).size())); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp new file mode 100644 index 0000000000..a70fdb07ce --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/FloatToMantExp.cpp @@ -0,0 +1,66 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test { + +// The only host function that writes to *two* output regions, and so the only place the +// "one call, one answer" assumption in every other marshalling path is not what happens. +// `float_to_mant_exp` splits a float into an eight-byte mantissa and a four-byte exponent, +// each into its own guest buffer, and answers with a status rather than a byte count. Two +// regions means two independent bounds checks, two writes, and an ordering between them — +// none of which the single-output shapes exercise. `host_calls` pins that wiring against a +// mock; this proves the real impl drives it the same way, with the guest reading both +// halves back out of its own memory. +struct FloatToMantExpE2e : RealVmTest +{ +}; + +TEST_F(FloatToMantExpE2e, ContractReadsBothHalvesOfASplitFloat) +{ + // Pi's canonical encoding in, mantissa to offset 64, exponent to offset 128. The + // contract returns the low half of the mantissa so the assertion checks that real bytes + // landed in the guest's buffer, not merely that the call reported success. + auto const wat = std::format( + R"wat( +(module + (import "host_lib" "float_to_mant_exp" (func $split (param i32 i32 i32 i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (data (i32.const 0) "{}") + (func (export "escrow_finish") (result i32) + (local $r i32) + (local.set $r (call $split + (i32.const 0) (i32.const 12) + (i32.const 64) (i32.const 8) + (i32.const 128) (i32.const 4))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + (i32.load (i32.const 64)))) +)wat", + watEscaped(FloatTest::kPi)); + + auto const outcome = run(wat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + + // The expected value is derived from the input rather than written out as a literal, + // because the derivation is the interesting part: a float stores its mantissa in the + // first eight bytes **big-endian**, while `float_to_mant_exp` writes it to the guest + // **little-endian**. So the guest's `i32.load` at the start of the mantissa buffer sees + // the *low* 32 bits of a number whose bytes arrived in the opposite order. Getting that + // flip wrong is exactly the convention mismatch this layer exists to catch, and a + // hard-coded constant would hide it. + auto mantissa = std::int64_t{0}; + for (auto i = 0U; i < 8; ++i) + { + mantissa = (mantissa << 8) | FloatTest::kPi[i]; + } + EXPECT_EQ(outcome->result, static_cast(mantissa & 0xFFFFFFFF)); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp new file mode 100644 index 0000000000..3b7203b415 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/HostError.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test { + +// The error channel, driven by a real failure rather than a mock's canned one. +// Every other e2e case here proves a success path. But a contract spends most of its life +// reacting to codes, and the path a *real* error takes is different from the one a mock +// error takes: the impl returns a `HostFunctionError`, `HostContext` turns it into a wire +// code, and the engine hands that back to the guest as a negative i32 without disturbing the +// run. `host_calls` proves the middle step against a mock that was *told* to fail; nothing +// until now has proved that a real impl's real failure comes out the far end intact. +struct HostErrorE2e : RealVmTest +{ +}; + +TEST_F(HostErrorE2e, ARealHostErrorReachesTheGuestAsItsWireCode) +{ + // The contract runs against an account root, then asks it for `sfMemoData` — a field + // that object does not carry. The impl genuinely fails to find it, so the code the + // guest reads was produced by the real lookup rather than staged. + auto const owner = fund("owner"); + + auto const wat = std::format( + R"wat( +(module + (import "host_lib" "home_le_field" (func $home_le_field (param i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (call $home_le_field (i32.const {}) (i32.const 0) (i32.const 32)))) +)wat", + sfMemoData.getCode()); + + auto const outcome = run(wat, keylet::account(owner.id())); + + // The run itself succeeds: a soft host error is an answer to the contract, not a fault + // in it. Reporting it as a failed run would be the interesting bug here. + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, static_cast(HostFunctionError::FieldNotFound)); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp b/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp new file mode 100644 index 0000000000..ed3570aab5 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/HostFunctionTour.cpp @@ -0,0 +1,49 @@ +#include + +#include +#include + +#include + +namespace xrpl::test { + +// A single contract that tours several host functions end to end — a ledger-header read, the +// base fee, a hash, a keylet, and a data write — returning 1 only if every call succeeds. +struct HostFunctionTourE2e : RealVmTest +{ +}; + +TEST_F(HostFunctionTourE2e, AContractTouringManyHostFunctionsSucceeds) +{ + // Each call must return >= 0 (a byte count, i.e. success); the guest returns the first + // negative error code, or 1 if the whole tour succeeds. Output regions are disjoint so no + // call clobbers another, and buffers are generous so exact value sizes don't matter. + static constexpr auto kWat = std::string_view{R"wat( +(module + (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) + (import "host_lib" "base_fee" (func $base_fee (param i32 i32) (result i32))) + (import "host_lib" "sha512_half" (func $sha512_half (param i32 i32 i32 i32) (result i32))) + (import "host_lib" "accountroot_id" (func $accountroot_id (param i32 i32 i32 i32) (result i32))) + (import "host_lib" "set_data" (func $set_data (param i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (local $r i32) + (local.set $r (call $ldgr_index (i32.const 0) (i32.const 32))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + (local.set $r (call $base_fee (i32.const 32) (i32.const 32))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + (local.set $r (call $sha512_half (i32.const 0) (i32.const 4) (i32.const 64) (i32.const 32))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + (local.set $r (call $accountroot_id (i32.const 0) (i32.const 20) (i32.const 128) (i32.const 32))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + (local.set $r (call $set_data (i32.const 0) (i32.const 8))) + (if (i32.lt_s (local.get $r) (i32.const 0)) (then (return (local.get $r)))) + (i32.const 1))) +)wat"}; + + auto const outcome = run(kWat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, 1) << "every host call in the tour should have succeeded"; +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp new file mode 100644 index 0000000000..824cd19f45 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/LedgerSqn.cpp @@ -0,0 +1,33 @@ +#include + +#include +#include + +#include +#include + +namespace xrpl::test { + +// The real ledger's sequence. +struct LedgerSqnE2e : RealVmTest +{ +}; + +TEST_F(LedgerSqnE2e, ContractReadsTheRealLedgerSequence) +{ + // Ask the host for the ledger sequence into offset 0, then return the i32 stored there. + static constexpr auto kWat = std::string_view{R"wat( +(module + (import "host_lib" "ldgr_index" (func $ldgr_index (param i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (drop (call $ldgr_index (i32.const 0) (i32.const 4))) + (i32.load (i32.const 0)))) +)wat"}; + + auto const outcome = run(kWat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, static_cast(ledger.getOpenLedger().header().seq)); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp new file mode 100644 index 0000000000..130c812dc8 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/SetData.cpp @@ -0,0 +1,31 @@ +#include + +#include +#include + +#include + +namespace xrpl::test { + +// A contract writes its data field end to end. +struct SetDataE2e : RealVmTest +{ +}; + +TEST_F(SetDataE2e, ContractWritesItsData) +{ + // `set_data` over 8 bytes of (zero-initialized) memory returns the byte count it stored. + static constexpr auto kWat = std::string_view{R"wat( +(module + (import "host_lib" "set_data" (func $set_data (param i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (call $set_data (i32.const 0) (i32.const 8)))) +)wat"}; + + auto const outcome = run(kWat); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, 8); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp new file mode 100644 index 0000000000..54c66c1e9e --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/TxField.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test { + +// A contract reads a field of its transaction end to end. +struct TxFieldE2e : RealVmTest +{ +}; + +TEST_F(TxFieldE2e, ContractReadsAFieldOfItsTransaction) +{ + auto const owner = Account{"owner"}; + ledger.createAccount(owner, XRP(1000)); + static constexpr auto kScale = std::uint8_t{8}; + auto const tx = mptIssuanceCreateTx(owner, kScale); + + // Ask the tx for `sfAssetScale` (a single byte) and return the i32 the guest loads — the + // scale, zero-extended — so the assertion checks the value flowed through, not just a count. + auto const wat = std::format( + R"wat( +(module + (import "host_lib" "tx_field" (func $tx_field (param i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (drop (call $tx_field (i32.const {}) (i32.const 0) (i32.const 4))) + (i32.load (i32.const 0)))) +)wat", + sfAssetScale.getCode()); + + auto const outcome = run(wat, keylet::account(owner.id()), tx.type, tx.build); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + EXPECT_EQ(outcome->result, kScale); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp new file mode 100644 index 0000000000..224e3bb525 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/e2e/TxNestedField.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace xrpl::test { + +// The locator convention, end to end. +struct TxNestedFieldE2e : RealVmTest +{ + // An EscrowFinish carrying a memo, so the locator has a real leaf to reach. + TxAssembler + withMemo(Account const& acct) + { + auto assembler = escrowFinishTx(ledger, acct); + assembler.build = [inner = std::move(assembler.build)](STObject& obj) { + inner(obj); + auto memos = STArray{}; + auto memo = STObject::makeInnerObject(sfMemo); + memo.setFieldVL(sfMemoData, Slice{"hello", 5}); + memos.push_back(std::move(memo)); + obj.setFieldArray(sfMemos, memos); + }; + return assembler; + } +}; + +TEST_F(TxNestedFieldE2e, ContractWalksALocatorToANestedTransactionField) +{ + auto const owner = fund("owner"); + auto assembler = withMemo(owner); + + auto const wat = std::format( + R"wat( +(module + (import "host_lib" "tx_inner" (func $tx_inner (param i32 i32 i32 i32) (result i32))) + (memory (export "memory") 1) + (func (export "escrow_finish") (result i32) + (i32.store (i32.const 0) (i32.const {})) + (i32.store (i32.const 4) (i32.const 0)) + (i32.store (i32.const 8) (i32.const {})) + (call $tx_inner (i32.const 0) (i32.const 12) (i32.const 64) (i32.const 32)))) +)wat", + sfMemos.getCode(), + sfMemoData.getCode()); + + auto const outcome = run(wat, keylet::account(owner.id()), assembler.type, assembler.build); + ASSERT_TRUE(outcome.has_value()) << transToken(outcome.error().ter); + // Five bytes: "hello", the memo's data, reached through the locator. + EXPECT_EQ(outcome->result, 5); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/FloatFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/FloatConstants.h similarity index 91% rename from src/tests/libxrpl/tx/wasm/FloatFixture.h rename to src/tests/libxrpl/tx/wasm/fixtures/FloatConstants.h index d643f7f39a..fe7be63c8d 100644 --- a/src/tests/libxrpl/tx/wasm/FloatFixture.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/FloatConstants.h @@ -3,15 +3,17 @@ #include #include -#include - #include #include #include +// Canonical float encodings, with no ledger and no test framework behind them — just the byte +// patterns the float host functions take and return. Benchmarks include this directly; +// `FloatFixture.h` mixes it into the GTest fixture the `host_functions/` tests use. + namespace xrpl::test { -struct FloatTest : RealHostFixture +struct FloatConstants { static constexpr std::int64_t kMin64 = std::numeric_limits::min(); static constexpr std::int64_t kMax64 = std::numeric_limits::max(); diff --git a/src/tests/libxrpl/tx/wasm/fixtures/FloatFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/FloatFixture.h new file mode 100644 index 0000000000..926a6f5943 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/FloatFixture.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +// The float constants with a real ledger and GTest attached, for the `host_functions/Float*` +// tests. The constants alone are in FloatConstants.h, which links no test framework. + +namespace xrpl::test { + +struct FloatTest : RealHostFixture, FloatConstants +{ +}; + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/HostContextFixture.cpp b/src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.cpp similarity index 96% rename from src/tests/libxrpl/tx/wasm/HostContextFixture.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.cpp index cf5efc0453..fd0fd5d4bc 100644 --- a/src/tests/libxrpl/tx/wasm/HostContextFixture.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/HostContextFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.h similarity index 98% rename from src/tests/libxrpl/tx/wasm/HostContextFixture.h rename to src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.h index 1677014b8a..3789b3b7fa 100644 --- a/src/tests/libxrpl/tx/wasm/HostContextFixture.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/HostContextFixture.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/MockHostFunctions.h b/src/tests/libxrpl/tx/wasm/fixtures/MockHostFunctions.h similarity index 100% rename from src/tests/libxrpl/tx/wasm/MockHostFunctions.h rename to src/tests/libxrpl/tx/wasm/fixtures/MockHostFunctions.h diff --git a/src/tests/libxrpl/tx/wasm/fixtures/NFTFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/NFTFixture.h new file mode 100644 index 0000000000..9a163b2ca0 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/NFTFixture.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include +#include +#include + +#include +#include + +// The NFToken helpers with a real ledger and GTest attached, for the `host_functions/NFT*` tests. +// The ledger-only versions are in NftSetup.h, which links no test framework. + +namespace xrpl::test { + +struct NFTTest : RealHostFixture, NftIds +{ + uint256 + mintNFT(Account const& issuer, std::optional uri = std::nullopt) + { + return mintNft(*this, issuer, uri); + } +}; + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/NFTFixture.cpp b/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.cpp similarity index 59% rename from src/tests/libxrpl/tx/wasm/NFTFixture.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/NftSetup.cpp index 0bf1ea023c..bdaf29c8f9 100644 --- a/src/tests/libxrpl/tx/wasm/NFTFixture.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -10,28 +10,33 @@ #include // IWYU pragma: keep #include -#include #include +#include #include +#include #include namespace xrpl::test { uint256 -NFTTest::makeNftId(AccountID const& issuer) +NftIds::makeNftId(AccountID const& issuer) { return NFTokenMint::createNFTokenID(kFlags, kFee, issuer, nft::toTaxon(kTaxon), kSequence); } uint256 -NFTTest::mintNFT(Account const& issuer, std::optional uri) +mintNft(WasmLedger& fixture, Account const& issuer, std::optional uri) { + auto& ledger = fixture.ledger; auto builder = transactions::NFTokenMintBuilder{issuer.id(), 0u}; if (uri) builder.setURI(Slice{uri->data(), uri->size()}); auto const r = ledger.submit(builder, issuer); - EXPECT_EQ(r.ter, tesSUCCESS) << transToken(r.ter); + if (r.ter != tesSUCCESS) + { + fixtureFailed(std::string{"minting the NFToken: "} + transToken(r.ter)); + } ledger.close(); // The single minted token lives in the owner's first NFTokenPage. @@ -39,14 +44,21 @@ NFTTest::mintNFT(Account const& issuer, std::optional uri) auto const first = keylet::nftokenPageMin(issuer.id()).key; auto const last = keylet::nftokenPageMax(issuer.id()).key; auto const pageKey = view.succ(first, last.next()); - EXPECT_TRUE(pageKey.has_value()); - auto const page = pageKey ? view.read(Keylet{ltNFTOKEN_PAGE, *pageKey}) : nullptr; - EXPECT_NE(page, nullptr); - if (!page) - return uint256{}; + if (!pageKey.has_value()) + { + fixtureFailed("finding the minted token's NFTokenPage"); + } + auto const page = view.read(Keylet{ltNFTOKEN_PAGE, *pageKey}); + if (page == nullptr) + { + fixtureFailed("reading the minted token's NFTokenPage"); + } auto const& tokens = page->getFieldArray(sfNFTokens); - EXPECT_FALSE(tokens.empty()); - return tokens.empty() ? uint256{} : tokens[0].getFieldH256(sfNFTokenID); + if (tokens.empty()) + { + fixtureFailed("the NFTokenPage holds no tokens"); + } + return tokens[0].getFieldH256(sfNFTokenID); } } // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.h b/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.h new file mode 100644 index 0000000000..93e3f798f1 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/NftSetup.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include + +// NFToken setup, built on `WasmLedger` rather than on a GTest fixture so a benchmark can mint a +// token without linking a test framework. Tests reach the same helpers through +// `RealHostFixture`, which derives from `WasmLedger`. + +namespace xrpl::test { + +// The fields baked into `makeNftId`, so a caller can assert an extractor returned the right one. +struct NftIds +{ + static constexpr std::uint16_t kFlags = nft::kFlagTransferable | nft::kFlagBurnable; + static constexpr std::uint16_t kFee = 314; + static constexpr std::uint32_t kTaxon = 12345; + static constexpr std::uint32_t kSequence = 7; + + // A well-formed id carrying the constants above. Computed, not minted: the id-extractor host + // functions read the id itself and never touch the ledger. + static uint256 + makeNftId(AccountID const& issuer); +}; + +// Mint a real NFToken owned by `issuer` (taxon 0) and return its id, read back from the owner's +// NFTokenPage. `TxTest` applies to the open ledger, which produces no metadata, so the id comes +// from ledger state rather than from the mint's metadata. +// +// Throws via `fixtureFailed` if the mint or the page lookup fails; see WasmLedger.h for why that +// is a throw and not an `EXPECT_`. +uint256 +mintNft( + WasmLedger& fixture, + Account const& issuer, + std::optional uri = std::nullopt); + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.cpp b/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.cpp new file mode 100644 index 0000000000..6380f301f6 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.cpp @@ -0,0 +1,16 @@ +#include + +#include +#include + +#include + +namespace xrpl::test { + +void +expectKeyletMatches(std::expected const& result, Keylet const& expected) +{ + expectValue(result, RealHostFixture::toBytes(expected.key)); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.h new file mode 100644 index 0000000000..f9bdb6b049 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/RealHostFixture.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include + +#include +#include + +#include +#include + +// The GTest layer over `WasmLedger`: the assertion helpers, and the fixture base the +// `host_functions/` tests derive from. +// +// Everything that touches a ledger or builds a host lives in `WasmLedger.h`, which knows nothing +// about GTest so the benchmarks can share it. Only what genuinely needs the framework is here. + +namespace xrpl::test { + +template +void +expectValue( + std::expected const& result, + U const& expected, + std::source_location loc = std::source_location::current()) +{ + auto trace = testing::ScopedTrace{loc.file_name(), static_cast(loc.line()), ""}; + ASSERT_TRUE(result.has_value()) + << "expected a value, got error " << static_cast(result.error()); + EXPECT_EQ(*result, expected); +} + +template +void +expectError( + std::expected const& result, + HostFunctionError expected, + std::source_location loc = std::source_location::current()) +{ + auto trace = testing::ScopedTrace{loc.file_name(), static_cast(loc.line()), ""}; + ASSERT_FALSE(result.has_value()) << "expected error, got a value"; + EXPECT_EQ(result.error(), expected); +} + +void +expectKeyletMatches(std::expected const& result, Keylet const& expected); + +// A `WasmLedger` with GTest's lifecycle attached. Tests derive from this; benchmarks use +// `WasmLedger` directly. +struct RealHostFixture : testing::Test, WasmLedger +{ +}; + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/fixtures/RealVmTest.h b/src/tests/libxrpl/tx/wasm/fixtures/RealVmTest.h new file mode 100644 index 0000000000..a2bed7bc4d --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/RealVmTest.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace xrpl::test { + +// End-to-end: a WAT contract run through the REAL VM against the REAL host +// over a REAL `TxTest` ledger. +struct RealVmTest : RealHostFixture +{ + // Assemble `wat` and run its `entryPoint` through the real VM against a real host built + // over the current open ledger. `leKey`/`txType`/`assembler` configure the ledger object + // the contract runs against and the transaction it reads. + std::expected + run( + std::string_view wat, + Keylet const& leKey = keylet::account(AccountID{}), + TxType txType = ttESCROW_FINISH, + std::function assembler = [](STObject&) {}, + std::int64_t gas = kAmpleGas, + std::string_view entryPoint = escrowFunctionName) + { + auto host = makeHost(leKey, txType, std::move(assembler)); + return runWat(*host, wat, gas, entryPoint); + } +}; + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/WasmFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/WasmFixture.h similarity index 77% rename from src/tests/libxrpl/tx/wasm/WasmFixture.h rename to src/tests/libxrpl/tx/wasm/fixtures/WasmFixture.h index 662752806e..28099f0a97 100644 --- a/src/tests/libxrpl/tx/wasm/WasmFixture.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmFixture.h @@ -8,8 +8,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -18,30 +18,16 @@ namespace xrpl::test { -// Assemble `wat`. Throws `rust::Error` on a typo, which gtest reports against the test that -// holds it. -// -// A free function because not every wasm test needs a host: `preflightEscrowWasm` takes none, -// so its fixture derives from `testing::Test` rather than from `WasmTest`. -inline Bytes -assembleWat(std::string_view wat) -{ - auto const wasm = rs::wasm_testkit::compile_wat(rust::Str{wat.data(), wat.size()}); - return Bytes{wasm.begin(), wasm.end()}; -} - -// Base for every wasm test that runs a contract: a mocked host whose log is captured, and one -// way into the engine. +// Base for every wasm test that runs a contract against a MOCKED host whose log is captured. +// Its real-host counterpart is `RealVmTest`; both run a WAT guest through the real VM and +// forward to the shared `runWat` harness (`WasmRun.h`), differing only in the host. // // Modules are written as WebAssembly text and assembled by `assembleWat`. The assembler is in // a test-only crate: the engine itself refuses text // (`the_vm_refuses_a_text_format_module`), because a text assembler on the consensus path // would make a transaction's validity a build flag. -struct WasmTest : testing::Test +struct MockVmTest : testing::Test { - // Enough for every module here to run to completion; a test about budgets passes its own. - static constexpr std::int64_t kAmpleGas = 100'000; - // Keeps what a run logged. The host's default journal is a null sink, which would let a // swallowed condition pass a test that only checks the TER. CaptureSink sink{beast::Severity::Warning}; @@ -51,7 +37,7 @@ struct WasmTest : testing::Test // something on its own — which is the kind of surprise a test suite exists to catch. testing::StrictMock host{beast::Journal{sink}}; - WasmTest() + MockVmTest() { // `runEscrowWasm` asks every run whether the host is clean, so under a strict mock // every test would have to say so. Declared once here, and any number of times @@ -71,7 +57,7 @@ struct WasmTest : testing::Test std::int64_t gas = kAmpleGas, std::string_view entryPoint = escrowFunctionName) { - return runEscrowWasm(assemble(wat), host, gas, entryPoint); + return runWat(host, wat, gas, entryPoint); } std::expected @@ -93,7 +79,7 @@ struct WasmTest : testing::Test // Base for the per-host-function fixtures. Each derives, supplies the module that exercises // its own import, and runs it through `callHost()` — so a test says only what the host was // asked and what came back. -struct HostCallTest : WasmTest +struct HostCallTest : MockVmTest { // The module under test. One import, one `escrow_finish` that calls it. [[nodiscard]] virtual std::string diff --git a/src/tests/libxrpl/tx/wasm/RealHostFixture.cpp b/src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.cpp similarity index 82% rename from src/tests/libxrpl/tx/wasm/RealHostFixture.cpp rename to src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.cpp index 4e97566845..887bf4fbab 100644 --- a/src/tests/libxrpl/tx/wasm/RealHostFixture.cpp +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -24,36 +24,42 @@ #include #include -#include #include #include #include -#include #include #include #include #include +#include +#include #include #include #include namespace xrpl::test { +void +fixtureFailed(std::string_view what) +{ + throw std::runtime_error("test fixture setup failed: " + std::string{what}); +} + Bytes -RealHostFixture::toBytes(std::uint8_t value) +WasmLedger::toBytes(std::uint8_t value) { return {value}; } Bytes -RealHostFixture::toBytes(std::uint16_t value) +WasmLedger::toBytes(std::uint16_t value) { return {static_cast(value), static_cast(value >> 8)}; } Bytes -RealHostFixture::toBytes(std::uint32_t value) +WasmLedger::toBytes(std::uint32_t value) { return { static_cast(value), @@ -63,31 +69,31 @@ RealHostFixture::toBytes(std::uint32_t value) } Bytes -RealHostFixture::toBytes(uint256 const& value) +WasmLedger::toBytes(uint256 const& value) { return Bytes{std::begin(value), std::end(value)}; } Bytes -RealHostFixture::toBytes(std::string_view value) +WasmLedger::toBytes(std::string_view value) { return Bytes{std::begin(value), std::end(value)}; } Bytes -RealHostFixture::toBytes(std::span value) +WasmLedger::toBytes(std::span value) { return Bytes{std::begin(value), std::end(value)}; } Bytes -RealHostFixture::toBytes(AccountID const& account) +WasmLedger::toBytes(AccountID const& account) { return Bytes{std::begin(account), std::end(account)}; } Bytes -RealHostFixture::toBytes(Issue const& issue) +WasmLedger::toBytes(Issue const& issue) { auto s = Serializer{}; s.addBitString(issue.currency); @@ -97,7 +103,7 @@ RealHostFixture::toBytes(Issue const& issue) } Bytes -RealHostFixture::toBytes(Asset const& asset) +WasmLedger::toBytes(Asset const& asset) { if (asset.holds()) return toBytes(asset.get()); @@ -108,7 +114,7 @@ RealHostFixture::toBytes(Asset const& asset) } Bytes -RealHostFixture::toBytes(STAmount const& amount) +WasmLedger::toBytes(STAmount const& amount) { auto msg = Serializer{}; amount.add(msg); @@ -116,19 +122,13 @@ RealHostFixture::toBytes(STAmount const& amount) } Bytes -RealHostFixture::toBytes(STNumber const& number) +WasmLedger::toBytes(STNumber const& number) { auto msg = Serializer{}; number.add(msg); return msg.getData(); } -void -expectKeyletMatches(std::expected const& result, Keylet const& expected) -{ - expectValue(result, RealHostFixture::toBytes(expected.key)); -} - SignedMessage signMessage(std::string_view message, KeyType keyType) { @@ -145,7 +145,10 @@ uint256 credentialId(std::string_view hex) { auto id = uint256{}; - EXPECT_TRUE(id.parseHex(std::string{hex})); + if (!id.parseHex(std::string{hex})) + { + fixtureFailed("parsing the credential id hex"); + } return id; } @@ -168,8 +171,11 @@ escrowFinishTx(TxTest& ledger, Account const& acct) { return {.type = ttESCROW_FINISH, .build = [&ledger, acct](STObject& obj) { auto credId = uint256{}; - EXPECT_TRUE(credId.parseHex( - "0011223344556677889900112233445566778899001122334455667788990011")); + if (!credId.parseHex( + "0011223344556677889900112233445566778899001122334455667788990011")) + { + fixtureFailed("parsing the credential id hex"); + } obj.setAccountID(sfAccount, acct.id()); obj.setAccountID(sfOwner, acct.id()); @@ -221,7 +227,7 @@ WasmHost::operator*() const } Account -RealHostFixture::fund(char const* name, XRPAmount amount) +WasmLedger::fund(char const* name, XRPAmount amount) { auto const account = Account{name}; ledger.createAccount(account, amount); @@ -229,7 +235,7 @@ RealHostFixture::fund(char const* name, XRPAmount amount) } WasmHost -RealHostFixture::makeHost( +WasmLedger::makeHost( beast::Journal journal, Keylet const& leKey, TxType txType, @@ -250,17 +256,14 @@ RealHostFixture::makeHost( } WasmHost -RealHostFixture::makeHost( - Keylet const& leKey, - TxType txType, - std::function assembler) +WasmLedger::makeHost(Keylet const& leKey, TxType txType, std::function assembler) { return makeHost( beast::Journal{beast::Journal::getNullSink()}, leKey, txType, std::move(assembler)); } WasmHost -RealHostFixture::makeTracingHost( +WasmLedger::makeTracingHost( Keylet const& leKey, TxType txType, std::function assembler) @@ -269,13 +272,13 @@ RealHostFixture::makeTracingHost( } std::string -RealHostFixture::logged() const +WasmLedger::logged() const { return traceSink_.messages(); } void -RealHostFixture::makeSignerList( +WasmLedger::makeSignerList( Account const& owner, std::uint32_t quorum, std::vector> const& signers) @@ -290,7 +293,10 @@ RealHostFixture::makeSignerList( } auto const r = ledger.submit( transactions::SignerListSetBuilder{owner.id(), quorum}.setSignerEntries(entries), owner); - EXPECT_EQ(r.ter, tesSUCCESS) << transToken(r.ter); + if (r.ter != tesSUCCESS) + { + fixtureFailed(std::string{"submitting the signer list: "} + transToken(r.ter)); + } ledger.close(); } diff --git a/src/tests/libxrpl/tx/wasm/RealHostFixture.h b/src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.h similarity index 79% rename from src/tests/libxrpl/tx/wasm/RealHostFixture.h rename to src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.h index 9e149c1f3b..abe6aa8e26 100644 --- a/src/tests/libxrpl/tx/wasm/RealHostFixture.h +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmLedger.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -19,51 +18,36 @@ #include #include -#include #include #include #include #include -#include #include #include -#include #include #include #include #include #include +// A real genesis ledger and the real host built over it, with **no test framework**. +// +// This is the piece both `xrpl_tests` and `xrpl.bench.wasm` need, and the reason it is its own +// type: a benchmark wants a ledger and a host, not GTest's lifecycle. `RealHostFixture` adds the +// framework on top (`: testing::Test, WasmLedger`) plus the assertion helpers; a benchmark uses +// `WasmLedger` directly and links no GTest at all. +// +// Setup steps here **throw** rather than `EXPECT_`. That is the point of the separation, not a +// detail: an `EXPECT_` outside a running test is recorded and discarded, so a benchmark whose +// escrow was never created would still run its host call, take the not-found path, and report a +// cheap, plausible, completely wrong price. Throwing turns that into a stopped run. + namespace xrpl::test { -template -void -expectValue( - std::expected const& result, - U const& expected, - std::source_location loc = std::source_location::current()) -{ - auto trace = testing::ScopedTrace{loc.file_name(), static_cast(loc.line()), ""}; - ASSERT_TRUE(result.has_value()) - << "expected a value, got error " << static_cast(result.error()); - EXPECT_EQ(*result, expected); -} - -template -void -expectError( - std::expected const& result, - HostFunctionError expected, - std::source_location loc = std::source_location::current()) -{ - auto trace = testing::ScopedTrace{loc.file_name(), static_cast(loc.line()), ""}; - ASSERT_FALSE(result.has_value()) << "expected error, got a value"; - EXPECT_EQ(result.error(), expected); -} - -void -expectKeyletMatches(std::expected const& result, Keylet const& expected); +// Fail a setup step loudly. See the note above on why this is not an `EXPECT_`. +[[noreturn]] void +fixtureFailed(std::string_view what); struct SignedMessage { @@ -116,7 +100,7 @@ private: std::unique_ptr host_; }; -class RealHostFixture : public testing::Test +class WasmLedger { public: TxTest ledger; diff --git a/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.cpp b/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.cpp new file mode 100644 index 0000000000..278bd8fabe --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.cpp @@ -0,0 +1,52 @@ +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace xrpl::test { + +Bytes +assembleWat(std::string_view wat) +{ + auto const wasm = rs::wasm_testkit::compile_wat(rust::Str{wat.data(), wat.size()}); + return Bytes{wasm.begin(), wasm.end()}; +} + +std::string +watEscaped(std::span bytes) +{ + static constexpr char kHex[] = "0123456789abcdef"; + auto out = std::string{}; + out.reserve(bytes.size() * 3); + for (auto const byte : bytes) + { + out += '\\'; + out += kHex[byte >> 4]; + out += kHex[byte & 0x0F]; + } + return out; +} + +std::string +watEscaped(Bytes const& bytes) +{ + return watEscaped(std::span{bytes.data(), bytes.size()}); +} + +std::expected +runWat(HostFunctions& host, std::string_view wat, std::int64_t gas, std::string_view entryPoint) +{ + return runEscrowWasm(assembleWat(wat), host, gas, entryPoint); +} + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.h b/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.h new file mode 100644 index 0000000000..a67d784bb6 --- /dev/null +++ b/src/tests/libxrpl/tx/wasm/fixtures/WasmRun.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace xrpl::test { + +// Enough gas for a small module to run to completion; a test about budgets passes its own. +inline constexpr std::int64_t kAmpleGas = 100'000; + +// Assemble WebAssembly text to bytes via the test-only `wasm_testkit` crate. The engine +// itself refuses text (a text assembler on the consensus path would make a transaction's +// validity a build flag), so this is where a WAT string becomes something runnable. Throws +// `rust::Error` on a typo, which gtest reports against the test that holds it. +Bytes +assembleWat(std::string_view wat); + +// `bytes` as the escape sequence a WAT string literal wants (`\aa\bb...`), for seeding a +// contract's memory through a `(data ...)` segment. +// +// Guest memory starts zeroed, and zeros are not a usable input to most host functions: an +// all-zero account id is `InvalidAccount`, an all-zero float is non-canonical. A contract +// that needs real bytes to work on gets them here, once at instantiation, rather than +// building them out of `i32.store` instructions. +std::string +watEscaped(std::span bytes); + +std::string +watEscaped(Bytes const& bytes); + +// Assemble and run `wat`'s `entryPoint` through the real VM, servicing host calls through +// `host` — a mock (`MockVmTest`) or the real impl over a ledger (`RealVmTest`). The one +// host-agnostic harness both fixtures inject their host into. +std::expected +runWat( + HostFunctions& host, + std::string_view wat, + std::int64_t gas = kAmpleGas, + std::string_view entryPoint = escrowFunctionName); + +} // namespace xrpl::test diff --git a/src/tests/libxrpl/tx/wasm/host_calls/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_calls/CurrentLedgerObjField.cpp index 143c20fa96..e6030d7886 100644 --- a/src/tests/libxrpl/tx/wasm/host_calls/CurrentLedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_calls/CurrentLedgerObjField.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_calls/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/host_calls/LedgerSqn.cpp index d4cec43616..32f383f5c6 100644 --- a/src/tests/libxrpl/tx/wasm/host_calls/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/host_calls/LedgerSqn.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_calls/Sha512Half.cpp b/src/tests/libxrpl/tx/wasm/host_calls/Sha512Half.cpp index 3653a6e931..9aef5d5966 100644 --- a/src/tests/libxrpl/tx/wasm/host_calls/Sha512Half.cpp +++ b/src/tests/libxrpl/tx/wasm/host_calls/Sha512Half.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_calls/Trace.cpp b/src/tests/libxrpl/tx/wasm/host_calls/Trace.cpp index e7dd854d22..fd7b871749 100644 --- a/src/tests/libxrpl/tx/wasm/host_calls/Trace.cpp +++ b/src/tests/libxrpl/tx/wasm/host_calls/Trace.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include // For `TraceDataType`: declared in the cxx bridge, defined in the header it generates. #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/AccountKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/AccountKeylet.cpp index e64ef2c073..f53d625216 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/AccountKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/AccountKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/AmmKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/AmmKeylet.cpp index e734bdc464..5ef7108fda 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/AmmKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/AmmKeylet.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/BaseFee.cpp b/src/tests/libxrpl/tx/wasm/host_context/BaseFee.cpp index 373a47f483..ee8557ce3a 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/BaseFee.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/BaseFee.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/host_context/CacheLedgerObj.cpp index 8c3d015362..a9376fa890 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CacheLedgerObj.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CacheLedgerObj.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CheckKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/CheckKeylet.cpp index 60191ec484..f2af938101 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CheckKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CheckKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CheckSignature.cpp b/src/tests/libxrpl/tx/wasm/host_context/CheckSignature.cpp index 796c56665c..751e4f17aa 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CheckSignature.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CheckSignature.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CredentialKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/CredentialKeylet.cpp index 09d4c7b2fc..462babad6c 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CredentialKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CredentialKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjArrayLen.cpp index 5ef9dbe7c3..8c3aab2d8b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjArrayLen.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjField.cpp index ad00450c35..43f139bfc4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjField.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedArrayLen.cpp index 6a3f9f2263..5b68a4c510 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedArrayLen.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedField.cpp index f9b03f0623..7279438209 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/CurrentLedgerObjNestedField.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/DelegateKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/DelegateKeylet.cpp index ecbbf2abab..d1ef893d00 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/DelegateKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/DelegateKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/DepositPreauthKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/DepositPreauthKeylet.cpp index a6f2cc151c..81e524baf2 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/DepositPreauthKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/DepositPreauthKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/DidKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/DidKeylet.cpp index 872c6e9120..220cce677f 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/DidKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/DidKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/EscrowKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/EscrowKeylet.cpp index fbb4d2dbce..8983cfae8b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/EscrowKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/EscrowKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatAdd.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatAdd.cpp index a6dadf0219..5408e80738 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatAdd.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatAdd.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatCompare.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatCompare.cpp index dbd2fbcb65..381dc58e6f 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatCompare.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatCompare.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatDivide.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatDivide.cpp index 552d172e34..b224e353e8 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatDivide.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatDivide.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromInt.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromInt.cpp index 78e78d7aa1..51736589a8 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromInt.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromInt.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromMantExp.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromMantExp.cpp index 0f3b5d8acd..f825f43f49 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromMantExp.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTAmount.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTAmount.cpp index 9a9c22e390..ce2b9f070e 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTAmount.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTAmount.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTNumber.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTNumber.cpp index c18e849026..58497bd914 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTNumber.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromSTNumber.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatFromUint.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatFromUint.cpp index 35370dfb9b..2c8c101863 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatFromUint.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatFromUint.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatMultiply.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatMultiply.cpp index 939ecb6885..74f20430e4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatMultiply.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatMultiply.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatPower.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatPower.cpp index 6b2c8087f4..3ec0c3b8be 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatPower.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatPower.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatSubtract.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatSubtract.cpp index 7f2a08ee1b..1821acc392 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatSubtract.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatSubtract.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatToInt.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatToInt.cpp index 05626d5c60..7f9f3f0ae2 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatToInt.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatToInt.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/host_context/FloatToMantExp.cpp index 709c6198c0..fb6a82cdc4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/FloatToMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/FloatToMantExp.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/IsAmendmentEnabled.cpp b/src/tests/libxrpl/tx/wasm/host_context/IsAmendmentEnabled.cpp index b0cbb6362c..f8fe9c7010 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/IsAmendmentEnabled.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/IsAmendmentEnabled.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjArrayLen.cpp index 80df1bd313..e7c9c62b0e 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjArrayLen.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjField.cpp index 8ee616b75a..bd33245258 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjField.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedArrayLen.cpp index 8f2d0d59a0..f4048f93fc 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedArrayLen.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedField.cpp index f0336cf39c..a4df4ec6da 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerObjNestedField.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/host_context/LedgerSqn.cpp index 442248b47a..4471a0e2b0 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/LedgerSqn.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/MptokenIssuanceKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/MptokenIssuanceKeylet.cpp index 5a53b05eb5..b8c4c7701b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/MptokenIssuanceKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/MptokenIssuanceKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/MptokenKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/MptokenKeylet.cpp index 7f4fd2b8f3..c26f0cd5cf 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/MptokenKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/MptokenKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFT.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFT.cpp index ba34fff6b0..67ee63ab7b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFT.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFT.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTFlags.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTFlags.cpp index 3c18d53f1f..7c785de074 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTFlags.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTFlags.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTIssuer.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTIssuer.cpp index 7d0401bccb..cf0c222cf2 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTIssuer.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTIssuer.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTSequence.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTSequence.cpp index 01bdf0e19a..d3fcc9be87 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTSequence.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTSequence.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTTaxon.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTTaxon.cpp index 4ddff82c78..1e2909845e 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTTaxon.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTTaxon.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NFTTransferFee.cpp b/src/tests/libxrpl/tx/wasm/host_context/NFTTransferFee.cpp index d67c5fc5db..2ccd30f517 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NFTTransferFee.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NFTTransferFee.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/NftokenOfferKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/NftokenOfferKeylet.cpp index c009321ad2..81e547039e 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/NftokenOfferKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/NftokenOfferKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/OfferKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/OfferKeylet.cpp index de1f36809d..7068ee846d 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/OfferKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/OfferKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/OracleKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/OracleKeylet.cpp index 0355d05b8c..85c58d2c1d 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/OracleKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/OracleKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerHash.cpp b/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerHash.cpp index 2c9d3f219b..9d11271ae6 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerHash.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerHash.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerTime.cpp b/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerTime.cpp index 71a02e995c..c31d20a690 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerTime.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/ParentLedgerTime.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/PaychannelKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/PaychannelKeylet.cpp index a184882a1a..096a3996b9 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/PaychannelKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/PaychannelKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/PermissionedDomainKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/PermissionedDomainKeylet.cpp index 5b490954b5..b2484379d3 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/PermissionedDomainKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/PermissionedDomainKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/Sha512Half.cpp b/src/tests/libxrpl/tx/wasm/host_context/Sha512Half.cpp index 6745be70d3..a7bd781335 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/Sha512Half.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/Sha512Half.cpp @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/SignerListKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/SignerListKeylet.cpp index 29c179863c..fd48a2d18b 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/SignerListKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/SignerListKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TicketKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/TicketKeylet.cpp index 03dadd4079..c18963993d 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TicketKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TicketKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/Trace.cpp b/src/tests/libxrpl/tx/wasm/host_context/Trace.cpp index 857b068cdd..2ac0ebacf3 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/Trace.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/Trace.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TrustLineKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/TrustLineKeylet.cpp index c4e4bccb01..18a4d8d34a 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TrustLineKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TrustLineKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TxArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/TxArrayLen.cpp index 120a8069d7..887842ef7a 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TxArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TxArrayLen.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TxField.cpp b/src/tests/libxrpl/tx/wasm/host_context/TxField.cpp index 24b73bb63c..84a3d694a4 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TxField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TxField.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TxNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_context/TxNestedArrayLen.cpp index 0269f6fbbe..5d550cc623 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TxNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TxNestedArrayLen.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_context/TxNestedField.cpp index 0cc1cb5a77..43351b6884 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/TxNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/TxNestedField.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/UpdateData.cpp b/src/tests/libxrpl/tx/wasm/host_context/UpdateData.cpp index 7d724205d5..11ee5760ed 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/UpdateData.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/UpdateData.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_context/VaultKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_context/VaultKeylet.cpp index a480b21ba2..febf81f0e0 100644 --- a/src/tests/libxrpl/tx/wasm/host_context/VaultKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_context/VaultKeylet.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.cpp index c36eea1d13..a846f8807e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AccountKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.cpp index 9414ecd6dc..cf393f7b89 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/AmmKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.cpp b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.cpp index b1f40233ca..0bba608633 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/BaseFee.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.cpp index 2625238e2e..649bd6e5ba 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CacheLedgerObj.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.cpp index 0abcbdc3db..7e2571fac5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.cpp index c1bfd722e4..7bfd7be73a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CheckSignature.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.cpp index 0eaeeb5d6a..d3521ad256 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CredentialKeylet.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.cpp index 6ef7b686c3..72c3491e85 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjArrayLen.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.cpp index 08816ee4fa..c3c249396f 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjField.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp index b94d6f1329..40ce10c841 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedArrayLen.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.cpp index c59ab5ed47..c1a9cab3da 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/CurrentLedgerObjNestedField.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.cpp index 8b936652d3..afe148ed53 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DelegateKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.cpp index 8846c8d1f0..a7a3fec8c4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DepositPreauthKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.cpp index 933b3583e0..5ba5a9585c 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/DidKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.cpp index ce6bfa73a0..e8bbaa1145 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/EscrowKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.cpp index 6864794411..c594950cad 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatAdd.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.cpp index e66a3beebe..21acd3f915 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatCompare.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.cpp index 518ab79a82..8e48cfcafe 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatDivide.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.cpp index 9b5cc70b1f..cc972cbde3 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromInt.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.cpp index 518db9e411..705c6b3fa1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromMantExp.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.cpp index 66136d78c4..36666ba2d3 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStAmount.cpp @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.cpp index 17b350fb9c..40c9f30fa5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromStNumber.cpp @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.cpp index bac8d19b6e..c407831448 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatFromUint.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.cpp index d49693dc31..cb91211dd4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatMultiply.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.cpp index dcb99ca9b3..44e01add62 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatPower.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.cpp index fc0d5eaa53..4e2a1d9d95 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatSubtract.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.cpp index 119ab42b00..c8fbe6c54b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToInt.cpp @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.cpp b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.cpp index 877db427d5..5c8a89e5d0 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/FloatToMantExp.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.cpp b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.cpp index e51b65e1e6..e6d152a06b 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/GetNFT.cpp @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.cpp b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.cpp index f31954c54c..8c9c34a0df 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/IsAmendmentEnabled.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.cpp index c9969d9f86..b63dfa2657 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjArrayLen.cpp @@ -5,7 +5,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.cpp index 91efc2738b..8deed246f5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjField.cpp @@ -5,7 +5,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.cpp index bd340883e6..d7e2fa8939 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedArrayLen.cpp @@ -5,7 +5,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.cpp index 95c4da4e69..c8e5d844e7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerObjNestedField.cpp @@ -7,7 +7,8 @@ #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.cpp b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.cpp index cf21a259f1..a88c81a586 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/LedgerSqn.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.cpp index 91637c6e3e..d2960a0747 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenIssuanceKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.cpp index 1e9a67fe90..eb3544c2a5 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/MptokenKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.cpp index d06ad23a17..c69871dc0d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTFlags.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.cpp index 12fcf76c48..ef65a4fa4a 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTIssuer.cpp @@ -3,8 +3,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.cpp index af8f2227a4..28cba45a68 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTSequence.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.cpp index da2942e6cd..3b7641d9e1 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTaxon.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.cpp index c9181b872c..e69eee0192 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NFTTransferFee.cpp @@ -1,8 +1,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.cpp index 97d8b3f699..18e669e949 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/NftokenOfferKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.cpp index cf4eac49e6..82737c9a11 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OfferKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.cpp index 0d6df50f13..69b0792fe4 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/OracleKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.cpp index 4f0142731a..d5b39bde46 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerHash.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.cpp b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.cpp index f76e47fda1..3abdef7916 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/ParentLedgerTime.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.cpp index 77b51254dd..8695f51605 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PaychannelKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.cpp index 1c9a2ae3ce..fd659f24a7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/PermissionedDomainedKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.cpp index b02c720503..7cf56f4550 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Sha512Half.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.cpp index b35afd493b..4d640a7a25 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/SignerListKeylet.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.cpp index e7669bc354..93be84aff7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TicketKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/Trace.cpp b/src/tests/libxrpl/tx/wasm/host_functions/Trace.cpp index 8bb94acd13..0db8539c1d 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/Trace.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/Trace.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.cpp index 26017ade9e..c8c428eadf 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TrustLineKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.cpp index 12aa3b6760..97e5d1d8b9 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxArrayLen.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxField.cpp index 6d83977c09..c0dd8efdc7 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxField.cpp @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.cpp index c2d8354805..f697ceeed3 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedArrayLen.cpp @@ -6,7 +6,8 @@ #include #include -#include +#include +#include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.cpp b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.cpp index 4a229478db..d801d46f44 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/TxNestedField.cpp @@ -7,7 +7,8 @@ #include #include -#include +#include +#include #include #include diff --git a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.cpp b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.cpp index 46bbee69d8..295956d6fb 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/UpdateData.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include namespace xrpl::test { diff --git a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.cpp b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.cpp index dfc968fa04..1026ed448e 100644 --- a/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.cpp +++ b/src/tests/libxrpl/tx/wasm/host_functions/VaultKeylet.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace xrpl::test {