From 38c7a27010da7465c1436a5fde98df970ddaac03 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 5 Aug 2025 18:06:34 -0400 Subject: [PATCH] clean up WASM functions a bit (#5628) --- src/test/app/Wasm_test.cpp | 59 ++++++++----- src/xrpld/app/misc/WasmVM.cpp | 129 +++++++++++++++-------------- src/xrpld/app/misc/WasmVM.h | 6 +- src/xrpld/app/tx/detail/Escrow.cpp | 8 +- 4 files changed, 114 insertions(+), 88 deletions(-) diff --git a/src/test/app/Wasm_test.cpp b/src/test/app/Wasm_test.cpp index 98e06a8636..c8db385c67 100644 --- a/src/test/app/Wasm_test.cpp +++ b/src/test/app/Wasm_test.cpp @@ -141,14 +141,19 @@ struct Wasm_test : public beast::unit_test::suite Env env{*this}; TestLedgerDataProvider hf(&env); - std::string const funcName("finish"); std::vector imports; WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", &hf, 33); auto& engine = WasmEngine::instance(); auto re = engine.run( - wasm, funcName, {}, imports, &hf, 1'000'000, env.journal); + wasm, + ESCROW_FUNCTION_NAME, + {}, + imports, + &hf, + 1'000'000, + env.journal); // code takes 11 gas + 1 getLedgerSqn call if (BEAST_EXPECT(re.has_value())) @@ -160,7 +165,8 @@ struct Wasm_test : public beast::unit_test::suite env.close(); // empty module - run the same instance - re = engine.run({}, funcName, {}, imports, &hf, 1'000'000, env.journal); + re = engine.run( + {}, ESCROW_FUNCTION_NAME, {}, imports, &hf, 1'000'000, env.journal); // code takes 22 gas + 2 getLedgerSqn calls if (BEAST_EXPECT(re.has_value())) @@ -327,10 +333,9 @@ struct Wasm_test : public beast::unit_test::suite "6d756c746976616c7565"; auto wasmStr = boost::algorithm::unhex(std::string(badWasmHex)); std::vector wasm(wasmStr.begin(), wasmStr.end()); - std::string funcName("finish"); - auto const re = - preflightEscrowWasm(wasm, funcName, {}, &hfs, env.journal); + auto const re = preflightEscrowWasm( + wasm, ESCROW_FUNCTION_NAME, {}, &hfs, env.journal); BEAST_EXPECT(!isTesSuccess(re)); } } @@ -348,8 +353,8 @@ struct Wasm_test : public beast::unit_test::suite Env env{*this}; { TestHostFunctions nfs(env, 0); - std::string funcName("finish"); - auto re = runEscrowWasm(wasm, funcName, {}, &nfs, 100'000); + auto re = + runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000); if (BEAST_EXPECT(re.has_value())) { BEAST_EXPECT(re->result && (re->cost == 41'132)); @@ -369,8 +374,8 @@ struct Wasm_test : public beast::unit_test::suite } }; BadTestHostFunctions nfs(env); - std::string funcName("finish"); - auto re = runEscrowWasm(wasm, funcName, {}, &nfs, 100000); + auto re = + runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100000); BEAST_EXPECT(re.has_value() && !re->result && (re->cost == 5831)); // std::cout << "bad case (access nonexistent field) result " // << re.error() << std::endl; @@ -389,8 +394,8 @@ struct Wasm_test : public beast::unit_test::suite } }; BadTestHostFunctions nfs(env); - std::string funcName("finish"); - auto re = runEscrowWasm(wasm, funcName, {}, &nfs, 100'000); + auto re = + runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000); BEAST_EXPECT(re.has_value() && !re->result && (re->cost == 5831)); // std::cout << "bad case (more than MAX_PAGES) result " // << re.error() << std::endl; @@ -431,7 +436,6 @@ struct Wasm_test : public beast::unit_test::suite { auto wasmStr = boost::algorithm::unhex(ledgerSqnHex); Bytes wasm(wasmStr.begin(), wasmStr.end()); - std::string const funcName("finish"); TestLedgerDataProvider ledgerDataProvider(&env); std::vector imports; @@ -441,7 +445,13 @@ struct Wasm_test : public beast::unit_test::suite auto& engine = WasmEngine::instance(); auto re = engine.run( - wasm, funcName, {}, imports, nullptr, 1'000'000, env.journal); + wasm, + ESCROW_FUNCTION_NAME, + {}, + imports, + nullptr, + 1'000'000, + env.journal); // expected import not provided BEAST_EXPECT(!re); @@ -453,8 +463,6 @@ struct Wasm_test : public beast::unit_test::suite { testcase("wasm test host functions cost"); - std::string const funcName("finish"); - using namespace test::jtx; Env env(*this); @@ -471,7 +479,13 @@ struct Wasm_test : public beast::unit_test::suite i.gas = 0; auto re = engine.run( - wasm, funcName, {}, imp, &hfs, 1'000'000, env.journal); + wasm, + ESCROW_FUNCTION_NAME, + {}, + imp, + &hfs, + 1'000'000, + env.journal); if (BEAST_EXPECT(re.has_value())) { @@ -498,7 +512,13 @@ struct Wasm_test : public beast::unit_test::suite std::vector const imp = createWasmImport(&hfs); auto re = engine.run( - wasm, funcName, {}, imp, &hfs, 1'000'000, env.journal); + wasm, + ESCROW_FUNCTION_NAME, + {}, + imp, + &hfs, + 1'000'000, + env.journal); if (BEAST_EXPECT(re.has_value())) { @@ -542,7 +562,6 @@ struct Wasm_test : public beast::unit_test::suite using namespace jtx; using namespace std::chrono; - std::string const funcName("finish"); // std::string const funcName("test"); auto const& wasmHex = hfPerfTest; // auto const& wasmHex = opcCallPerfTest; @@ -614,7 +633,7 @@ struct Wasm_test : public beast::unit_test::suite PerfHostFunctions nfs(env, k, env.tx()); - auto re = runEscrowWasm(wasm, funcName, {}, &nfs); + auto re = runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs); if (BEAST_EXPECT(re.has_value())) { BEAST_EXPECT(re->result); diff --git a/src/xrpld/app/misc/WasmVM.cpp b/src/xrpld/app/misc/WasmVM.cpp index 49990dfb99..d815c9939d 100644 --- a/src/xrpld/app/misc/WasmVM.cpp +++ b/src/xrpld/app/misc/WasmVM.cpp @@ -34,6 +34,71 @@ namespace ripple { +static void +setCommonHostFunctions(HostFunctions* hfs, std::vector& i) +{ + // clang-format off + WASM_IMPORT_FUNC2(i, getLedgerSqn, "get_ledger_sqn", hfs, 60); + WASM_IMPORT_FUNC2(i, getParentLedgerTime, "get_parent_ledger_time", hfs, 60); + WASM_IMPORT_FUNC2(i, getParentLedgerHash, "get_parent_ledger_hash", hfs, 60); + WASM_IMPORT_FUNC2(i, getLedgerAccountHash, "get_ledger_account_hash", hfs, 60); + WASM_IMPORT_FUNC2(i, getLedgerTransactionHash, "get_ledger_tx_hash", hfs, 60); + WASM_IMPORT_FUNC2(i, getBaseFee, "get_base_fee", hfs, 60); + WASM_IMPORT_FUNC2(i, isAmendmentEnabled, "amendment_enabled", hfs, 60); + WASM_IMPORT_FUNC2(i, cacheLedgerObj, "cache_ledger_obj", hfs, 5000); + WASM_IMPORT_FUNC2(i, getTxField, "get_tx_field", hfs, 70); + WASM_IMPORT_FUNC2(i, getCurrentLedgerObjField, "get_current_ledger_obj_field", hfs, 70); + WASM_IMPORT_FUNC2(i, getLedgerObjField, "get_ledger_obj_field", hfs, 70); + WASM_IMPORT_FUNC2(i, getTxNestedField, "get_tx_nested_field", hfs, 110); + WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedField, "get_current_ledger_obj_nested_field", hfs, 110); + WASM_IMPORT_FUNC2(i, getLedgerObjNestedField, "get_ledger_obj_nested_field", hfs, 110); + WASM_IMPORT_FUNC2(i, getTxArrayLen, "get_tx_array_len", hfs, 40); + WASM_IMPORT_FUNC2(i, getCurrentLedgerObjArrayLen, "get_current_ledger_obj_array_len", hfs, 40); + WASM_IMPORT_FUNC2(i, getLedgerObjArrayLen, "get_ledger_obj_array_len", hfs, 40); + WASM_IMPORT_FUNC2(i, getTxNestedArrayLen, "get_tx_nested_array_len", hfs, 70); + WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedArrayLen, "get_current_ledger_obj_nested_array_len", hfs, 70); + WASM_IMPORT_FUNC2(i, getLedgerObjNestedArrayLen, "get_ledger_obj_nested_array_len", hfs, 70); + WASM_IMPORT_FUNC2(i, updateData, "update_data", hfs, 1000); + WASM_IMPORT_FUNC2(i, checkSignature, "check_sig", hfs, 2000); + WASM_IMPORT_FUNC2(i, computeSha512HalfHash, "compute_sha512_half", hfs, 2000); + WASM_IMPORT_FUNC2(i, accountKeylet, "account_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, checkKeylet, "check_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, credentialKeylet, "credential_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, delegateKeylet, "delegate_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, depositPreauthKeylet, "deposit_preauth_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, didKeylet, "did_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, escrowKeylet, "escrow_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, lineKeylet, "line_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, nftOfferKeylet, "nft_offer_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, offerKeylet, "offer_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, oracleKeylet, "oracle_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, paychanKeylet, "paychan_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, signersKeylet, "signers_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, ticketKeylet, "ticket_keylet", hfs, 350); + WASM_IMPORT_FUNC2(i, getNFT, "get_nft", hfs, 1000); + WASM_IMPORT_FUNC2(i, getNFTIssuer, "get_nft_issuer", hfs, 60); + WASM_IMPORT_FUNC2(i, getNFTTaxon, "get_nft_taxon", hfs, 60); + WASM_IMPORT_FUNC2(i, getNFTFlags, "get_nft_flags", hfs, 60); + WASM_IMPORT_FUNC2(i, getNFTTransferFee, "get_nft_transfer_fee", hfs, 60); + WASM_IMPORT_FUNC2(i, getNFTSerial, "get_nft_serial", hfs, 60); + WASM_IMPORT_FUNC (i, trace, hfs, 500); + WASM_IMPORT_FUNC2(i, traceNum, "trace_num", hfs, 500); + WASM_IMPORT_FUNC2(i, traceFloat, "trace_opaque_float", hfs, 500); + + WASM_IMPORT_FUNC2(i, floatFromInt, "float_from_int", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatFromUint, "float_from_uint", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatSet, "float_set", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatCompare, "float_compare", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatSubtract, "float_subtract", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatMultiply, "float_multiply", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatDivide, "float_divide", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatRoot, "float_root", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatPower, "float_pow", hfs, 1000); + WASM_IMPORT_FUNC2(i, floatLog, "float_log", hfs, 1000); + // clang-format on +} + std::vector createWasmImport(HostFunctions* hfs) { @@ -41,68 +106,8 @@ createWasmImport(HostFunctions* hfs) if (hfs) { - // clang-format off - - WASM_IMPORT_FUNC2(i, getLedgerSqn, "get_ledger_sqn", hfs, 60); - WASM_IMPORT_FUNC2(i, getParentLedgerTime, "get_parent_ledger_time", hfs, 60); - WASM_IMPORT_FUNC2(i, getParentLedgerHash, "get_parent_ledger_hash", hfs, 60); - WASM_IMPORT_FUNC2(i, getLedgerAccountHash, "get_ledger_account_hash", hfs, 60); - WASM_IMPORT_FUNC2(i, getLedgerTransactionHash, "get_ledger_tx_hash", hfs, 60); - WASM_IMPORT_FUNC2(i, getBaseFee, "get_base_fee", hfs, 60); - WASM_IMPORT_FUNC2(i, isAmendmentEnabled, "amendment_enabled", hfs, 60); - WASM_IMPORT_FUNC2(i, cacheLedgerObj, "cache_ledger_obj", hfs, 5000); - WASM_IMPORT_FUNC2(i, getTxField, "get_tx_field", hfs, 70); - WASM_IMPORT_FUNC2(i, getCurrentLedgerObjField, "get_current_ledger_obj_field", hfs, 70); - WASM_IMPORT_FUNC2(i, getLedgerObjField, "get_ledger_obj_field", hfs, 70); - WASM_IMPORT_FUNC2(i, getTxNestedField, "get_tx_nested_field", hfs, 110); - WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedField, "get_current_ledger_obj_nested_field", hfs, 110); - WASM_IMPORT_FUNC2(i, getLedgerObjNestedField, "get_ledger_obj_nested_field", hfs, 110); - WASM_IMPORT_FUNC2(i, getTxArrayLen, "get_tx_array_len", hfs, 40); - WASM_IMPORT_FUNC2(i, getCurrentLedgerObjArrayLen, "get_current_ledger_obj_array_len", hfs, 40); - WASM_IMPORT_FUNC2(i, getLedgerObjArrayLen, "get_ledger_obj_array_len", hfs, 40); - WASM_IMPORT_FUNC2(i, getTxNestedArrayLen, "get_tx_nested_array_len", hfs, 70); - WASM_IMPORT_FUNC2(i, getCurrentLedgerObjNestedArrayLen, "get_current_ledger_obj_nested_array_len", hfs, 70); - WASM_IMPORT_FUNC2(i, getLedgerObjNestedArrayLen, "get_ledger_obj_nested_array_len", hfs, 70); - WASM_IMPORT_FUNC2(i, updateData, "update_data", hfs, 1000); - WASM_IMPORT_FUNC2(i, checkSignature, "check_sig", hfs, 2000); - WASM_IMPORT_FUNC2(i, computeSha512HalfHash, "compute_sha512_half", hfs, 2000); - WASM_IMPORT_FUNC2(i, accountKeylet, "account_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, checkKeylet, "check_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, credentialKeylet, "credential_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, delegateKeylet, "delegate_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, depositPreauthKeylet, "deposit_preauth_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, didKeylet, "did_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, escrowKeylet, "escrow_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, lineKeylet, "line_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, nftOfferKeylet, "nft_offer_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, offerKeylet, "offer_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, oracleKeylet, "oracle_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, paychanKeylet, "paychan_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, signersKeylet, "signers_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, ticketKeylet, "ticket_keylet", hfs, 350); - WASM_IMPORT_FUNC2(i, getNFT, "get_nft", hfs, 1000); - WASM_IMPORT_FUNC2(i, getNFTIssuer, "get_nft_issuer", hfs, 60); - WASM_IMPORT_FUNC2(i, getNFTTaxon, "get_nft_taxon", hfs, 60); - WASM_IMPORT_FUNC2(i, getNFTFlags, "get_nft_flags", hfs, 60); - WASM_IMPORT_FUNC2(i, getNFTTransferFee, "get_nft_transfer_fee", hfs, 60); - WASM_IMPORT_FUNC2(i, getNFTSerial, "get_nft_serial", hfs, 60); - WASM_IMPORT_FUNC (i, trace, hfs, 500); - WASM_IMPORT_FUNC2(i, traceNum, "trace_num", hfs, 500); - WASM_IMPORT_FUNC2(i, traceFloat, "trace_opaque_float", hfs, 500); - - WASM_IMPORT_FUNC2(i, floatFromInt, "float_from_int", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatFromUint, "float_from_uint", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatSet, "float_set", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatCompare, "float_compare", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatAdd, "float_add", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatSubtract, "float_subtract", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatMultiply, "float_multiply", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatDivide, "float_divide", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatRoot, "float_root", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatPower, "float_pow", hfs, 1000); - WASM_IMPORT_FUNC2(i, floatLog, "float_log", hfs, 1000); - - // clang-format on + setCommonHostFunctions(hfs, i); + WASM_IMPORT_FUNC2(i, updateData, "update_data", hfs, 1000); } return i; diff --git a/src/xrpld/app/misc/WasmVM.h b/src/xrpld/app/misc/WasmVM.h index c4db2fedd5..d4a9072740 100644 --- a/src/xrpld/app/misc/WasmVM.h +++ b/src/xrpld/app/misc/WasmVM.h @@ -34,6 +34,8 @@ static std::string_view const W_ALLOC = "allocate"; static std::string_view const W_DEALLOC = "deallocate"; static std::string_view const W_PROC_EXIT = "proc_exit"; +static std::string_view const ESCROW_FUNCTION_NAME = "finish"; + uint32_t const MAX_PAGES = 128; // 8MB = 64KB*128 class WamrEngine; @@ -92,7 +94,7 @@ createWasmImport(HostFunctions* hfs); Expected runEscrowWasm( Bytes const& wasmCode, - std::string_view funcName, + std::string_view funcName = ESCROW_FUNCTION_NAME, std::vector const& params = {}, HostFunctions* hfs = nullptr, int64_t gasLimit = -1, @@ -101,7 +103,7 @@ runEscrowWasm( NotTEC preflightEscrowWasm( Bytes const& wasmCode, - std::string_view funcName, + std::string_view funcName = ESCROW_FUNCTION_NAME, std::vector const& params = {}, HostFunctions* hfs = nullptr, beast::Journal j = beast::Journal(beast::Journal::getNullSink())); diff --git a/src/xrpld/app/tx/detail/Escrow.cpp b/src/xrpld/app/tx/detail/Escrow.cpp index c993d8ba59..f0389c06ad 100644 --- a/src/xrpld/app/tx/detail/Escrow.cpp +++ b/src/xrpld/app/tx/detail/Escrow.cpp @@ -232,7 +232,8 @@ EscrowCreate::preflight(PreflightContext const& ctx) } HostFunctions mock; - auto const re = preflightEscrowWasm(code, "finish", {}, &mock, ctx.j); + auto const re = + preflightEscrowWasm(code, ESCROW_FUNCTION_NAME, {}, &mock, ctx.j); if (!isTesSuccess(re)) { JLOG(ctx.j.debug()) << "EscrowCreate.FinishFunction bad WASM"; @@ -1266,7 +1267,6 @@ EscrowFinish::doApply() // WASM execution auto const wasmStr = slep->getFieldVL(sfFinishFunction); std::vector wasm(wasmStr.begin(), wasmStr.end()); - std::string funcName("finish"); WasmHostFunctionsImpl ledgerDataProvider(ctx_, k); @@ -1276,8 +1276,8 @@ EscrowFinish::doApply() return tecINTERNAL; } std::uint32_t allowance = ctx_.tx[sfComputationAllowance]; - auto re = - runEscrowWasm(wasm, funcName, {}, &ledgerDataProvider, allowance); + auto re = runEscrowWasm( + wasm, ESCROW_FUNCTION_NAME, {}, &ledgerDataProvider, allowance); JLOG(j_.trace()) << "Escrow WASM ran"; if (re.has_value()) {